Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

637 lines
19 KiB

/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
net\ip\rtrmgr\worker.c
Abstract:
IP Router Manager worker thread code
Revision History:
Gurdeep Singh Pall 6/8/95 Created
--*/
#include "allinc.h"
extern SOCKET McMiscSocket;
//
// From iphlpapi.h
//
DWORD
NotifyRouteChangeEx(
PHANDLE pHandle,
LPOVERLAPPED pOverLapped,
BOOL bExQueue
);
DWORD
WINAPI
EnableRouter(
HANDLE* pHandle,
OVERLAPPED* pOverlapped
);
DWORD
WINAPI
UnenableRouter(
OVERLAPPED* pOverlapped,
LPDWORD lpdwEnableCount OPTIONAL
);
DWORD
WorkerThread (
PVOID pGlobalInfo
)
{
DWORD eventindex ; // index of event notified
HANDLE workereventarray [NUMBER_OF_EVENTS] ; // event array
PPROTO_CB protptr ;
DWORD dwTimeOut, dwResult, dwByteCount, dwEnableCount;
OVERLAPPED RouteChangeOverlapped, SetForwardingOverlapped;
HANDLE hTemp;
TraceEnter("WorkerThread");
//
// Prepare list of events that WaitForMultipleObjects will wait on
//
workereventarray[EVENT_DEMANDDIAL] = g_hDemandDialEvent;
workereventarray[EVENT_IPINIP] = g_hIpInIpEvent;
workereventarray[EVENT_STOP_ROUTER] = g_hStopRouterEvent;
workereventarray[EVENT_SET_FORWARDING] = g_hSetForwardingEvent;
workereventarray[EVENT_FORWARDING_CHANGE] = g_hForwardingChangeEvent;
workereventarray[EVENT_STACK_CHANGE] = g_hStackChangeEvent;
workereventarray[EVENT_ROUTINGPROTOCOL] = g_hRoutingProtocolEvent ;
workereventarray[EVENT_RTRDISCTIMER] = g_hRtrDiscTimer;
workereventarray[EVENT_RTRDISCSOCKET] = g_hRtrDiscSocketEvent;
workereventarray[EVENT_MCMISCSOCKET] = g_hMcMiscSocketEvent;
workereventarray[EVENT_MZAPTIMER] = g_hMzapTimer;
workereventarray[EVENT_MZAPSOCKET] = g_hMzapSocketEvent;
workereventarray[EVENT_RASADVTIMER] = g_hRasAdvTimer;
workereventarray[EVENT_MHBEAT] = g_hMHbeatSocketEvent;
workereventarray[EVENT_MCAST_0] = g_hMcastEvents[0];
workereventarray[EVENT_MCAST_1] = g_hMcastEvents[1];
workereventarray[EVENT_MCAST_2] = g_hMcastEvents[2];
workereventarray[EVENT_ROUTE_CHANGE_0] = g_hRouteChangeEvents[0];
workereventarray[EVENT_ROUTE_CHANGE_1] = g_hRouteChangeEvents[1];
workereventarray[EVENT_ROUTE_CHANGE_2] = g_hRouteChangeEvents[2];
dwTimeOut = INFINITE;
//
// Do a setsockopt to listen for address changes.
// This must be done in the thread that will wait for the notifications
//
dwResult = WSAIoctl(McMiscSocket,
SIO_ADDRESS_LIST_CHANGE,
NULL,
0,
NULL,
0,
&dwByteCount,
NULL,
NULL);
if(dwResult is SOCKET_ERROR)
{
dwResult = WSAGetLastError();
if((dwResult isnot WSAEWOULDBLOCK) and
(dwResult isnot WSA_IO_PENDING) and
(dwResult isnot NO_ERROR))
{
Trace1(ERR,
"WorkerThread: Error %d from SIO_ADDRESS_LIST_CHANGE",
dwResult);
}
}
ZeroMemory(&SetForwardingOverlapped,
sizeof(SetForwardingOverlapped));
#if 1
for (
eventindex = 0;
eventindex < NUM_ROUTE_CHANGE_IRPS;
eventindex++
)
{
PostIoctlForRouteChangeNotification(eventindex);
}
#else
ZeroMemory(&RouteChangeOverlapped,
sizeof(RouteChangeOverlapped));
RouteChangeOverlapped.hEvent = g_hStackChangeEvent;
hTemp = NULL;
dwResult = NotifyRouteChangeEx(&hTemp,
&RouteChangeOverlapped,
TRUE);
if((dwResult isnot NO_ERROR) and
(dwResult isnot ERROR_IO_PENDING))
{
Trace1(ERR,
"WorkerThread: Error %d from NotifyRouteChange",
dwResult);
}
#endif
__try
{
while(TRUE)
{
eventindex = WaitForMultipleObjectsEx(NUMBER_OF_EVENTS,
workereventarray,
FALSE,
dwTimeOut,
TRUE);
switch(eventindex)
{
case WAIT_IO_COMPLETION:
{
continue ; // handle alertable wait case
}
case EVENT_DEMANDDIAL:
{
Trace0(DEMAND,
"WorkerThread: Demand Dial event received");
HandleDemandDialEvent();
break ;
}
case EVENT_IPINIP:
{
Trace0(DEMAND,
"WorkerThread: IpInIp event received");
HandleIpInIpEvent();
break ;
}
case EVENT_STOP_ROUTER:
case WAIT_TIMEOUT:
{
Trace0(GLOBAL,
"WorkerThread: Stop router event received");
// *** Exclusion Begin ***
ENTER_READER(ICB_LIST);
// *** Exclusion Begin ***
ENTER_WRITER(PROTOCOL_CB_LIST);
//
// If all interfaces havent been deleted we switch to
// polling mode where we get up every
// INTERFACE_DELETE_POLL_TIME and check
//
if(!IsListEmpty(&ICBList))
{
//
// Now wakeup every two second to check
//
dwTimeOut = INTERFACE_DELETE_POLL_TIME;
EXIT_LOCK(PROTOCOL_CB_LIST);
EXIT_LOCK(ICB_LIST);
break ;
}
else
{
//
// Get out of polling mode
//
dwTimeOut = INFINITE;
}
//
// Since all interfaces are now gone, we can delete the
// internal interface
//
if(g_pInternalInterfaceCb)
{
DeleteInternalInterface();
}
NotifyRoutingProtocolsToStop() ; // tells routing protocols to stop.
//
// Well interfaces have been deleted, so what about
// protocols?
//
WaitForAPIsToExitBeforeStopping() ; // returns when it is safe to stop router
if (AllRoutingProtocolsStopped())
{
//
// This check is done here since all routing protocols
// may have stopped synchronously, in which case
// we can safely stop
//
EXIT_LOCK(PROTOCOL_CB_LIST);
EXIT_LOCK(ICB_LIST);
__leave;
}
//
// All interfaces have been deleted but some protocol is
// still running. We will get a EVENT_ROUTINGPROTOCOL
// notification
//
EXIT_LOCK(PROTOCOL_CB_LIST);
EXIT_LOCK(ICB_LIST);
// make sure mrinfo/mtrace service is stopped
StopMcMisc();
if ( g_bEnableNetbtBcastFrowarding )
{
RestoreNetbtBcastForwardingMode();
g_bEnableNetbtBcastFrowarding = FALSE;
}
break ;
}
case EVENT_SET_FORWARDING:
{
hTemp = NULL;
EnterCriticalSection(&g_csFwdState);
//
// If our current state matches the user's request
// just free the message and move on
//
if(g_bEnableFwdRequest is g_bFwdEnabled)
{
LeaveCriticalSection(&g_csFwdState);
break;
}
SetForwardingOverlapped.hEvent = g_hForwardingChangeEvent;
if(g_bEnableFwdRequest)
{
Trace0(GLOBAL,
"WorkerThread: **--Enabling forwarding--**\n\n");
dwResult = EnableRouter(&hTemp,
&SetForwardingOverlapped);
g_bFwdEnabled = TRUE;
}
else
{
Trace0(GLOBAL,
"WorkerThread: **--Disabling forwarding--**\n\n");
dwResult = UnenableRouter(&SetForwardingOverlapped,
&dwEnableCount);
g_bFwdEnabled = FALSE;
}
if((dwResult isnot NO_ERROR) and
(dwResult isnot ERROR_IO_PENDING))
{
Trace1(ERR,
"WorkerThread: Error %d from call",
dwResult);
}
LeaveCriticalSection(&g_csFwdState);
break;
}
case EVENT_FORWARDING_CHANGE:
{
Trace0(GLOBAL,
"WorkerThread: **--Forwarding change event--**\n\n");
break;
}
case EVENT_STACK_CHANGE:
{
Trace0(GLOBAL,
"WorkerThread: Stack Change event received");
UpdateDefaultRoutes();
dwResult = NotifyRouteChangeEx(&hTemp,
&RouteChangeOverlapped,
TRUE);
if((dwResult isnot NO_ERROR) and
(dwResult isnot ERROR_IO_PENDING))
{
Trace1(ERR,
"WorkerThread: Error %d from NotifyRouteChangeEx",
dwResult);
//
// If there was an error, try again
//
NotifyRouteChangeEx(&hTemp,
&RouteChangeOverlapped,
TRUE);
}
break;
}
case EVENT_ROUTINGPROTOCOL:
{
Trace0(GLOBAL,
"WorkerThread: Routing protocol notification received");
HandleRoutingProtocolNotification() ;
if((RouterState.IRS_State is RTR_STATE_STOPPING) and
IsListEmpty(&ICBList) and
AllRoutingProtocolsStopped())
{
__leave;
}
break ;
}
case EVENT_RASADVTIMER:
{
EnterCriticalSection(&RouterStateLock);
if(RouterState.IRS_State isnot RTR_STATE_RUNNING)
{
Trace0(IF,
"WorkerThread: Router discovery timer fired while shutting down. Ignoring");
LeaveCriticalSection(&RouterStateLock);
break;
}
LeaveCriticalSection(&RouterStateLock);
Trace0(MCAST,
"WorkerThread: RasAdv Timer event received");
HandleRasAdvTimer();
break;
}
case EVENT_RTRDISCTIMER:
{
PLIST_ENTRY pleTimerNode;
PROUTER_DISC_CB pDiscCb;
EnterCriticalSection(&RouterStateLock);
if(RouterState.IRS_State isnot RTR_STATE_RUNNING)
{
Trace0(IF,
"WorkerThread: Router discovery timer fired while shutting down. Ignoring");
LeaveCriticalSection(&RouterStateLock);
break;
}
LeaveCriticalSection(&RouterStateLock);
ENTER_WRITER(ICB_LIST);
Trace0(RTRDISC,
"WorkerThread: Router Discovery Timer event received");
if(IsListEmpty(&g_leTimerQueueHead))
{
//
// Someone removed the timer item from under us
// and happened to empty the timer queue. Since we
// are a non-periodic timer, we will not
// fire again so no problem
//
Trace0(RTRDISC,
"WorkerThread: Router Discovery Timer went off but no timer items");
EXIT_LOCK(ICB_LIST);
break;
}
HandleRtrDiscTimer();
EXIT_LOCK(ICB_LIST);
break;
}
case EVENT_RTRDISCSOCKET:
{
EnterCriticalSection(&RouterStateLock);
if(RouterState.IRS_State isnot RTR_STATE_RUNNING)
{
Trace0(IF,
"WorkerThread: FD_READ while shutting down. Ignoring");
LeaveCriticalSection(&RouterStateLock);
break;
}
LeaveCriticalSection(&RouterStateLock);
ENTER_WRITER(ICB_LIST);
HandleSolicitations();
EXIT_LOCK(ICB_LIST);
break;
}
case EVENT_MCMISCSOCKET:
{
EnterCriticalSection(&RouterStateLock);
if(RouterState.IRS_State isnot RTR_STATE_RUNNING)
{
Trace0(IF,
"WorkerThread: FD_READ while shutting down. Ignoring");
LeaveCriticalSection(&RouterStateLock);
break;
}
LeaveCriticalSection(&RouterStateLock);
HandleMcMiscMessages();
break;
}
case EVENT_MZAPTIMER:
{
EnterCriticalSection(&RouterStateLock);
if(RouterState.IRS_State isnot RTR_STATE_RUNNING)
{
Trace0(IF,
"WorkerThread: Router discovery timer fired while shutting down. Ignoring");
LeaveCriticalSection(&RouterStateLock);
break;
}
LeaveCriticalSection(&RouterStateLock);
HandleMzapTimer();
break;
}
case EVENT_MZAPSOCKET:
{
EnterCriticalSection(&RouterStateLock);
if(RouterState.IRS_State isnot RTR_STATE_RUNNING)
{
Trace0(IF,
"WorkerThread: FD_READ while shutting down. Ignoring");
LeaveCriticalSection(&RouterStateLock);
break;
}
LeaveCriticalSection(&RouterStateLock);
HandleMZAPMessages();
break;
}
case EVENT_MCAST_0:
case EVENT_MCAST_1:
case EVENT_MCAST_2:
{
HandleMcastNotification(eventindex - EVENT_MCAST_0);
break;
}
case EVENT_ROUTE_CHANGE_0:
case EVENT_ROUTE_CHANGE_1:
case EVENT_ROUTE_CHANGE_2:
{
HandleRouteChangeNotification(
eventindex - EVENT_ROUTE_CHANGE_0
);
break;
}
default:
{
Trace1(ERR,
"WorkerThread: Wait failed with following error %d",
GetLastError());
break;
}
}
}
}
__finally
{
Trace0(GLOBAL,
"WorkerThread: Worker thread stopping");
RouterManagerCleanup();
RouterState.IRS_State = RTR_STATE_STOPPED;
(RouterStopped) (PID_IP, 0);
}
FreeLibraryAndExitThread(g_hOwnModule,
NO_ERROR);
return NO_ERROR;
}
VOID
WaitForAPIsToExitBeforeStopping(
VOID
)
{
DWORD sleepcount = 0 ;
TraceEnter("WaitForAPIsToExitBeforeStopping");
//
// Wait for refcount to trickle down to zero: this indicates that no
// threads are in the router now
//
while(RouterState.IRS_RefCount != 0)
{
if (sleepcount++ > 20)
{
Trace0(ERR,
"WaitForAPIsToExitBeforeStopping: RouterState.IRS_Refcount not decreasing");
}
Sleep (200L);
}
TraceLeave("WaitForAPIsToExitBeforeStopping");
}