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

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. net\ip\rtrmgr\worker.c
  5. Abstract:
  6. IP Router Manager worker thread code
  7. Revision History:
  8. Gurdeep Singh Pall 6/8/95 Created
  9. --*/
  10. #include "allinc.h"
  11. extern SOCKET McMiscSocket;
  12. //
  13. // From iphlpapi.h
  14. //
  15. DWORD
  16. NotifyRouteChangeEx(
  17. PHANDLE pHandle,
  18. LPOVERLAPPED pOverLapped,
  19. BOOL bExQueue
  20. );
  21. DWORD
  22. WINAPI
  23. EnableRouter(
  24. HANDLE* pHandle,
  25. OVERLAPPED* pOverlapped
  26. );
  27. DWORD
  28. WINAPI
  29. UnenableRouter(
  30. OVERLAPPED* pOverlapped,
  31. LPDWORD lpdwEnableCount OPTIONAL
  32. );
  33. DWORD
  34. WorkerThread (
  35. PVOID pGlobalInfo
  36. )
  37. {
  38. DWORD eventindex ; // index of event notified
  39. HANDLE workereventarray [NUMBER_OF_EVENTS] ; // event array
  40. PPROTO_CB protptr ;
  41. DWORD dwTimeOut, dwResult, dwByteCount, dwEnableCount;
  42. OVERLAPPED RouteChangeOverlapped, SetForwardingOverlapped;
  43. HANDLE hTemp;
  44. TraceEnter("WorkerThread");
  45. //
  46. // Prepare list of events that WaitForMultipleObjects will wait on
  47. //
  48. workereventarray[EVENT_DEMANDDIAL] = g_hDemandDialEvent;
  49. workereventarray[EVENT_IPINIP] = g_hIpInIpEvent;
  50. workereventarray[EVENT_STOP_ROUTER] = g_hStopRouterEvent;
  51. workereventarray[EVENT_SET_FORWARDING] = g_hSetForwardingEvent;
  52. workereventarray[EVENT_FORWARDING_CHANGE] = g_hForwardingChangeEvent;
  53. workereventarray[EVENT_STACK_CHANGE] = g_hStackChangeEvent;
  54. workereventarray[EVENT_ROUTINGPROTOCOL] = g_hRoutingProtocolEvent ;
  55. workereventarray[EVENT_RTRDISCTIMER] = g_hRtrDiscTimer;
  56. workereventarray[EVENT_RTRDISCSOCKET] = g_hRtrDiscSocketEvent;
  57. workereventarray[EVENT_MCMISCSOCKET] = g_hMcMiscSocketEvent;
  58. workereventarray[EVENT_MZAPTIMER] = g_hMzapTimer;
  59. workereventarray[EVENT_MZAPSOCKET] = g_hMzapSocketEvent;
  60. workereventarray[EVENT_RASADVTIMER] = g_hRasAdvTimer;
  61. workereventarray[EVENT_MHBEAT] = g_hMHbeatSocketEvent;
  62. workereventarray[EVENT_MCAST_0] = g_hMcastEvents[0];
  63. workereventarray[EVENT_MCAST_1] = g_hMcastEvents[1];
  64. workereventarray[EVENT_MCAST_2] = g_hMcastEvents[2];
  65. workereventarray[EVENT_ROUTE_CHANGE_0] = g_hRouteChangeEvents[0];
  66. workereventarray[EVENT_ROUTE_CHANGE_1] = g_hRouteChangeEvents[1];
  67. workereventarray[EVENT_ROUTE_CHANGE_2] = g_hRouteChangeEvents[2];
  68. dwTimeOut = INFINITE;
  69. //
  70. // Do a setsockopt to listen for address changes.
  71. // This must be done in the thread that will wait for the notifications
  72. //
  73. dwResult = WSAIoctl(McMiscSocket,
  74. SIO_ADDRESS_LIST_CHANGE,
  75. NULL,
  76. 0,
  77. NULL,
  78. 0,
  79. &dwByteCount,
  80. NULL,
  81. NULL);
  82. if(dwResult is SOCKET_ERROR)
  83. {
  84. dwResult = WSAGetLastError();
  85. if((dwResult isnot WSAEWOULDBLOCK) and
  86. (dwResult isnot WSA_IO_PENDING) and
  87. (dwResult isnot NO_ERROR))
  88. {
  89. Trace1(ERR,
  90. "WorkerThread: Error %d from SIO_ADDRESS_LIST_CHANGE",
  91. dwResult);
  92. }
  93. }
  94. ZeroMemory(&SetForwardingOverlapped,
  95. sizeof(SetForwardingOverlapped));
  96. #if 1
  97. for (
  98. eventindex = 0;
  99. eventindex < NUM_ROUTE_CHANGE_IRPS;
  100. eventindex++
  101. )
  102. {
  103. PostIoctlForRouteChangeNotification(eventindex);
  104. }
  105. #else
  106. ZeroMemory(&RouteChangeOverlapped,
  107. sizeof(RouteChangeOverlapped));
  108. RouteChangeOverlapped.hEvent = g_hStackChangeEvent;
  109. hTemp = NULL;
  110. dwResult = NotifyRouteChangeEx(&hTemp,
  111. &RouteChangeOverlapped,
  112. TRUE);
  113. if((dwResult isnot NO_ERROR) and
  114. (dwResult isnot ERROR_IO_PENDING))
  115. {
  116. Trace1(ERR,
  117. "WorkerThread: Error %d from NotifyRouteChange",
  118. dwResult);
  119. }
  120. #endif
  121. __try
  122. {
  123. while(TRUE)
  124. {
  125. eventindex = WaitForMultipleObjectsEx(NUMBER_OF_EVENTS,
  126. workereventarray,
  127. FALSE,
  128. dwTimeOut,
  129. TRUE);
  130. switch(eventindex)
  131. {
  132. case WAIT_IO_COMPLETION:
  133. {
  134. continue ; // handle alertable wait case
  135. }
  136. case EVENT_DEMANDDIAL:
  137. {
  138. Trace0(DEMAND,
  139. "WorkerThread: Demand Dial event received");
  140. HandleDemandDialEvent();
  141. break ;
  142. }
  143. case EVENT_IPINIP:
  144. {
  145. Trace0(DEMAND,
  146. "WorkerThread: IpInIp event received");
  147. HandleIpInIpEvent();
  148. break ;
  149. }
  150. case EVENT_STOP_ROUTER:
  151. case WAIT_TIMEOUT:
  152. {
  153. Trace0(GLOBAL,
  154. "WorkerThread: Stop router event received");
  155. // *** Exclusion Begin ***
  156. ENTER_READER(ICB_LIST);
  157. // *** Exclusion Begin ***
  158. ENTER_WRITER(PROTOCOL_CB_LIST);
  159. //
  160. // If all interfaces havent been deleted we switch to
  161. // polling mode where we get up every
  162. // INTERFACE_DELETE_POLL_TIME and check
  163. //
  164. if(!IsListEmpty(&ICBList))
  165. {
  166. //
  167. // Now wakeup every two second to check
  168. //
  169. dwTimeOut = INTERFACE_DELETE_POLL_TIME;
  170. EXIT_LOCK(PROTOCOL_CB_LIST);
  171. EXIT_LOCK(ICB_LIST);
  172. break ;
  173. }
  174. else
  175. {
  176. //
  177. // Get out of polling mode
  178. //
  179. dwTimeOut = INFINITE;
  180. }
  181. //
  182. // Since all interfaces are now gone, we can delete the
  183. // internal interface
  184. //
  185. if(g_pInternalInterfaceCb)
  186. {
  187. DeleteInternalInterface();
  188. }
  189. NotifyRoutingProtocolsToStop() ; // tells routing protocols to stop.
  190. //
  191. // Well interfaces have been deleted, so what about
  192. // protocols?
  193. //
  194. WaitForAPIsToExitBeforeStopping() ; // returns when it is safe to stop router
  195. if (AllRoutingProtocolsStopped())
  196. {
  197. //
  198. // This check is done here since all routing protocols
  199. // may have stopped synchronously, in which case
  200. // we can safely stop
  201. //
  202. EXIT_LOCK(PROTOCOL_CB_LIST);
  203. EXIT_LOCK(ICB_LIST);
  204. __leave;
  205. }
  206. //
  207. // All interfaces have been deleted but some protocol is
  208. // still running. We will get a EVENT_ROUTINGPROTOCOL
  209. // notification
  210. //
  211. EXIT_LOCK(PROTOCOL_CB_LIST);
  212. EXIT_LOCK(ICB_LIST);
  213. // make sure mrinfo/mtrace service is stopped
  214. StopMcMisc();
  215. if ( g_bEnableNetbtBcastFrowarding )
  216. {
  217. RestoreNetbtBcastForwardingMode();
  218. g_bEnableNetbtBcastFrowarding = FALSE;
  219. }
  220. break ;
  221. }
  222. case EVENT_SET_FORWARDING:
  223. {
  224. hTemp = NULL;
  225. EnterCriticalSection(&g_csFwdState);
  226. //
  227. // If our current state matches the user's request
  228. // just free the message and move on
  229. //
  230. if(g_bEnableFwdRequest is g_bFwdEnabled)
  231. {
  232. LeaveCriticalSection(&g_csFwdState);
  233. break;
  234. }
  235. SetForwardingOverlapped.hEvent = g_hForwardingChangeEvent;
  236. if(g_bEnableFwdRequest)
  237. {
  238. Trace0(GLOBAL,
  239. "WorkerThread: **--Enabling forwarding--**\n\n");
  240. dwResult = EnableRouter(&hTemp,
  241. &SetForwardingOverlapped);
  242. g_bFwdEnabled = TRUE;
  243. }
  244. else
  245. {
  246. Trace0(GLOBAL,
  247. "WorkerThread: **--Disabling forwarding--**\n\n");
  248. dwResult = UnenableRouter(&SetForwardingOverlapped,
  249. &dwEnableCount);
  250. g_bFwdEnabled = FALSE;
  251. }
  252. if((dwResult isnot NO_ERROR) and
  253. (dwResult isnot ERROR_IO_PENDING))
  254. {
  255. Trace1(ERR,
  256. "WorkerThread: Error %d from call",
  257. dwResult);
  258. }
  259. LeaveCriticalSection(&g_csFwdState);
  260. break;
  261. }
  262. case EVENT_FORWARDING_CHANGE:
  263. {
  264. Trace0(GLOBAL,
  265. "WorkerThread: **--Forwarding change event--**\n\n");
  266. break;
  267. }
  268. case EVENT_STACK_CHANGE:
  269. {
  270. Trace0(GLOBAL,
  271. "WorkerThread: Stack Change event received");
  272. UpdateDefaultRoutes();
  273. dwResult = NotifyRouteChangeEx(&hTemp,
  274. &RouteChangeOverlapped,
  275. TRUE);
  276. if((dwResult isnot NO_ERROR) and
  277. (dwResult isnot ERROR_IO_PENDING))
  278. {
  279. Trace1(ERR,
  280. "WorkerThread: Error %d from NotifyRouteChangeEx",
  281. dwResult);
  282. //
  283. // If there was an error, try again
  284. //
  285. NotifyRouteChangeEx(&hTemp,
  286. &RouteChangeOverlapped,
  287. TRUE);
  288. }
  289. break;
  290. }
  291. case EVENT_ROUTINGPROTOCOL:
  292. {
  293. Trace0(GLOBAL,
  294. "WorkerThread: Routing protocol notification received");
  295. HandleRoutingProtocolNotification() ;
  296. if((RouterState.IRS_State is RTR_STATE_STOPPING) and
  297. IsListEmpty(&ICBList) and
  298. AllRoutingProtocolsStopped())
  299. {
  300. __leave;
  301. }
  302. break ;
  303. }
  304. case EVENT_RASADVTIMER:
  305. {
  306. EnterCriticalSection(&RouterStateLock);
  307. if(RouterState.IRS_State isnot RTR_STATE_RUNNING)
  308. {
  309. Trace0(IF,
  310. "WorkerThread: Router discovery timer fired while shutting down. Ignoring");
  311. LeaveCriticalSection(&RouterStateLock);
  312. break;
  313. }
  314. LeaveCriticalSection(&RouterStateLock);
  315. Trace0(MCAST,
  316. "WorkerThread: RasAdv Timer event received");
  317. HandleRasAdvTimer();
  318. break;
  319. }
  320. case EVENT_RTRDISCTIMER:
  321. {
  322. PLIST_ENTRY pleTimerNode;
  323. PROUTER_DISC_CB pDiscCb;
  324. EnterCriticalSection(&RouterStateLock);
  325. if(RouterState.IRS_State isnot RTR_STATE_RUNNING)
  326. {
  327. Trace0(IF,
  328. "WorkerThread: Router discovery timer fired while shutting down. Ignoring");
  329. LeaveCriticalSection(&RouterStateLock);
  330. break;
  331. }
  332. LeaveCriticalSection(&RouterStateLock);
  333. ENTER_WRITER(ICB_LIST);
  334. Trace0(RTRDISC,
  335. "WorkerThread: Router Discovery Timer event received");
  336. if(IsListEmpty(&g_leTimerQueueHead))
  337. {
  338. //
  339. // Someone removed the timer item from under us
  340. // and happened to empty the timer queue. Since we
  341. // are a non-periodic timer, we will not
  342. // fire again so no problem
  343. //
  344. Trace0(RTRDISC,
  345. "WorkerThread: Router Discovery Timer went off but no timer items");
  346. EXIT_LOCK(ICB_LIST);
  347. break;
  348. }
  349. HandleRtrDiscTimer();
  350. EXIT_LOCK(ICB_LIST);
  351. break;
  352. }
  353. case EVENT_RTRDISCSOCKET:
  354. {
  355. EnterCriticalSection(&RouterStateLock);
  356. if(RouterState.IRS_State isnot RTR_STATE_RUNNING)
  357. {
  358. Trace0(IF,
  359. "WorkerThread: FD_READ while shutting down. Ignoring");
  360. LeaveCriticalSection(&RouterStateLock);
  361. break;
  362. }
  363. LeaveCriticalSection(&RouterStateLock);
  364. ENTER_WRITER(ICB_LIST);
  365. HandleSolicitations();
  366. EXIT_LOCK(ICB_LIST);
  367. break;
  368. }
  369. case EVENT_MCMISCSOCKET:
  370. {
  371. EnterCriticalSection(&RouterStateLock);
  372. if(RouterState.IRS_State isnot RTR_STATE_RUNNING)
  373. {
  374. Trace0(IF,
  375. "WorkerThread: FD_READ while shutting down. Ignoring");
  376. LeaveCriticalSection(&RouterStateLock);
  377. break;
  378. }
  379. LeaveCriticalSection(&RouterStateLock);
  380. HandleMcMiscMessages();
  381. break;
  382. }
  383. case EVENT_MZAPTIMER:
  384. {
  385. EnterCriticalSection(&RouterStateLock);
  386. if(RouterState.IRS_State isnot RTR_STATE_RUNNING)
  387. {
  388. Trace0(IF,
  389. "WorkerThread: Router discovery timer fired while shutting down. Ignoring");
  390. LeaveCriticalSection(&RouterStateLock);
  391. break;
  392. }
  393. LeaveCriticalSection(&RouterStateLock);
  394. HandleMzapTimer();
  395. break;
  396. }
  397. case EVENT_MZAPSOCKET:
  398. {
  399. EnterCriticalSection(&RouterStateLock);
  400. if(RouterState.IRS_State isnot RTR_STATE_RUNNING)
  401. {
  402. Trace0(IF,
  403. "WorkerThread: FD_READ while shutting down. Ignoring");
  404. LeaveCriticalSection(&RouterStateLock);
  405. break;
  406. }
  407. LeaveCriticalSection(&RouterStateLock);
  408. HandleMZAPMessages();
  409. break;
  410. }
  411. case EVENT_MCAST_0:
  412. case EVENT_MCAST_1:
  413. case EVENT_MCAST_2:
  414. {
  415. HandleMcastNotification(eventindex - EVENT_MCAST_0);
  416. break;
  417. }
  418. case EVENT_ROUTE_CHANGE_0:
  419. case EVENT_ROUTE_CHANGE_1:
  420. case EVENT_ROUTE_CHANGE_2:
  421. {
  422. HandleRouteChangeNotification(
  423. eventindex - EVENT_ROUTE_CHANGE_0
  424. );
  425. break;
  426. }
  427. default:
  428. {
  429. Trace1(ERR,
  430. "WorkerThread: Wait failed with following error %d",
  431. GetLastError());
  432. break;
  433. }
  434. }
  435. }
  436. }
  437. __finally
  438. {
  439. Trace0(GLOBAL,
  440. "WorkerThread: Worker thread stopping");
  441. RouterManagerCleanup();
  442. RouterState.IRS_State = RTR_STATE_STOPPED;
  443. (RouterStopped) (PID_IP, 0);
  444. }
  445. FreeLibraryAndExitThread(g_hOwnModule,
  446. NO_ERROR);
  447. return NO_ERROR;
  448. }
  449. VOID
  450. WaitForAPIsToExitBeforeStopping(
  451. VOID
  452. )
  453. {
  454. DWORD sleepcount = 0 ;
  455. TraceEnter("WaitForAPIsToExitBeforeStopping");
  456. //
  457. // Wait for refcount to trickle down to zero: this indicates that no
  458. // threads are in the router now
  459. //
  460. while(RouterState.IRS_RefCount != 0)
  461. {
  462. if (sleepcount++ > 20)
  463. {
  464. Trace0(ERR,
  465. "WaitForAPIsToExitBeforeStopping: RouterState.IRS_Refcount not decreasing");
  466. }
  467. Sleep (200L);
  468. }
  469. TraceLeave("WaitForAPIsToExitBeforeStopping");
  470. }