Leaked source code of windows server 2003
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.

873 lines
16 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. ripmain.c
  5. Abstract:
  6. Contains the rcv and worker threads
  7. Author:
  8. Stefan Solomon 07/06/1995
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. DWORD
  14. APIENTRY
  15. RegisterProtocol(
  16. IN OUT PMPR_ROUTING_CHARACTERISTICS pRoutingChar,
  17. IN OUT PMPR_SERVICE_CHARACTERISTICS pServiceChar
  18. );
  19. DWORD
  20. APIENTRY
  21. StartProtocol(
  22. IN HANDLE hMgrNotifyEvent,
  23. IN PSUPPORT_FUNCTIONS pSupportFunctions,
  24. IN PVOID pConfig
  25. );
  26. DWORD
  27. APIENTRY
  28. StopProtocol(
  29. VOID
  30. );
  31. DWORD
  32. APIENTRY
  33. GetGlobalInfo(
  34. IN OUT PVOID pConfig,
  35. IN OUT PDWORD pdwSize
  36. );
  37. DWORD
  38. APIENTRY
  39. SetGlobalInfo(
  40. IN PVOID pConfig
  41. );
  42. DWORD
  43. APIENTRY
  44. AddInterface(
  45. IN PWCHAR pwszInterfaceName,
  46. IN DWORD dwIndex,
  47. IN NET_INTERFACE_TYPE dwIfType,
  48. IN PVOID pConfig
  49. );
  50. DWORD
  51. APIENTRY
  52. DeleteInterface(
  53. IN DWORD dwIndex
  54. );
  55. DWORD
  56. APIENTRY
  57. GetEventMessage(
  58. OUT ROUTING_PROTOCOL_EVENTS *pEvent,
  59. OUT MESSAGE *pResult
  60. );
  61. DWORD
  62. APIENTRY
  63. GetInterfaceConfigInfo(
  64. IN DWORD dwIndex,
  65. IN OUT PVOID pConfig,
  66. IN OUT PDWORD pdwSize
  67. );
  68. DWORD
  69. APIENTRY
  70. SetInterfaceConfigInfo(
  71. IN DWORD dwIndex,
  72. IN PVOID pConfig
  73. );
  74. DWORD
  75. APIENTRY
  76. BindInterface(
  77. IN DWORD dwIndex,
  78. IN PVOID pBinding
  79. );
  80. DWORD
  81. APIENTRY
  82. UnbindInterface(
  83. IN DWORD dwIndex
  84. );
  85. DWORD
  86. APIENTRY
  87. EnableInterface(
  88. IN DWORD dwIndex
  89. );
  90. DWORD
  91. APIENTRY
  92. DisableInterface(
  93. IN DWORD dwIndex
  94. );
  95. DWORD
  96. APIENTRY
  97. DoUpdateRoutes(
  98. IN DWORD dwIndex
  99. );
  100. DWORD
  101. APIENTRY
  102. MibCreate(
  103. IN DWORD dwInputSize,
  104. IN PVOID pInputData
  105. );
  106. DWORD
  107. APIENTRY
  108. MibDelete(
  109. IN DWORD dwInputSize,
  110. IN PVOID pInputData
  111. );
  112. DWORD
  113. APIENTRY
  114. MibGet(
  115. IN DWORD dwInputSize,
  116. IN PVOID pInputData,
  117. IN OUT PDWORD pdwOutputSize,
  118. OUT PVOID pOutputData
  119. );
  120. DWORD
  121. APIENTRY
  122. MibSet(
  123. IN DWORD dwInputSize,
  124. IN PVOID pInputData
  125. );
  126. DWORD
  127. APIENTRY
  128. MibGetFirst(
  129. IN DWORD dwInputSize,
  130. IN PVOID pInputData,
  131. IN OUT PDWORD pdwOutputSize,
  132. OUT PVOID pOutputData
  133. );
  134. DWORD
  135. APIENTRY
  136. MibGetNext(
  137. IN DWORD dwInputSize,
  138. IN PVOID pInputData,
  139. IN OUT PDWORD pdwOutputSize,
  140. OUT PVOID pOutputData
  141. );
  142. // Router Manager Notification Event
  143. HANDLE RM_Event;
  144. TCHAR ModuleName[MAX_PATH+1];
  145. VOID
  146. WorkerThread(VOID);
  147. DWORD
  148. CreateWorkerThreadObjects(VOID);
  149. VOID
  150. DestroyWorkerThreadObjects(VOID);
  151. VOID
  152. ProcessDequeuedIoPacket(DWORD ErrorCode,
  153. DWORD BytesTransferred,
  154. LPOVERLAPPED Overlappedp);
  155. BOOL WINAPI
  156. IpxRipDllEntry(HINSTANCE hInstDll,
  157. DWORD fdwReason,
  158. LPVOID pReserved)
  159. {
  160. switch (fdwReason)
  161. {
  162. case DLL_PROCESS_ATTACH:
  163. GetModuleFileName (hInstDll, ModuleName,
  164. sizeof (ModuleName)/sizeof (ModuleName[0]));
  165. SS_DBGINITIALIZE;
  166. RipOperState = OPER_STATE_DOWN;
  167. // Create the database lock
  168. InitializeCriticalSection(&DbaseCritSec);
  169. // Create the queues lock
  170. InitializeCriticalSection(&QueuesCritSec);
  171. // Create the RIP changed list lock
  172. InitializeCriticalSection(&RipChangedListCritSec);
  173. break;
  174. case DLL_PROCESS_DETACH:
  175. // delete the RIP changed list lock
  176. DeleteCriticalSection(&RipChangedListCritSec);
  177. // delete the database lock
  178. DeleteCriticalSection(&DbaseCritSec);
  179. // delete the queues lock
  180. DeleteCriticalSection(&QueuesCritSec);
  181. break;
  182. default:
  183. break;
  184. }
  185. return TRUE;
  186. }
  187. DWORD WINAPI
  188. RegisterProtocol(
  189. IN OUT PMPR_ROUTING_CHARACTERISTICS pRoutingChar,
  190. IN OUT PMPR_SERVICE_CHARACTERISTICS pServiceChar
  191. )
  192. {
  193. if(pRoutingChar->dwProtocolId != IPX_PROTOCOL_RIP)
  194. {
  195. return ERROR_NOT_SUPPORTED;
  196. }
  197. pServiceChar->fSupportedFunctionality = 0;
  198. pRoutingChar->fSupportedFunctionality = (ROUTING | DEMAND_UPDATE_ROUTES);
  199. pRoutingChar->pfnStartProtocol = StartProtocol;
  200. pRoutingChar->pfnStopProtocol = StopProtocol;
  201. pRoutingChar->pfnAddInterface = AddInterface;
  202. pRoutingChar->pfnDeleteInterface = DeleteInterface;
  203. pRoutingChar->pfnGetEventMessage = GetEventMessage;
  204. pRoutingChar->pfnGetInterfaceInfo = GetInterfaceConfigInfo;
  205. pRoutingChar->pfnSetInterfaceInfo = SetInterfaceConfigInfo;
  206. pRoutingChar->pfnBindInterface = BindInterface;
  207. pRoutingChar->pfnUnbindInterface = UnbindInterface;
  208. pRoutingChar->pfnEnableInterface = EnableInterface;
  209. pRoutingChar->pfnDisableInterface = DisableInterface;
  210. pRoutingChar->pfnGetGlobalInfo = GetGlobalInfo;
  211. pRoutingChar->pfnSetGlobalInfo = SetGlobalInfo;
  212. pRoutingChar->pfnMibCreateEntry = MibCreate;
  213. pRoutingChar->pfnMibDeleteEntry = MibDelete;
  214. pRoutingChar->pfnMibGetEntry = MibGet;
  215. pRoutingChar->pfnMibSetEntry = MibSet;
  216. pRoutingChar->pfnMibGetFirstEntry = MibGetFirst;
  217. pRoutingChar->pfnMibGetNextEntry = MibGetNext;
  218. pRoutingChar->pfnUpdateRoutes = DoUpdateRoutes;
  219. return NO_ERROR;
  220. }
  221. DWORD WINAPI
  222. StartProtocol(IN HANDLE NotificationEvent,
  223. IN PSUPPORT_FUNCTIONS SupportFunctions,
  224. IN PVOID GlobalInfo)
  225. {
  226. #define ripGlobalInfo ((PRIP_GLOBAL_INFO)GlobalInfo)
  227. DWORD threadid, i;
  228. HANDLE ThreadHandle;
  229. RipEventLogMask = ripGlobalInfo->EventLogMask;
  230. StartTracing();
  231. Trace(INIT_TRACE, "StartProtocol: Entered\n");
  232. ACQUIRE_DATABASE_LOCK;
  233. ACQUIRE_QUEUES_LOCK;
  234. RipOperState = OPER_STATE_STARTING;
  235. GetIpxRipRegistryParameters();
  236. RM_Event = NotificationEvent;
  237. //init the interfaces database
  238. InitIfDbase();
  239. //
  240. // init all the queues
  241. //
  242. // InitializeListHead(&WorkersQueue);
  243. InitializeListHead(&TimerQueue);
  244. InitializeListHead(&RepostRcvPacketsQueue);
  245. InitializeListHead(&RipMessageQueue);
  246. // create the workers work items heap
  247. if(CreateWorkItemsManager() != NO_ERROR) {
  248. goto ErrorExit;
  249. }
  250. // open the RIP socket for I/O
  251. if(OpenRipSocket() != NO_ERROR) {
  252. Trace(INIT_TRACE, "Cannot open RIP socket\n");
  253. goto ErrorExit;
  254. }
  255. if(! BindIoCompletionCallback(RipSocketHandle,
  256. ProcessDequeuedIoPacket, 0)) {
  257. Trace(INIT_TRACE, "Cannot associate IO Completion Port\n");
  258. goto ErrorExit;
  259. }
  260. // create synchronization objects for the rip threads
  261. if(CreateWorkerThreadObjects() != NO_ERROR) {
  262. Trace(INIT_TRACE, "Cannot create synchronization objects\n");
  263. goto ErrorExit;
  264. }
  265. // Open RTM for RIP
  266. if(OpenRTM()) {
  267. Trace(INIT_TRACE, "Cannot open RTM\n");
  268. goto ErrorExit;
  269. }
  270. // create the Worker thread
  271. if ((ThreadHandle = CreateThread(
  272. (LPSECURITY_ATTRIBUTES) NULL,
  273. 0,
  274. (LPTHREAD_START_ROUTINE) WorkerThread,
  275. NULL,
  276. 0,
  277. &threadid)) == NULL) {
  278. // !!! log error cannot create the worker thread !!!
  279. goto ErrorExit;
  280. }
  281. else
  282. CloseHandle (ThreadHandle);
  283. RipOperState = OPER_STATE_UP;
  284. RELEASE_QUEUES_LOCK;
  285. RELEASE_DATABASE_LOCK;
  286. CreateStartChangesBcastWi();
  287. Trace(INIT_TRACE, "Started successfully\n");
  288. return NO_ERROR;
  289. ErrorExit:
  290. RELEASE_QUEUES_LOCK;
  291. RELEASE_DATABASE_LOCK;
  292. return ERROR_CAN_NOT_COMPLETE;
  293. #undef ripGlobalInfo
  294. }
  295. DWORD
  296. WINAPI
  297. StopProtocol(VOID)
  298. {
  299. PWORK_ITEM wip;
  300. Trace(INIT_TRACE, "StopProtocol: Entered\n");
  301. ACQUIRE_DATABASE_LOCK;
  302. if(RipOperState != OPER_STATE_UP) {
  303. SS_ASSERT(FALSE);
  304. goto ErrorExit;
  305. }
  306. RipOperState = OPER_STATE_STOPPING;
  307. // send interfaces shutdown work item to the workers
  308. if((wip = AllocateWorkItem(SHUTDOWN_INTERFACES_TYPE)) == NULL) {
  309. goto ErrorExit;
  310. }
  311. wip->WorkItemSpecific.WIS_ShutdownInterfaces.ShutdownState = SHUTDOWN_START;
  312. RtlQueueWorkItem(ProcessWorkItem, wip, 0);
  313. RELEASE_DATABASE_LOCK;
  314. return NO_ERROR;
  315. ErrorExit:
  316. RELEASE_DATABASE_LOCK;
  317. return ERROR_CAN_NOT_COMPLETE;
  318. }
  319. VOID
  320. WorkerThread(VOID)
  321. {
  322. DWORD rc;
  323. DWORD signaled_event, delay;
  324. ULONG dueTime = GetTickCount() + MAXULONG/2;
  325. PWORK_ITEM wip;
  326. PLIST_ENTRY lep;
  327. HANDLE hModuleReference;
  328. hModuleReference = LoadLibrary (ModuleName);
  329. StartReceiver();
  330. while(TRUE)
  331. {
  332. delay = dueTime - GetTickCount();
  333. if(delay < MAXULONG/2) {
  334. // dueTime is later then present time
  335. while((rc = WaitForMultipleObjects(
  336. MAX_WORKER_THREAD_OBJECTS,
  337. WorkerThreadObjects,
  338. FALSE, // wait any
  339. delay // timeout
  340. )) == WAIT_IO_COMPLETION);
  341. }
  342. else
  343. {
  344. // dueTime already happened
  345. rc = WAIT_TIMEOUT;
  346. }
  347. if(rc == WAIT_TIMEOUT) {
  348. dueTime = ProcessTimerQueue();
  349. }
  350. else
  351. {
  352. signaled_event = rc - WAIT_OBJECT_0;
  353. if(signaled_event < MAX_WORKER_THREAD_OBJECTS) {
  354. switch(signaled_event) {
  355. case TIMER_EVENT:
  356. dueTime = ProcessTimerQueue();
  357. break;
  358. case REPOST_RCV_PACKETS_EVENT:
  359. RepostRcvPackets();
  360. break;
  361. // case WORKERS_QUEUE_EVENT:
  362. // dequeue only one item from the work items queue
  363. // ACQUIRE_QUEUES_LOCK;
  364. // while(!IsListEmpty(&WorkersQueue)) {
  365. // lep = RemoveHeadList(&WorkersQueue);
  366. // wip = CONTAINING_RECORD(lep, WORK_ITEM, Linkage);
  367. // RELEASE_QUEUES_LOCK;
  368. // Queue the work item for processing by the
  369. // worker threads
  370. // RtlQueueWorkItem(ProcessWorkItem,
  371. // wip,
  372. // WT_EXECUTEINIOTHREAD); // never dieing workers so we can do send submits
  373. // and the thread won't die before send completes
  374. // ACQUIRE_QUEUES_LOCK;
  375. // }
  376. // RELEASE_QUEUES_LOCK;
  377. // break;
  378. case RTM_EVENT:
  379. ProcessRTMChanges();
  380. break;
  381. case RIP_CHANGES_EVENT:
  382. ProcessRIPChanges();
  383. break;
  384. case TERMINATE_WORKER_EVENT:
  385. // stop the StartChangesBcast work item
  386. DestroyStartChangesBcastWi = TRUE;
  387. // close the rip socket
  388. CloseRipSocket();
  389. FlushTimerQueue();
  390. CloseRTM();
  391. // wait until no more work items
  392. while(WorkItemsCount != 0) {
  393. Trace(INIT_TRACE, "Terminating: Waiting for work items to be freed: %d outstanding ...\n",
  394. WorkItemsCount);
  395. Sleep(1000);
  396. }
  397. // destroy worker thread objects
  398. DestroyWorkerThreadObjects();
  399. // destroy workers heap
  400. DestroyWorkItemsManager();
  401. // post stop complete message
  402. PostEventMessage(ROUTER_STOPPED, NULL);
  403. Trace(INIT_TRACE, "Terminating: Stop completed and STOP Event Message posted\n");
  404. FreeLibraryAndExitThread(hModuleReference, 0);
  405. break;
  406. default:
  407. break;
  408. }
  409. }
  410. }
  411. }
  412. }
  413. // table of handlers for work items which keep a reference to the if CB
  414. typedef VOID (* IF_WORK_ITEM_HANDLER)(PWORK_ITEM wip);
  415. IF_WORK_ITEM_HANDLER IfWorkItemHandler[] = {
  416. IfPeriodicBcast,
  417. IfCompleteGenResponse,
  418. IfChangeBcast,
  419. IfCheckUpdateStatus,
  420. IfPeriodicGenRequest
  421. };
  422. #define MAX_IF_WORK_ITEM_HANDLERS sizeof(IfWorkItemHandler)/sizeof(IF_WORK_ITEM_HANDLER)
  423. VOID
  424. ProcessWorkItem(PWORK_ITEM wip)
  425. {
  426. PLIST_ENTRY lep;
  427. PICB icbp;
  428. switch(wip->Type) {
  429. case RECEIVE_PACKET_TYPE:
  430. // this work item references the interface via the adapter index
  431. ACQUIRE_DATABASE_LOCK;
  432. if(RipOperState != OPER_STATE_UP) {
  433. RELEASE_DATABASE_LOCK;
  434. }
  435. else
  436. {
  437. if((icbp = GetInterfaceByAdapterIndex(wip->AdapterIndex)) != NULL) {
  438. wip->icbp = icbp;
  439. ACQUIRE_IF_LOCK(icbp);
  440. RELEASE_DATABASE_LOCK;
  441. ProcessReceivedPacket(wip);
  442. RELEASE_IF_LOCK(icbp);
  443. }
  444. else
  445. {
  446. RELEASE_DATABASE_LOCK;
  447. }
  448. }
  449. // queue the receive packet back to recv thread for reposting
  450. EnqueueRcvPacketToRepostQueue(wip);
  451. break;
  452. case START_CHANGES_BCAST_TYPE:
  453. ACQUIRE_DATABASE_LOCK;
  454. StartChangesBcast(wip);
  455. RELEASE_DATABASE_LOCK;
  456. break;
  457. case SHUTDOWN_INTERFACES_TYPE:
  458. ACQUIRE_DATABASE_LOCK;
  459. ShutdownInterfaces(wip);
  460. RELEASE_DATABASE_LOCK;
  461. break;
  462. case DEBUG_TYPE:
  463. FreeWorkItem(wip);
  464. break;
  465. default:
  466. // all these work items reference the interface via an if CB pointer
  467. icbp = wip->icbp;
  468. ACQUIRE_IF_LOCK(icbp);
  469. (*IfWorkItemHandler[wip->Type])(wip);
  470. if(icbp->Discarded) {
  471. RELEASE_IF_LOCK(icbp);
  472. ACQUIRE_DATABASE_LOCK;
  473. ACQUIRE_IF_LOCK(icbp);
  474. if(--icbp->RefCount == 0) {
  475. // remove the if CB from the discarded queue and free it
  476. RemoveEntryList(&icbp->IfListLinkage);
  477. // free the interface CB
  478. Trace(INIT_TRACE, "ProcessWorkItem: Free DISCARDED if CB for if # %d\n", icbp->InterfaceIndex);
  479. DestroyInterfaceCB(icbp);
  480. }
  481. else
  482. {
  483. RELEASE_IF_LOCK(icbp);
  484. }
  485. RELEASE_DATABASE_LOCK;
  486. }
  487. else
  488. {
  489. icbp->RefCount--;
  490. RELEASE_IF_LOCK(icbp);
  491. }
  492. }
  493. }
  494. DWORD
  495. WINAPI
  496. GetEventMessage(ROUTING_PROTOCOL_EVENTS *Event,
  497. PMESSAGE Result)
  498. {
  499. PRIP_MESSAGE emp;
  500. PLIST_ENTRY lep;
  501. Trace(INIT_TRACE, "GetEventMessage: Entered\n");
  502. ACQUIRE_DATABASE_LOCK;
  503. if((RipOperState == OPER_STATE_DOWN) ||
  504. (RipOperState == OPER_STATE_STARTING)) {
  505. RELEASE_DATABASE_LOCK;
  506. return ERROR_CAN_NOT_COMPLETE;
  507. }
  508. ACQUIRE_QUEUES_LOCK;
  509. if(IsListEmpty(&RipMessageQueue)) {
  510. RELEASE_QUEUES_LOCK;
  511. RELEASE_DATABASE_LOCK;
  512. return ERROR_NO_MORE_ITEMS;
  513. }
  514. lep = RemoveHeadList(&RipMessageQueue);
  515. emp = CONTAINING_RECORD(lep, RIP_MESSAGE, Linkage);
  516. *Event = emp->Event;
  517. if(Result != NULL) {
  518. *Result = emp->Result;
  519. }
  520. if(emp->Event == ROUTER_STOPPED) {
  521. RipOperState = OPER_STATE_DOWN;
  522. StopTracing();
  523. }
  524. GlobalFree(emp);
  525. RELEASE_QUEUES_LOCK;
  526. RELEASE_DATABASE_LOCK;
  527. return NO_ERROR;
  528. }
  529. VOID
  530. PostEventMessage(ROUTING_PROTOCOL_EVENTS Event,
  531. PMESSAGE Result)
  532. {
  533. PRIP_MESSAGE emp;
  534. if((emp = GlobalAlloc(GPTR, sizeof(RIP_MESSAGE))) == NULL) {
  535. return;
  536. }
  537. emp->Event = Event;
  538. if(Result != NULL) {
  539. emp->Result = *Result;
  540. }
  541. ACQUIRE_QUEUES_LOCK;
  542. InsertTailList(&RipMessageQueue, &emp->Linkage);
  543. RELEASE_QUEUES_LOCK;
  544. SetEvent(RM_Event);
  545. }
  546. DWORD
  547. CreateWorkerThreadObjects(VOID)
  548. {
  549. int i;
  550. for(i=0; i<MAX_WORKER_THREAD_OBJECTS; i++) {
  551. if((WorkerThreadObjects[i] = CreateEvent(NULL,
  552. FALSE,
  553. FALSE,
  554. NULL)) == NULL) {
  555. return ERROR_CAN_NOT_COMPLETE;
  556. }
  557. }
  558. return NO_ERROR;
  559. }
  560. VOID
  561. DestroyWorkerThreadObjects(VOID)
  562. {
  563. int i;
  564. for(i=0; i<MAX_WORKER_THREAD_OBJECTS; i++) {
  565. CloseHandle(WorkerThreadObjects[i]);
  566. }
  567. }
  568. DWORD WINAPI
  569. SetGlobalInfo(PVOID GlobalInfo)
  570. {
  571. #define ripGlobalInfo ((PRIP_GLOBAL_INFO)GlobalInfo)
  572. ACQUIRE_DATABASE_LOCK;
  573. if(RipOperState != OPER_STATE_UP) {
  574. RELEASE_DATABASE_LOCK;
  575. return ERROR_CAN_NOT_COMPLETE;
  576. }
  577. RipEventLogMask = ripGlobalInfo->EventLogMask;
  578. RELEASE_DATABASE_LOCK;
  579. return NO_ERROR;
  580. #undef ripGlobalInfo
  581. }
  582. DWORD WINAPI
  583. GetGlobalInfo(
  584. IN PVOID GlobalInfo,
  585. IN OUT PULONG GlobalInfoSize
  586. )
  587. {
  588. ACQUIRE_DATABASE_LOCK;
  589. if(RipOperState != OPER_STATE_UP) {
  590. RELEASE_DATABASE_LOCK;
  591. return ERROR_CAN_NOT_COMPLETE;
  592. }
  593. if ((*GlobalInfoSize>=sizeof (RIP_GLOBAL_INFO))
  594. && (GlobalInfo!=NULL)) {
  595. #define ripGlobalInfo ((PRIP_GLOBAL_INFO)GlobalInfo)
  596. ripGlobalInfo->EventLogMask = RipEventLogMask;
  597. #undef ripGlobalInfo
  598. }
  599. *GlobalInfoSize = sizeof (RIP_GLOBAL_INFO);
  600. RELEASE_DATABASE_LOCK;
  601. return NO_ERROR;
  602. }
  603. VOID
  604. ProcessDequeuedIoPacket(DWORD ErrorCode,
  605. DWORD BytesTransferred,
  606. LPOVERLAPPED Overlappedp)
  607. {
  608. PWORK_ITEM wip;
  609. wip = CONTAINING_RECORD(Overlappedp, WORK_ITEM, Overlapped);
  610. wip->IoCompletionStatus = (DWORD)Overlappedp->Internal;
  611. switch(wip->Type) {
  612. case RECEIVE_PACKET_TYPE:
  613. ReceiveComplete(wip);
  614. break;
  615. default:
  616. SendComplete(wip);
  617. break;
  618. }
  619. }