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.

2874 lines
66 KiB

  1. //============================================================================
  2. // Copyright (c) 1995, Microsoft Corporation
  3. //
  4. // File: api.c
  5. //
  6. // History:
  7. // Abolade Gbadegesin Aug-8-1995 Created.
  8. //
  9. // router manager API implementations
  10. //============================================================================
  11. #include "pchrip.h"
  12. #pragma hdrstop
  13. //
  14. // Definition of sole global variable for IPRIP
  15. //
  16. IPRIP_GLOBALS ig;
  17. //----------------------------------------------------------------------------
  18. // Function: DLLMAIN
  19. //
  20. // This is the DLL entrypoint handler. It calls DllStartup
  21. // to initialize locking and event queue and to create IPRIP's heap,
  22. // and calls DllCleanup to delete the lock and event queue.
  23. //----------------------------------------------------------------------------
  24. BOOL
  25. WINAPI
  26. DLLMAIN(
  27. HINSTANCE hInstance,
  28. DWORD dwReason,
  29. PVOID pUnused
  30. ) {
  31. BOOL bErr;
  32. bErr = FALSE;
  33. switch(dwReason) {
  34. case DLL_PROCESS_ATTACH:
  35. DisableThreadLibraryCalls(hInstance);
  36. bErr = DllStartup();
  37. break;
  38. case DLL_PROCESS_DETACH:
  39. bErr = DllCleanup();
  40. break;
  41. default:
  42. bErr = TRUE;
  43. break;
  44. }
  45. return bErr;
  46. }
  47. //----------------------------------------------------------------------------
  48. // Function: DllStartup
  49. //
  50. // Initializes IPRIP's function lock, event queue, and global heap.
  51. //----------------------------------------------------------------------------
  52. BOOL
  53. DllStartup(
  54. ) {
  55. BOOL bErr;
  56. DWORD dwErr;
  57. bErr = TRUE;
  58. do { // error breakout loop
  59. ZeroMemory(&ig, sizeof(IPRIP_GLOBALS));
  60. //
  61. // create the global critical section and set IPRIP's status
  62. //
  63. try {
  64. InitializeCriticalSection(&ig.IG_CS);
  65. }
  66. except (EXCEPTION_EXECUTE_HANDLER) {
  67. bErr = FALSE;
  68. break;
  69. }
  70. ig.IG_Status = IPRIP_STATUS_STOPPED;
  71. //
  72. // attempt to create a private heap for IPRIP
  73. //
  74. ig.IG_IpripGlobalHeap = HeapCreate(0, 0, 0);
  75. if (ig.IG_IpripGlobalHeap == NULL) {
  76. bErr = FALSE;
  77. break;
  78. }
  79. //
  80. // create the router manager message queue
  81. //
  82. ig.IG_EventQueue = RIP_ALLOC(sizeof(LOCKED_LIST));
  83. if (ig.IG_EventQueue == NULL) {
  84. bErr = FALSE;
  85. break;
  86. }
  87. //
  88. // initialize the Router Manager event queue
  89. //
  90. try {
  91. CREATE_LOCKED_LIST(ig.IG_EventQueue);
  92. }
  93. except (EXCEPTION_EXECUTE_HANDLER) {
  94. bErr = FALSE;
  95. break;
  96. }
  97. } while(FALSE);
  98. return bErr;
  99. }
  100. //----------------------------------------------------------------------------
  101. // Function: DllCleanup
  102. //
  103. // Deletes the global heap, event queue, and function lock.
  104. //----------------------------------------------------------------------------
  105. BOOL
  106. DllCleanup(
  107. ) {
  108. BOOL bErr;
  109. bErr = TRUE;
  110. do { // error breakout loop
  111. //
  112. // destroy the router manager event queue
  113. //
  114. if (ig.IG_EventQueue != NULL) {
  115. if (LOCKED_LIST_CREATED(ig.IG_EventQueue)) {
  116. DELETE_LOCKED_LIST(
  117. ig.IG_EventQueue, EVENT_QUEUE_ENTRY, EQE_Link
  118. );
  119. }
  120. RIP_FREE(ig.IG_EventQueue);
  121. }
  122. if (ig.IG_IpripGlobalHeap != NULL) {
  123. HeapDestroy(ig.IG_IpripGlobalHeap);
  124. }
  125. //
  126. // delete the global critical section
  127. //
  128. DeleteCriticalSection(&ig.IG_CS);
  129. RouterLogDeregister(ig.IG_LogHandle);
  130. if (ig.IG_TraceID != INVALID_TRACEID) {
  131. TraceDeregister(ig.IG_TraceID);
  132. }
  133. } while(FALSE);
  134. return bErr;
  135. }
  136. //----------------------------------------------------------------------------
  137. // Function: ProtocolStartup
  138. //
  139. // This is called by StartProtocol. Initializes data structures,
  140. // creates IPRIP threads.
  141. //----------------------------------------------------------------------------
  142. DWORD
  143. ProtocolStartup(
  144. HANDLE hEventEvent,
  145. PVOID pConfig
  146. ) {
  147. WSADATA wd;
  148. HANDLE hThread;
  149. BOOL bCleanupWinsock;
  150. DWORD dwErr, dwSize, dwThread;
  151. PIPRIP_GLOBAL_CONFIG pgcsrc, pgcdst;
  152. EnterCriticalSection(&ig.IG_CS);
  153. ig.IG_TraceID = TraceRegister("IPRIP2");
  154. ig.IG_LogHandle = RouterLogRegister("IPRIP2");
  155. //
  156. // make certain RIP is not already running
  157. //
  158. if (ig.IG_Status != IPRIP_STATUS_STOPPED) {
  159. TRACE0(START, "ERROR: StartProtocol called with IPRIP already running");
  160. LOGWARN0(IPRIP_ALREADY_STARTED, NO_ERROR);
  161. LeaveCriticalSection(&ig.IG_CS);
  162. return ERROR_CAN_NOT_COMPLETE;
  163. }
  164. bCleanupWinsock = FALSE;
  165. do { // break-out construct
  166. TRACE0(ENTER, "IPRIP is starting up");
  167. //
  168. // save the Router Manager notification event
  169. //
  170. ig.IG_EventEvent = hEventEvent;
  171. //
  172. // find the size of the global configuration passed in
  173. //
  174. pgcsrc = (PIPRIP_GLOBAL_CONFIG)pConfig;
  175. dwSize = IPRIP_GLOBAL_CONFIG_SIZE(pgcsrc);
  176. //
  177. // allocate a block to hold the configuration
  178. //
  179. ig.IG_Config = pgcdst = RIP_ALLOC(dwSize);
  180. if (pgcdst == NULL) {
  181. dwErr = GetLastError();
  182. TRACE2(
  183. ANY, "error %d allocating %d bytes for global config",
  184. dwErr, dwSize
  185. );
  186. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  187. break;
  188. }
  189. //
  190. // copy the supplied configuration
  191. //
  192. CopyMemory(pgcdst, pgcsrc, dwSize);
  193. ig.IG_LogLevel = pgcsrc->GC_LoggingLevel;
  194. //
  195. // attempt to start Winsock
  196. //
  197. dwErr = (DWORD)WSAStartup(MAKEWORD(1,1), &wd);
  198. if (dwErr != 0) {
  199. TRACE1(START, "error %d starting Windows Sockets.", dwErr);
  200. LOGERR0(WSASTARTUP_FAILED, dwErr);
  201. break;
  202. }
  203. bCleanupWinsock = TRUE;
  204. //
  205. // attempt to create synchronization object for global config
  206. //
  207. dwErr = CreateReadWriteLock(&ig.IG_RWL);
  208. if (dwErr != NO_ERROR) {
  209. TRACE1(START, "error %d creating read-write lock", dwErr);
  210. LOGERR0(CREATE_RWL_FAILED, dwErr);
  211. break;
  212. }
  213. //
  214. // register a timer queue with Ntdll timer thread
  215. //
  216. ig.IG_TimerQueueHandle = CreateTimerQueue();
  217. if ( !ig.IG_TimerQueueHandle) {
  218. dwErr = GetLastError();
  219. TRACE1(START,
  220. "error %d registering time queue with NtdllTimer thread",
  221. dwErr
  222. );
  223. LOGERR0(CREATE_TIMER_QUEUE_FAILED, dwErr);
  224. break;
  225. }
  226. //
  227. // allocate space for an interface table
  228. //
  229. ig.IG_IfTable = RIP_ALLOC(sizeof(IF_TABLE));
  230. if (ig.IG_IfTable == NULL) {
  231. dwErr = GetLastError();
  232. TRACE2(
  233. ANY, "error %d allocating %d bytes for interface table",
  234. dwErr, sizeof(IF_TABLE)
  235. );
  236. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  237. break;
  238. }
  239. //
  240. // initialize the interface table
  241. //
  242. dwErr = CreateIfTable(ig.IG_IfTable);
  243. if (dwErr != NO_ERROR) {
  244. TRACE1(START, "error %d initializing interface table", dwErr);
  245. LOGERR0(CREATE_IF_TABLE_FAILED, dwErr);
  246. break;
  247. }
  248. //
  249. // allocate space for the peer statistics table
  250. //
  251. ig.IG_PeerTable = RIP_ALLOC(sizeof(PEER_TABLE));
  252. if (ig.IG_PeerTable == NULL) {
  253. dwErr = GetLastError();
  254. TRACE2(
  255. ANY, "error %d allocating %d bytes for peer table",
  256. dwErr, sizeof(PEER_TABLE)
  257. );
  258. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  259. break;
  260. }
  261. //
  262. // initialize the peer statistics table
  263. //
  264. dwErr = CreatePeerTable(ig.IG_PeerTable);
  265. if (dwErr != NO_ERROR) {
  266. TRACE1(START, "error %d initializing peer statistics table", dwErr);
  267. LOGERR0(CREATE_PEER_TABLE_FAILED, dwErr);
  268. break;
  269. }
  270. //
  271. // allocate space for the binding table
  272. //
  273. ig.IG_BindingTable = RIP_ALLOC(sizeof(BINDING_TABLE));
  274. if (ig.IG_BindingTable == NULL) {
  275. dwErr = GetLastError();
  276. TRACE2(
  277. ANY, "error %d allocating %d bytes for binding table",
  278. dwErr, sizeof(PEER_TABLE)
  279. );
  280. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  281. break;
  282. }
  283. //
  284. // initialize the binding table
  285. //
  286. dwErr = CreateBindingTable(ig.IG_BindingTable);
  287. if (dwErr != NO_ERROR) {
  288. TRACE1(START, "error %d creating binding table", dwErr);
  289. LOGERR0(CREATE_BINDING_TABLE_FAILED, dwErr);
  290. break;
  291. }
  292. //
  293. // allocate space for the send queue
  294. //
  295. ig.IG_SendQueue = RIP_ALLOC(sizeof(LOCKED_LIST));
  296. if (ig.IG_SendQueue == NULL) {
  297. dwErr = GetLastError();
  298. TRACE2(
  299. ANY, "error %d allocating %d bytes for send-queue",
  300. dwErr, sizeof(LOCKED_LIST)
  301. );
  302. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  303. break;
  304. }
  305. //
  306. // initialize the send queue
  307. //
  308. try {
  309. CREATE_LOCKED_LIST(ig.IG_SendQueue);
  310. }
  311. except (EXCEPTION_EXECUTE_HANDLER) {
  312. dwErr = GetExceptionCode();
  313. TRACE1(START, "exception %d initializing send queue", dwErr);
  314. LOGERR0(INIT_CRITSEC_FAILED, dwErr);
  315. break;
  316. }
  317. //
  318. // allocate space for the receive queue
  319. //
  320. ig.IG_RecvQueue = RIP_ALLOC(sizeof(LOCKED_LIST));
  321. if (ig.IG_RecvQueue == NULL) {
  322. dwErr = GetLastError();
  323. TRACE2(
  324. ANY, "error %d allocating %d bytes for receive queue",
  325. dwErr, sizeof(LOCKED_LIST)
  326. );
  327. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  328. break;
  329. }
  330. //
  331. // initialize the receive queue
  332. //
  333. try {
  334. CREATE_LOCKED_LIST(ig.IG_RecvQueue);
  335. }
  336. except (EXCEPTION_EXECUTE_HANDLER) {
  337. dwErr = GetExceptionCode();
  338. TRACE1(START, "exception %d initializing receive queue", dwErr);
  339. LOGERR0(INIT_CRITSEC_FAILED, dwErr);
  340. break;
  341. }
  342. //
  343. // create event signalled by WinSock when input arrives
  344. // and register it with the NtdllWait thread
  345. //
  346. ig.IG_IpripInputEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  347. if (ig.IG_IpripInputEvent == NULL) {
  348. dwErr = GetLastError();
  349. TRACE1(START, "error %d creating event to signal input", dwErr);
  350. LOGERR0(CREATE_EVENT_FAILED, dwErr);
  351. break;
  352. }
  353. if (! RegisterWaitForSingleObject(
  354. &ig.IG_IpripInputEventHandle,
  355. ig.IG_IpripInputEvent,
  356. CallbackFunctionNetworkEvents,
  357. NULL,
  358. INFINITE,
  359. (WT_EXECUTEINWAITTHREAD|WT_EXECUTEONLYONCE)
  360. )) {
  361. dwErr = GetLastError();
  362. TRACE1(START,
  363. "error %d registering input event with NtdllWait thread",
  364. dwErr);
  365. LOGERR0(REGISTER_WAIT_FAILED, dwErr);
  366. break;
  367. }
  368. //
  369. // initialize the count of threads which are active in IPRIP
  370. // (includes IpripThread and worker threads),
  371. // and create the semaphore released by each thread when it is done
  372. //
  373. ig.IG_ActivityCount = 0;
  374. ig.IG_ActivitySemaphore = CreateSemaphore(NULL, 0, 0xfffffff, NULL);
  375. if (ig.IG_ActivitySemaphore == NULL) {
  376. dwErr = GetLastError();
  377. TRACE1(
  378. START, "error %d creating semaphore for IPRIP threads", dwErr
  379. );
  380. LOGERR0(CREATE_SEMAPHORE_FAILED, dwErr);
  381. break;
  382. }
  383. //
  384. // register with RTMv2
  385. //
  386. ig.IG_RtmEntityInfo.RtmInstanceId = 0;
  387. ig.IG_RtmEntityInfo.AddressFamily = AF_INET;
  388. ig.IG_RtmEntityInfo.EntityId.EntityProtocolId = PROTO_IP_RIP;
  389. ig.IG_RtmEntityInfo.EntityId.EntityInstanceId = 0;
  390. dwErr = RtmRegisterEntity(
  391. &ig.IG_RtmEntityInfo, NULL,
  392. ProcessRtmNotification,
  393. FALSE, &ig.IG_RtmProfile,
  394. &ig.IG_RtmHandle
  395. );
  396. if (dwErr != NO_ERROR ) {
  397. TRACE1(START, "error %d registering with RTM", dwErr);
  398. LOGERR0(RTM_REGISTER_FAILED, dwErr);
  399. break;
  400. }
  401. dwErr = RtmRegisterForChangeNotification(
  402. ig.IG_RtmHandle,
  403. RTM_VIEW_MASK_UCAST,
  404. RTM_CHANGE_TYPE_BEST,
  405. NULL,
  406. &ig.IG_RtmNotifHandle
  407. );
  408. if (dwErr != NO_ERROR ) {
  409. TRACE1(START, "error %d registering for change with RTM", dwErr);
  410. LOGERR0(RTM_REGISTER_FAILED, dwErr);
  411. break;
  412. }
  413. //
  414. // set IPRIP's status to running now, before we attempt
  415. // to queue the MIB display work-item;
  416. // QueueRipWorker() will check the status,
  417. // and it will refuse to queue any work-items
  418. // unless the status is IPRIP_STATUS_RUNNING
  419. //
  420. ig.IG_Status = IPRIP_STATUS_RUNNING;
  421. #if CONFIG_DBG
  422. //
  423. // queue work item to display IPRIP's MIB tables periodically
  424. //
  425. ig.IG_MibTraceID = TraceRegisterEx("IPRIPMIB", TRACE_USE_CONSOLE);
  426. if (ig.IG_MibTraceID != INVALID_TRACEID) {
  427. //
  428. // create the persistent timer for the timer queue
  429. //
  430. if (!CreateTimerQueueTimer(
  431. &ig.IG_MibTimerHandle, ig.IG_TimerQueueHandle,
  432. WorkerFunctionMibDisplay, NULL,
  433. 0, 10000, 0)) {
  434. dwErr = GetLastError();
  435. TRACE1(START, "error %d creating MIB display timer", dwErr);
  436. }
  437. }
  438. #endif
  439. TRACE0(START, "IPRIP has started successfully");
  440. LOGINFO0(IPRIP_STARTED, NO_ERROR);
  441. LeaveCriticalSection(&ig.IG_CS);
  442. return NO_ERROR;
  443. } while (FALSE);
  444. //
  445. // something went wrong, so we cleanup.
  446. // Note that we needn't worry about the main thread,
  447. // since when we finally leave this critical section it will find
  448. // that the status is IPRIP_STATUS_STOPPED, and it will immediately quit
  449. //
  450. TRACE0(START, "IPRIP failed to start");
  451. ProtocolCleanup(bCleanupWinsock);
  452. LeaveCriticalSection(&ig.IG_CS);
  453. return (dwErr == NO_ERROR ? ERROR_CAN_NOT_COMPLETE : dwErr);
  454. }
  455. //----------------------------------------------------------------------------
  456. // Function: ProtocolCleanup
  457. //
  458. // This function deallocates allocated memory, closes open handles, and
  459. // cleans up the global struct. It leaves IPRIP in clean state, so that
  460. // it should be possible to do StartProtocol again with no memory leaks.
  461. //----------------------------------------------------------------------------
  462. DWORD
  463. ProtocolCleanup(
  464. BOOL bCleanupWinsock
  465. ) {
  466. DWORD dwErr;
  467. // EnterCriticalSection(&ig.IG_CS);
  468. #ifdef CONFIG_DBG
  469. TraceDeregister(ig.IG_MibTraceID);
  470. ig.IG_MibTraceID = INVALID_TRACEID;
  471. #endif
  472. if ( ig.IG_RtmNotifHandle != NULL ) {
  473. dwErr = RtmDeregisterFromChangeNotification(
  474. ig.IG_RtmHandle, ig.IG_RtmNotifHandle
  475. );
  476. if ( dwErr != NO_ERROR ) {
  477. TRACE1(STOP, "error %d deregistering change notification", dwErr);
  478. }
  479. }
  480. if (ig.IG_RtmHandle != NULL) {
  481. dwErr = RtmDeregisterEntity(ig.IG_RtmHandle);
  482. if ( dwErr != NO_ERROR ) {
  483. TRACE1(STOP, "error %d deregistering from RTM", dwErr);
  484. }
  485. }
  486. if (ig.IG_ActivitySemaphore != NULL) {
  487. CloseHandle(ig.IG_ActivitySemaphore);
  488. ig.IG_ActivitySemaphore = NULL;
  489. }
  490. if (ig.IG_IpripInputEvent != NULL) {
  491. CloseHandle(ig.IG_IpripInputEvent);
  492. ig.IG_IpripInputEvent = NULL;
  493. }
  494. if (ig.IG_RecvQueue != NULL) {
  495. if (LOCKED_LIST_CREATED(ig.IG_RecvQueue)) {
  496. FlushRecvQueue(ig.IG_RecvQueue);
  497. DELETE_LOCKED_LIST(ig.IG_RecvQueue, RECV_QUEUE_ENTRY, RQE_Link);
  498. }
  499. RIP_FREE(ig.IG_RecvQueue);
  500. ig.IG_RecvQueue = NULL;
  501. }
  502. if (ig.IG_SendQueue != NULL) {
  503. if (LOCKED_LIST_CREATED(ig.IG_SendQueue)) {
  504. FlushSendQueue(ig.IG_SendQueue);
  505. DELETE_LOCKED_LIST(ig.IG_SendQueue, SEND_QUEUE_ENTRY, SQE_Link);
  506. }
  507. RIP_FREE(ig.IG_SendQueue);
  508. ig.IG_SendQueue = NULL;
  509. }
  510. if (ig.IG_BindingTable != NULL) {
  511. if (BINDING_TABLE_CREATED(ig.IG_BindingTable)) {
  512. DeleteBindingTable(ig.IG_BindingTable);
  513. }
  514. RIP_FREE(ig.IG_BindingTable);
  515. ig.IG_BindingTable = NULL;
  516. }
  517. if (ig.IG_PeerTable != NULL) {
  518. if (PEER_TABLE_CREATED(ig.IG_PeerTable)) {
  519. DeletePeerTable(ig.IG_PeerTable);
  520. }
  521. RIP_FREE(ig.IG_PeerTable);
  522. ig.IG_PeerTable = NULL;
  523. }
  524. if (ig.IG_IfTable != NULL) {
  525. if (IF_TABLE_CREATED(ig.IG_IfTable)) {
  526. DeleteIfTable(ig.IG_IfTable);
  527. }
  528. RIP_FREE(ig.IG_IfTable);
  529. ig.IG_IfTable = NULL;
  530. }
  531. if (READ_WRITE_LOCK_CREATED(&ig.IG_RWL)) {
  532. DeleteReadWriteLock(&ig.IG_RWL);
  533. }
  534. if (bCleanupWinsock) {
  535. WSACleanup();
  536. }
  537. if (ig.IG_Config != NULL) {
  538. RIP_FREE(ig.IG_Config);
  539. ig.IG_Config = NULL;
  540. }
  541. ig.IG_Status = IPRIP_STATUS_STOPPED;
  542. // LeaveCriticalSection(&ig.IG_CS);
  543. return NO_ERROR;
  544. }
  545. //----------------------------------------------------------------------------
  546. // Function: RegisterProtocol
  547. //
  548. // Returns protocol ID and functionality for IPRIP
  549. //----------------------------------------------------------------------------
  550. DWORD
  551. APIENTRY
  552. RegisterProtocol(
  553. IN OUT PMPR_ROUTING_CHARACTERISTICS pRoutingChar,
  554. IN OUT PMPR_SERVICE_CHARACTERISTICS pServiceChar
  555. )
  556. {
  557. if(pRoutingChar->dwProtocolId != MS_IP_RIP)
  558. {
  559. return ERROR_NOT_SUPPORTED;
  560. }
  561. //
  562. // Since we are not a service advertiser (and IPX thing)
  563. //
  564. pServiceChar->fSupportedFunctionality = 0;
  565. if((pRoutingChar->fSupportedFunctionality & (RF_ROUTING|RF_DEMAND_UPDATE_ROUTES)) !=
  566. (RF_ROUTING|RF_DEMAND_UPDATE_ROUTES))
  567. {
  568. return ERROR_NOT_SUPPORTED;
  569. }
  570. pRoutingChar->fSupportedFunctionality = (RF_ROUTING | RF_DEMAND_UPDATE_ROUTES);
  571. pRoutingChar->fSupportedFunctionality = RF_ROUTING;
  572. pRoutingChar->pfnStartProtocol = StartProtocol;
  573. pRoutingChar->pfnStartComplete = StartComplete;
  574. pRoutingChar->pfnStopProtocol = StopProtocol;
  575. pRoutingChar->pfnGetGlobalInfo = GetGlobalInfo;
  576. pRoutingChar->pfnSetGlobalInfo = SetGlobalInfo;
  577. pRoutingChar->pfnQueryPower = NULL;
  578. pRoutingChar->pfnSetPower = NULL;
  579. pRoutingChar->pfnAddInterface = AddInterface;
  580. pRoutingChar->pfnDeleteInterface = DeleteInterface;
  581. pRoutingChar->pfnInterfaceStatus = InterfaceStatus;
  582. pRoutingChar->pfnGetInterfaceInfo = GetInterfaceConfigInfo;
  583. pRoutingChar->pfnSetInterfaceInfo = SetInterfaceConfigInfo;
  584. pRoutingChar->pfnGetEventMessage = GetEventMessage;
  585. pRoutingChar->pfnUpdateRoutes = DoUpdateRoutes;
  586. pRoutingChar->pfnConnectClient = NULL;
  587. pRoutingChar->pfnDisconnectClient = NULL;
  588. pRoutingChar->pfnGetNeighbors = NULL;
  589. pRoutingChar->pfnGetMfeStatus = NULL;
  590. pRoutingChar->pfnMibCreateEntry = MibCreate;
  591. pRoutingChar->pfnMibDeleteEntry = MibDelete;
  592. pRoutingChar->pfnMibGetEntry = MibGet;
  593. pRoutingChar->pfnMibSetEntry = MibSet;
  594. pRoutingChar->pfnMibGetFirstEntry = MibGetFirst;
  595. pRoutingChar->pfnMibGetNextEntry = MibGetNext;
  596. return NO_ERROR;
  597. }
  598. //----------------------------------------------------------------------------
  599. // Function: StartProtocol
  600. //
  601. // creates events, tables and queues used by IPRIP, registers with RTM,
  602. // and starts threads.
  603. //----------------------------------------------------------------------------
  604. DWORD
  605. WINAPI
  606. StartProtocol (
  607. HANDLE NotificationEvent,
  608. SUPPORT_FUNCTIONS *SupportFunctions,
  609. LPVOID GlobalInfo,
  610. ULONG StructureVersion,
  611. ULONG StructureSize,
  612. ULONG StructureCount
  613. )
  614. {
  615. ig.IG_SupportFunctions = *SupportFunctions;
  616. return ProtocolStartup(NotificationEvent, GlobalInfo);
  617. }
  618. //----------------------------------------------------------------------------
  619. // Function: StartComplete
  620. //
  621. // Invoked by RouterManager to inform protocol that startup (init + interface
  622. // additions are complete). Protocol is expected to wait for this before
  623. // starting protocol specfic behavior
  624. //----------------------------------------------------------------------------
  625. DWORD
  626. APIENTRY
  627. StartComplete(
  628. VOID
  629. )
  630. {
  631. return NO_ERROR;
  632. }
  633. //----------------------------------------------------------------------------
  634. // Function: StopProtocol
  635. //
  636. // This function is onvoked by Router Manager. It informs the main thread
  637. // that it should exit, and then queues a work-item which waits for it
  638. // to exit as well as any active or queued work-items.
  639. //----------------------------------------------------------------------------
  640. DWORD
  641. APIENTRY
  642. StopProtocol(
  643. VOID
  644. ) {
  645. LONG lThreadCount;
  646. EnterCriticalSection(&ig.IG_CS);
  647. //
  648. // cannot stop if already stopped
  649. //
  650. if (ig.IG_Status != IPRIP_STATUS_RUNNING) {
  651. LeaveCriticalSection(&ig.IG_CS);
  652. return ERROR_CAN_NOT_COMPLETE;
  653. }
  654. TRACE0(ENTER, "entering StopProtocol");
  655. //
  656. // set IPRIP's status to STOPPING;
  657. // this prevents any more work-items from being queued,
  658. // and it prevents the ones already queued from executing
  659. //
  660. ig.IG_Status = IPRIP_STATUS_STOPPING;
  661. //
  662. // find out how many threads are active in IPRIP;
  663. // we will have to wait for this many threads to exit
  664. // before we clean up RIP's resources
  665. //
  666. lThreadCount = ig.IG_ActivityCount;
  667. TRACE1(STOP, "%d threads are active in IPRIP", lThreadCount);
  668. LeaveCriticalSection(&ig.IG_CS);
  669. //
  670. // queue the stopprotocol work-item, and return PENDING to Router Manager
  671. //
  672. QueueUserWorkItem(
  673. (LPTHREAD_START_ROUTINE)WorkerFunctionFinishStopProtocol,
  674. (PVOID)UlongToPtr(lThreadCount), 0
  675. );
  676. TRACE0(LEAVE, "leaving StopProtocol");
  677. return ERROR_PROTOCOL_STOP_PENDING;
  678. }
  679. //----------------------------------------------------------------------------
  680. // Function: GetGlobalInfo
  681. //
  682. // Copies to the given buffer the global information currently in use by
  683. // IPRIP.
  684. //----------------------------------------------------------------------------
  685. DWORD WINAPI
  686. GetGlobalInfo (
  687. PVOID OutGlobalInfo,
  688. PULONG GlobalInfoSize,
  689. PULONG StructureVersion,
  690. PULONG StructureSize,
  691. PULONG StructureCount
  692. )
  693. {
  694. DWORD dwErr, dwSize;
  695. PIPRIP_GLOBAL_CONFIG pgcsrc, pgcdst;
  696. if (!ENTER_RIP_API()) { return ERROR_CAN_NOT_COMPLETE; }
  697. TRACE2(ENTER, "entering GetGlobalInfo: 0x%08x 0x%08x", OutGlobalInfo, GlobalInfoSize);
  698. dwErr = NO_ERROR;
  699. ACQUIRE_GLOBAL_LOCK_SHARED();
  700. do {
  701. //
  702. // check the arguments
  703. //
  704. if (GlobalInfoSize == NULL) {
  705. dwErr = ERROR_INVALID_PARAMETER;
  706. break;
  707. }
  708. pgcsrc = ig.IG_Config;
  709. dwSize = IPRIP_GLOBAL_CONFIG_SIZE(pgcsrc);
  710. //
  711. // check the buffer size
  712. //
  713. if (*GlobalInfoSize < dwSize || OutGlobalInfo == NULL) {
  714. dwErr = ERROR_INSUFFICIENT_BUFFER;
  715. }
  716. else {
  717. pgcdst = (PIPRIP_GLOBAL_CONFIG)OutGlobalInfo;
  718. *StructureVersion = 1;
  719. *StructureSize = dwSize;
  720. *StructureCount = 1;
  721. CopyMemory(pgcdst, pgcsrc, dwSize);
  722. }
  723. *GlobalInfoSize = dwSize;
  724. } while(FALSE);
  725. RELEASE_GLOBAL_LOCK_SHARED();
  726. TRACE1(LEAVE, "leaving GetGlobalInfo: %d", dwErr);
  727. LEAVE_RIP_API();
  728. return dwErr;
  729. }
  730. //----------------------------------------------------------------------------
  731. // Function: SetGlobalInfo
  732. //
  733. // Changes IPRIP's global configuration to the supplied values.
  734. //----------------------------------------------------------------------------
  735. DWORD WINAPI
  736. SetGlobalInfo (
  737. PVOID GlobalInfo,
  738. ULONG StructureVersion,
  739. ULONG StructureSize,
  740. ULONG StructureCount
  741. )
  742. {
  743. DWORD dwErr, dwSize;
  744. PIPRIP_GLOBAL_CONFIG pgcsrc, pgcdst;
  745. if (!ENTER_RIP_API()) { return ERROR_CAN_NOT_COMPLETE; }
  746. TRACE1(ENTER, "entering SetGlobalInfo: 0x%08x", GlobalInfo);
  747. dwErr = NO_ERROR;
  748. ACQUIRE_GLOBAL_LOCK_EXCLUSIVE();
  749. do {
  750. //
  751. // check the argument
  752. //
  753. if (GlobalInfo == NULL) {
  754. dwErr = ERROR_INVALID_PARAMETER;
  755. break;
  756. }
  757. pgcsrc = (PIPRIP_GLOBAL_CONFIG)GlobalInfo;
  758. //
  759. // find the size of the new global config
  760. //
  761. dwSize = IPRIP_GLOBAL_CONFIG_SIZE(pgcsrc);
  762. //
  763. // allocate space for the private copy of the config
  764. //
  765. pgcdst = (PIPRIP_GLOBAL_CONFIG)RIP_ALLOC(dwSize);
  766. if (pgcdst == NULL) {
  767. dwErr = GetLastError();
  768. TRACE2(
  769. ANY, "error %d allocating %d bytes for global config",
  770. dwErr, dwSize
  771. );
  772. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  773. break;
  774. }
  775. //
  776. // copy from the buffer
  777. //
  778. CopyMemory(pgcdst, pgcsrc, dwSize);
  779. InterlockedExchange(&ig.IG_LogLevel, pgcsrc->GC_LoggingLevel);
  780. if (ig.IG_Config != NULL) { RIP_FREE(ig.IG_Config); }
  781. ig.IG_Config = pgcdst;
  782. } while(FALSE);
  783. RELEASE_GLOBAL_LOCK_EXCLUSIVE();
  784. TRACE1(LEAVE, "leaving SetGlobalInfo: %d", dwErr);
  785. LEAVE_RIP_API();
  786. return dwErr;
  787. }
  788. //----------------------------------------------------------------------------
  789. // Function: AddInterface
  790. //
  791. // This function is called to add an interface with the given configuration
  792. // to IPRIP. The interface is created inactive.
  793. //----------------------------------------------------------------------------
  794. DWORD WINAPI
  795. AddInterface (
  796. PWCHAR pwszInterfaceName,
  797. ULONG InterfaceIndex,
  798. NET_INTERFACE_TYPE InterfaceType,
  799. DWORD MediaType,
  800. WORD AccessType,
  801. WORD ConnectionType,
  802. PVOID InterfaceInfo,
  803. ULONG StructureVersion,
  804. ULONG StructureSize,
  805. ULONG StructureCount
  806. )
  807. {
  808. DWORD dwErr;
  809. if (!ENTER_RIP_API()) { return ERROR_CAN_NOT_COMPLETE; }
  810. TRACE3(
  811. ENTER, "entering AddInterface: %d %d 0x%08x", InterfaceIndex, InterfaceType, InterfaceInfo
  812. );
  813. ACQUIRE_IF_LOCK_EXCLUSIVE();
  814. dwErr = CreateIfEntry(ig.IG_IfTable, InterfaceIndex, InterfaceType, InterfaceInfo, NULL);
  815. RELEASE_IF_LOCK_EXCLUSIVE();
  816. TRACE1(LEAVE, "leaving AddInterface: %d", dwErr);
  817. LEAVE_RIP_API();
  818. return dwErr;
  819. }
  820. //----------------------------------------------------------------------------
  821. // Function: DeleteInterface
  822. //
  823. // This removes the interface with the given index, deactivating it if
  824. // necessary.
  825. //----------------------------------------------------------------------------
  826. DWORD
  827. APIENTRY
  828. DeleteInterface(
  829. IN DWORD dwIndex
  830. ) {
  831. DWORD dwErr;
  832. PIF_TABLE pTable;
  833. if (!ENTER_RIP_API()) { return ERROR_CAN_NOT_COMPLETE; }
  834. TRACE1(ENTER, "entering DeleteInterface: %d", dwIndex);
  835. ACQUIRE_IF_LOCK_EXCLUSIVE();
  836. dwErr = DeleteIfEntry(ig.IG_IfTable, dwIndex);
  837. RELEASE_IF_LOCK_EXCLUSIVE();
  838. TRACE1(LEAVE, "leaving DeleteInterface: %d", dwErr);
  839. LEAVE_RIP_API();
  840. return dwErr;
  841. }
  842. //----------------------------------------------------------------------------
  843. // Function: GetEventMessage
  844. //
  845. // Dequeues a message for Router Manager from IPRIP's event queue.
  846. //----------------------------------------------------------------------------
  847. DWORD
  848. APIENTRY
  849. GetEventMessage(
  850. OUT ROUTING_PROTOCOL_EVENTS *pEvent,
  851. OUT PMESSAGE pResult
  852. ) {
  853. DWORD dwErr;
  854. //
  855. // note that GetEventMessage does not use the
  856. // ENTER_RIP_API()/LEAVE_RIP_API() mechanism,
  857. // since it may be called after RIP has stopped, when the
  858. // Router Manager is retrieving the ROUTER_STOPPED message
  859. //
  860. TRACE2(ENTER, "entering GetEventMessage: 0x%08x 0x%08x", pEvent, pResult);
  861. ACQUIRE_LIST_LOCK(ig.IG_EventQueue);
  862. dwErr = DequeueEvent(ig.IG_EventQueue, pEvent, pResult);
  863. RELEASE_LIST_LOCK(ig.IG_EventQueue);
  864. TRACE1(LEAVE, "leaving GetEventMessage: %d", dwErr);
  865. return dwErr;
  866. }
  867. //----------------------------------------------------------------------------
  868. // Function: GetInterfaceConfigInfo
  869. //
  870. // Copies to the caller's buffer the configuration for the interface
  871. // with the specified index.
  872. //----------------------------------------------------------------------------
  873. DWORD WINAPI
  874. GetInterfaceConfigInfo (
  875. ULONG InterfaceIndex,
  876. PVOID OutInterfaceInfo,
  877. PULONG InterfaceInfoSize,
  878. PULONG StructureVersion,
  879. PULONG StructureSize,
  880. PULONG StructureCount
  881. )
  882. {
  883. DWORD dwErr, dwSize;
  884. PIF_TABLE pTable;
  885. PIF_TABLE_ENTRY pite;
  886. PIPRIP_IF_CONFIG picsrc, picdst;
  887. if (!ENTER_RIP_API()) { return ERROR_CAN_NOT_COMPLETE; }
  888. TRACE3(
  889. ENTER, "entering GetInterfaceConfigInfo: %d 0x%08x 0x%08x",
  890. InterfaceIndex,, OutInterfaceInfo, InterfaceInfoSize
  891. );
  892. dwErr = NO_ERROR;
  893. do {
  894. //
  895. // check the arguments
  896. //
  897. if (InterfaceInfoSize == NULL) {
  898. dwErr = ERROR_INVALID_PARAMETER;
  899. break;
  900. }
  901. pTable = ig.IG_IfTable;
  902. ACQUIRE_IF_LOCK_SHARED();
  903. //
  904. // find the interface specified
  905. //
  906. pite = GetIfByIndex(pTable, InterfaceIndex);
  907. if (pite == NULL) {
  908. dwErr = ERROR_INVALID_PARAMETER;
  909. }
  910. else {
  911. //
  912. // get the size of the interface config
  913. //
  914. picsrc = pite->ITE_Config;
  915. dwSize = IPRIP_IF_CONFIG_SIZE(picsrc);
  916. //
  917. // check the buffer size
  918. //
  919. if (*InterfaceInfoSize < dwSize) {
  920. dwErr = ERROR_INSUFFICIENT_BUFFER;
  921. }
  922. else {
  923. picdst = (PIPRIP_IF_CONFIG)OutInterfaceInfo;
  924. //
  925. // copy the interface config, and set the IP address
  926. //
  927. CopyMemory(picdst, picsrc, dwSize);
  928. *StructureVersion = 1;
  929. *StructureSize = dwSize;
  930. *StructureCount = 1;
  931. picdst->IC_State = 0;
  932. if (IF_IS_ENABLED(pite)) {
  933. picdst->IC_State |= IPRIP_STATE_ENABLED;
  934. }
  935. if (IF_IS_BOUND(pite)) {
  936. picdst->IC_State |= IPRIP_STATE_BOUND;
  937. }
  938. }
  939. *InterfaceInfoSize = dwSize;
  940. }
  941. RELEASE_IF_LOCK_SHARED();
  942. } while(FALSE);
  943. TRACE1(LEAVE, "leaving GetInterfaceConfigInfo: %d", dwErr);
  944. LEAVE_RIP_API();
  945. return dwErr;
  946. }
  947. //----------------------------------------------------------------------------
  948. // Function: SetInterfaceConfigInfo
  949. //
  950. // This sets the configuration for the interface with the given index.
  951. //----------------------------------------------------------------------------
  952. DWORD WINAPI
  953. SetInterfaceConfigInfo (
  954. ULONG InterfaceIndex,
  955. PVOID InterfaceInfo,
  956. ULONG StructureVersion,
  957. ULONG StructureSize,
  958. ULONG StructureCount
  959. )
  960. {
  961. DWORD dwErr;
  962. PIF_TABLE pTable;
  963. PIF_TABLE_ENTRY pite;
  964. if (!ENTER_RIP_API()) { return ERROR_CAN_NOT_COMPLETE; }
  965. TRACE2(
  966. ENTER, "entering SetInterfaceConfigInfo: %d, 0x%08x", InterfaceIndex, InterfaceInfo
  967. );
  968. dwErr = NO_ERROR;
  969. do {
  970. if (InterfaceInfo == NULL) {
  971. dwErr = ERROR_INVALID_PARAMETER;
  972. break;
  973. }
  974. pTable = ig.IG_IfTable;
  975. ACQUIRE_IF_LOCK_EXCLUSIVE();
  976. dwErr = ConfigureIfEntry(pTable, InterfaceIndex, InterfaceInfo);
  977. RELEASE_IF_LOCK_EXCLUSIVE();
  978. } while(FALSE);
  979. TRACE1(LEAVE, "leaving SetInterfaceConfigInfo: %d", dwErr);
  980. LEAVE_RIP_API();
  981. return dwErr;
  982. }
  983. DWORD WINAPI
  984. InterfaceStatus(
  985. ULONG InterfaceIndex,
  986. BOOL InterfaceActive,
  987. DWORD StatusType,
  988. PVOID StatusInfo
  989. )
  990. {
  991. DWORD dwResult;
  992. if (!ENTER_RIP_API()) { return ERROR_CAN_NOT_COMPLETE; }
  993. switch(StatusType)
  994. {
  995. case RIS_INTERFACE_ADDRESS_CHANGE:
  996. {
  997. PIP_ADAPTER_BINDING_INFO pBindInfo;
  998. pBindInfo = (PIP_ADAPTER_BINDING_INFO)StatusInfo;
  999. if(pBindInfo->AddressCount)
  1000. {
  1001. dwResult = BindInterface(InterfaceIndex,
  1002. pBindInfo);
  1003. }
  1004. else
  1005. {
  1006. dwResult = UnBindInterface(InterfaceIndex);
  1007. }
  1008. break;
  1009. }
  1010. case RIS_INTERFACE_ENABLED:
  1011. {
  1012. dwResult = EnableInterface(InterfaceIndex);
  1013. break;
  1014. }
  1015. case RIS_INTERFACE_DISABLED:
  1016. {
  1017. dwResult = DisableInterface(InterfaceIndex);
  1018. break;
  1019. }
  1020. default:
  1021. {
  1022. RTASSERT(FALSE);
  1023. dwResult = ERROR_INVALID_PARAMETER;
  1024. }
  1025. }
  1026. LEAVE_RIP_API();
  1027. return dwResult;
  1028. }
  1029. //---------------------------------------------------------------------------
  1030. // Function: BindInterface
  1031. //
  1032. // This function is called to supply the binding information
  1033. // for an interface
  1034. //---------------------------------------------------------------------------
  1035. DWORD
  1036. APIENTRY
  1037. BindInterface(
  1038. IN DWORD dwIndex,
  1039. IN PVOID pBinding
  1040. ) {
  1041. DWORD dwErr;
  1042. PIF_TABLE pTable;
  1043. TRACE2(ENTER, "entering BindInterface: %d 0x%08x", dwIndex, pBinding);
  1044. if (pBinding == NULL) {
  1045. TRACE0(IF, "error: binding struct pointer is NULL");
  1046. TRACE1(LEAVE, "leaving BindInterface: %d", ERROR_INVALID_PARAMETER);
  1047. return ERROR_INVALID_PARAMETER;
  1048. }
  1049. //
  1050. // now bind the interface in the interface table
  1051. //
  1052. pTable = ig.IG_IfTable;
  1053. ACQUIRE_IF_LOCK_EXCLUSIVE();
  1054. dwErr = BindIfEntry(pTable, dwIndex, pBinding);
  1055. RELEASE_IF_LOCK_EXCLUSIVE();
  1056. TRACE1(LEAVE, "leaving BindInterface: %d", dwErr);
  1057. return dwErr;
  1058. }
  1059. //---------------------------------------------------------------------------
  1060. // Function: UnBindInterface
  1061. //
  1062. // This function removes the binding for an interface.
  1063. //---------------------------------------------------------------------------
  1064. DWORD
  1065. APIENTRY
  1066. UnBindInterface(
  1067. IN DWORD dwIndex
  1068. ) {
  1069. DWORD dwErr;
  1070. PIF_TABLE pTable;
  1071. PIF_TABLE_ENTRY pite;
  1072. TRACE1(ENTER, "entering UnBindInterface: %d", dwIndex);
  1073. pTable = ig.IG_IfTable;
  1074. //
  1075. // unbind the interface
  1076. //
  1077. ACQUIRE_IF_LOCK_EXCLUSIVE();
  1078. dwErr = UnBindIfEntry(pTable, dwIndex);
  1079. RELEASE_IF_LOCK_EXCLUSIVE();
  1080. TRACE1(LEAVE, "leaving UnBindInterface: %d", dwErr);
  1081. return dwErr;
  1082. }
  1083. //----------------------------------------------------------------------------
  1084. // Function: EnableInterface
  1085. //
  1086. // This function starts IPRIP activity over the interface with
  1087. // the given index, using the given binding information.
  1088. //----------------------------------------------------------------------------
  1089. DWORD
  1090. APIENTRY
  1091. EnableInterface(
  1092. IN DWORD dwIndex
  1093. ) {
  1094. DWORD dwErr;
  1095. PIF_TABLE pTable;
  1096. TRACE1(ENTER, "entering EnableInterface: %d", dwIndex);
  1097. pTable = ig.IG_IfTable;
  1098. //
  1099. // activate the interface
  1100. //
  1101. ACQUIRE_IF_LOCK_EXCLUSIVE();
  1102. dwErr = EnableIfEntry(pTable, dwIndex);
  1103. RELEASE_IF_LOCK_EXCLUSIVE();
  1104. TRACE1(LEAVE, "leaving EnableInterface: %d", dwErr);
  1105. return dwErr;
  1106. }
  1107. //----------------------------------------------------------------------------
  1108. // Function: DisableInterface
  1109. //
  1110. // This function stops IPRIP activity on an interface, also removing
  1111. // routes associated with the interface from RTM and purging the network
  1112. // of such routes.
  1113. //----------------------------------------------------------------------------
  1114. DWORD
  1115. APIENTRY
  1116. DisableInterface(
  1117. IN DWORD dwIndex
  1118. ) {
  1119. DWORD dwErr;
  1120. PIF_TABLE pTable;
  1121. TRACE1(ENTER, "entering DisableInterface: %d", dwIndex);
  1122. pTable = ig.IG_IfTable;
  1123. //
  1124. // stop activity on the interface
  1125. //
  1126. ACQUIRE_IF_LOCK_EXCLUSIVE();
  1127. dwErr = DisableIfEntry(pTable, dwIndex);
  1128. RELEASE_IF_LOCK_EXCLUSIVE();
  1129. TRACE1(LEAVE, "leaving DisableInterface: %d", dwIndex);
  1130. return dwErr;
  1131. }
  1132. //----------------------------------------------------------------------------
  1133. // Function: DoUpdateRoutes
  1134. //
  1135. // This function begins a demand-update of routes, by queuing a work-item
  1136. // which will send out requests on the specified interface.
  1137. //----------------------------------------------------------------------------
  1138. DWORD
  1139. APIENTRY
  1140. DoUpdateRoutes(
  1141. IN DWORD dwIndex
  1142. ) {
  1143. DWORD dwErr;
  1144. if (!ENTER_RIP_API()) { return ERROR_CAN_NOT_COMPLETE; }
  1145. TRACE1(ENTER, "entering DoUpdateRoutes: %d", dwIndex);
  1146. //
  1147. // queue the work-item; perhaps we could call the function directly,
  1148. // but using a worker-thread lets us return to Router Manager right away
  1149. //
  1150. dwErr = QueueRipWorker(
  1151. WorkerFunctionStartDemandUpdate,
  1152. (PVOID)UlongToPtr(dwIndex)
  1153. );
  1154. TRACE1(LEAVE,"leaving DoUpdateRoutes(), errcode %d", dwErr);
  1155. LEAVE_RIP_API();
  1156. return dwErr;
  1157. }
  1158. //----------------------------------------------------------------------------
  1159. // Function: MibCreate
  1160. //
  1161. // This function does nothing, since IPRIP does not support creation of
  1162. // interface objects via SNMP. However, this could be implemented as a call
  1163. // to CreateIfEntry() followed by a call to ActivateIfEntry(), and the input
  1164. // data would have to contain the interface's index, configuration,
  1165. // and binding.
  1166. //----------------------------------------------------------------------------
  1167. DWORD
  1168. APIENTRY
  1169. MibCreate(
  1170. IN DWORD dwInputSize,
  1171. IN PVOID pInputData
  1172. ) {
  1173. DWORD dwErr;
  1174. if (!ENTER_RIP_API()) { return ERROR_CAN_NOT_COMPLETE; }
  1175. TRACE2(ENTER, "entering MibCreate: %d 0x%08x", dwInputSize, pInputData);
  1176. dwErr = ERROR_CAN_NOT_COMPLETE;
  1177. TRACE1(LEAVE, "leaving MibCreate: %d", dwErr);
  1178. LEAVE_RIP_API();
  1179. return dwErr;
  1180. }
  1181. //----------------------------------------------------------------------------
  1182. // Function: MibDelete
  1183. //
  1184. // This function does nothing, since IPRIP does not support deletion of
  1185. // interface objects via SNMP. This could be implemented as a call to
  1186. // DeactivateIfEntry() followed by a call to DeleteIfEntry(), and the
  1187. // input data would have to contain the interface's index
  1188. //----------------------------------------------------------------------------
  1189. DWORD
  1190. APIENTRY
  1191. MibDelete(
  1192. IN DWORD dwInputSize,
  1193. IN PVOID pInputData
  1194. ) {
  1195. DWORD dwErr;
  1196. if (!ENTER_RIP_API()) { return ERROR_CAN_NOT_COMPLETE; }
  1197. TRACE2(ENTER, "entering MibDelete: %d 0x%08x", dwInputSize, pInputData);
  1198. dwErr = ERROR_CAN_NOT_COMPLETE;
  1199. TRACE1(LEAVE, "leaving MibDelete: %d", dwErr);
  1200. LEAVE_RIP_API();
  1201. return dwErr;
  1202. }
  1203. //----------------------------------------------------------------------------
  1204. // Function: MibSet
  1205. //
  1206. // The function sets global or interface configuration.
  1207. //----------------------------------------------------------------------------
  1208. DWORD
  1209. APIENTRY
  1210. MibSet(
  1211. IN DWORD dwInputSize,
  1212. IN PVOID pInputData
  1213. ) {
  1214. DWORD dwErr;
  1215. PIPRIP_MIB_SET_INPUT_DATA pimsid;
  1216. if (!ENTER_RIP_API()) { return ERROR_CAN_NOT_COMPLETE; }
  1217. TRACE2(ENTER, "entering MibSet: %d 0x%08x", dwInputSize, pInputData);
  1218. dwErr = NO_ERROR;
  1219. do { // breakout loop
  1220. if (pInputData == NULL) {
  1221. dwErr = ERROR_INVALID_PARAMETER;
  1222. break;
  1223. }
  1224. if (dwInputSize < sizeof(IPRIP_MIB_SET_INPUT_DATA)) {
  1225. dwErr = ERROR_INSUFFICIENT_BUFFER;
  1226. break;
  1227. }
  1228. pimsid = (PIPRIP_MIB_SET_INPUT_DATA)pInputData;
  1229. switch (pimsid->IMSID_TypeID) {
  1230. case IPRIP_GLOBAL_CONFIG_ID: {
  1231. PIPRIP_GLOBAL_CONFIG pigc;
  1232. if (pimsid->IMSID_BufferSize < sizeof(IPRIP_GLOBAL_CONFIG)) {
  1233. dwErr = ERROR_INSUFFICIENT_BUFFER;
  1234. break;
  1235. }
  1236. dwErr = SetGlobalInfo(pimsid->IMSID_Buffer,1,0,1);
  1237. if (dwErr == NO_ERROR) {
  1238. MESSAGE msg = {0, 0, 0};
  1239. ACQUIRE_LIST_LOCK(ig.IG_EventQueue);
  1240. EnqueueEvent(
  1241. ig.IG_EventQueue, SAVE_GLOBAL_CONFIG_INFO, msg
  1242. );
  1243. SetEvent(ig.IG_EventEvent);
  1244. RELEASE_LIST_LOCK(ig.IG_EventQueue);
  1245. }
  1246. break;
  1247. }
  1248. case IPRIP_IF_CONFIG_ID: {
  1249. DWORD dwSize;
  1250. PIF_TABLE pTable;
  1251. PIPRIP_IF_CONFIG pic;
  1252. PIF_TABLE_ENTRY pite;
  1253. if (pimsid->IMSID_BufferSize < sizeof(IPRIP_IF_CONFIG)) {
  1254. dwErr = ERROR_INSUFFICIENT_BUFFER;
  1255. break;
  1256. }
  1257. pic = (PIPRIP_IF_CONFIG)pimsid->IMSID_Buffer;
  1258. pTable = ig.IG_IfTable;
  1259. ACQUIRE_IF_LOCK_EXCLUSIVE();
  1260. //
  1261. // retrieve the interface to be configured
  1262. //
  1263. pite = GetIfByIndex(
  1264. pTable, pimsid->IMSID_IfIndex
  1265. );
  1266. if (pite == NULL) {
  1267. dwErr = ERROR_INVALID_PARAMETER;
  1268. }
  1269. else {
  1270. dwErr = ConfigureIfEntry(pTable, pite->ITE_Index, pic);
  1271. }
  1272. //
  1273. // notify Router Manager
  1274. //
  1275. if (dwErr == NO_ERROR) {
  1276. MESSAGE msg = {0, 0, 0};
  1277. msg.InterfaceIndex = pite->ITE_Index;
  1278. ACQUIRE_LIST_LOCK(ig.IG_EventQueue);
  1279. EnqueueEvent(
  1280. ig.IG_EventQueue, SAVE_INTERFACE_CONFIG_INFO, msg
  1281. );
  1282. SetEvent(ig.IG_EventEvent);
  1283. RELEASE_LIST_LOCK(ig.IG_EventQueue);
  1284. }
  1285. RELEASE_IF_LOCK_EXCLUSIVE();
  1286. break;
  1287. }
  1288. default: {
  1289. dwErr = ERROR_INVALID_PARAMETER;
  1290. }
  1291. }
  1292. } while(FALSE);
  1293. TRACE1(LEAVE, "leaving MibSet: %d", dwErr);
  1294. LEAVE_RIP_API();
  1295. return dwErr;
  1296. }
  1297. //----------------------------------------------------------------------------
  1298. // Function: MibGetInternal
  1299. //
  1300. // Forward declaration of internal implementation function
  1301. //----------------------------------------------------------------------------
  1302. DWORD
  1303. MibGetInternal(
  1304. PIPRIP_MIB_GET_INPUT_DATA pimgid,
  1305. PIPRIP_MIB_GET_OUTPUT_DATA pimgod,
  1306. PDWORD pdwOutputSize,
  1307. DWORD dwGetMode
  1308. );
  1309. //----------------------------------------------------------------------------
  1310. // Function: MibGet
  1311. //
  1312. // This function retrieves global or interface configuration, as well as
  1313. // global stats, interface stats, and peer-router stats.
  1314. //----------------------------------------------------------------------------
  1315. DWORD
  1316. APIENTRY
  1317. MibGet(
  1318. IN DWORD dwInputSize,
  1319. IN PVOID pInputData,
  1320. IN OUT PDWORD pdwOutputSize,
  1321. OUT PVOID pOutputData
  1322. ) {
  1323. DWORD dwErr;
  1324. PIPRIP_MIB_GET_INPUT_DATA pimgid;
  1325. PIPRIP_MIB_GET_OUTPUT_DATA pimgod;
  1326. if (!ENTER_RIP_API()) { return ERROR_CAN_NOT_COMPLETE; }
  1327. TRACE4(
  1328. ENTER, "entering MibGet: %d 0x%08x 0x%08x 0x%08x",
  1329. dwInputSize, pInputData, pdwOutputSize, pOutputData
  1330. );
  1331. if (pInputData == NULL ||
  1332. dwInputSize < sizeof(IPRIP_MIB_GET_INPUT_DATA) ||
  1333. pdwOutputSize == NULL) {
  1334. dwErr = ERROR_INVALID_PARAMETER;
  1335. }
  1336. else {
  1337. pimgid = (PIPRIP_MIB_GET_INPUT_DATA)pInputData;
  1338. pimgod = (PIPRIP_MIB_GET_OUTPUT_DATA)pOutputData;
  1339. dwErr = MibGetInternal(pimgid, pimgod, pdwOutputSize, GETMODE_EXACT);
  1340. }
  1341. TRACE1(LEAVE, "leaving MibGet: %d", dwErr);
  1342. LEAVE_RIP_API();
  1343. return dwErr;
  1344. }
  1345. //----------------------------------------------------------------------------
  1346. // Function: MibGetFirst
  1347. //
  1348. // This function retrieves global or interface configuration, as well as
  1349. // global stats, interface stats, and peer-router stats. It differs from
  1350. // MibGet() in that it always returns the FIRST entry in whichever table
  1351. // is being queried. There is only one entry in the global stats and config
  1352. // tables, but the interface config, interface stats, and peer stats tables
  1353. // are sorted by IP address; this function returns the first entry from these.
  1354. //----------------------------------------------------------------------------
  1355. DWORD
  1356. APIENTRY
  1357. MibGetFirst(
  1358. IN DWORD dwInputSize,
  1359. IN PVOID pInputData,
  1360. IN OUT PDWORD pdwOutputSize,
  1361. OUT PVOID pOutputData
  1362. ) {
  1363. DWORD dwErr;
  1364. PIPRIP_MIB_GET_INPUT_DATA pimgid;
  1365. PIPRIP_MIB_GET_OUTPUT_DATA pimgod;
  1366. if (!ENTER_RIP_API()) { return ERROR_CAN_NOT_COMPLETE; }
  1367. TRACE4(
  1368. ENTER, "entering MibGetFirst: %d 0x%08x 0x%08x 0x%08x",
  1369. dwInputSize, pInputData, pdwOutputSize, pOutputData
  1370. );
  1371. if (pInputData == NULL ||
  1372. dwInputSize < sizeof(IPRIP_MIB_GET_INPUT_DATA) ||
  1373. pdwOutputSize == NULL) {
  1374. dwErr = ERROR_INVALID_PARAMETER;
  1375. }
  1376. else {
  1377. pimgid = (PIPRIP_MIB_GET_INPUT_DATA)pInputData;
  1378. pimgod = (PIPRIP_MIB_GET_OUTPUT_DATA)pOutputData;
  1379. dwErr = MibGetInternal(pimgid, pimgod, pdwOutputSize, GETMODE_FIRST);
  1380. }
  1381. TRACE1(LEAVE, "leaving MibGetFirst: %d", dwErr);
  1382. LEAVE_RIP_API();
  1383. return dwErr;
  1384. }
  1385. //----------------------------------------------------------------------------
  1386. // Function: MibGetNext
  1387. //
  1388. // This function retrieves global or interface configuration, as well as
  1389. // global stats, interface stats, and peer-router stats. It differs from both
  1390. // MibGet() and MibGetFirst(0 in that it always returns the entry AFTER the
  1391. // specified in the specified table. Thus, in the interface config, interface
  1392. // stats, and peer stats tables, this function supplies the entry after the
  1393. // one with the address passed in.
  1394. //
  1395. // If the end of the table being queried has been reached, this function will
  1396. // return the FIRST entry from the NEXT table, where "NEXT" here means the
  1397. // table whose ID is one greater than the ID passed in.
  1398. // Thus calling MibGetNext() for the last entry in the interface
  1399. // stats table (ID==2) will return the first entry in the interface config
  1400. // table (ID==3).
  1401. //
  1402. // In any case, this function writes the required size to pdwOutputSize and
  1403. // writes the ID of the object that WOULD have been returned into the output
  1404. // buffer.
  1405. //----------------------------------------------------------------------------
  1406. DWORD
  1407. APIENTRY
  1408. MibGetNext(
  1409. IN DWORD dwInputSize,
  1410. IN PVOID pInputData,
  1411. IN OUT PDWORD pdwOutputSize,
  1412. OUT PVOID pOutputData
  1413. ) {
  1414. DWORD dwErr, dwOutSize = 0, dwBufSize = 0;
  1415. PIPRIP_MIB_GET_INPUT_DATA pimgid;
  1416. PIPRIP_MIB_GET_OUTPUT_DATA pimgod;
  1417. if (!ENTER_RIP_API()) { return ERROR_CAN_NOT_COMPLETE; }
  1418. TRACE4(
  1419. ENTER, "entering MibGetNext: %d 0x%08x 0x%08x 0x%08x",
  1420. dwInputSize, pInputData, pdwOutputSize, pOutputData
  1421. );
  1422. if (pInputData == NULL ||
  1423. dwInputSize < sizeof(IPRIP_MIB_GET_INPUT_DATA) ||
  1424. pdwOutputSize == NULL) {
  1425. dwErr = ERROR_INVALID_PARAMETER;
  1426. }
  1427. else {
  1428. pimgid = (PIPRIP_MIB_GET_INPUT_DATA)pInputData;
  1429. pimgod = (PIPRIP_MIB_GET_OUTPUT_DATA)pOutputData;
  1430. dwOutSize = *pdwOutputSize;
  1431. dwErr = MibGetInternal(pimgid, pimgod, pdwOutputSize, GETMODE_NEXT);
  1432. if (dwErr == ERROR_NO_MORE_ITEMS) {
  1433. //
  1434. // need to wrap to the first entry in the next table,
  1435. // if there is a next table
  1436. //
  1437. TRACE1(
  1438. CONFIG, "MibGetNext is wrapping to table %d",
  1439. pimgid->IMGID_TypeID + 1
  1440. );
  1441. *pdwOutputSize = dwOutSize;
  1442. //
  1443. // wrap to next table by incrementing the type ID
  1444. //
  1445. ++pimgid->IMGID_TypeID;
  1446. if (pimgid->IMGID_TypeID <= IPRIP_PEER_STATS_ID) {
  1447. dwErr = MibGetInternal(
  1448. pimgid, pimgod, pdwOutputSize, GETMODE_FIRST
  1449. );
  1450. }
  1451. --pimgid->IMGID_TypeID;
  1452. }
  1453. }
  1454. TRACE1(LEAVE, "leaving MibGetNext: %d", dwErr);
  1455. LEAVE_RIP_API();
  1456. return dwErr;
  1457. }
  1458. //----------------------------------------------------------------------------
  1459. // Function: MibGetInternal
  1460. //
  1461. // This handles the actual structure access required to read MIB data.
  1462. // Each table supported by IPRIP supports three modes of querying;
  1463. // EXACT, FIRST, and NEXT, which correspond to the functions MibGet(),
  1464. // MibGetFirst(), and MibGetNext() respectively.
  1465. //----------------------------------------------------------------------------
  1466. DWORD
  1467. MibGetInternal(
  1468. PIPRIP_MIB_GET_INPUT_DATA pimgid,
  1469. PIPRIP_MIB_GET_OUTPUT_DATA pimgod,
  1470. PDWORD pdwOutputSize,
  1471. DWORD dwGetMode
  1472. ) {
  1473. DWORD dwErr, dwBufferSize, dwSize;
  1474. ULONG ulVersion, ulSize, ulCount;
  1475. dwErr = NO_ERROR;
  1476. //
  1477. // first we use pdwOutputSize to compute the size of the buffer
  1478. // available for storing returned structures (the size of IMGOD_Buffer)
  1479. //
  1480. if (pimgod == NULL) {
  1481. dwBufferSize = 0;
  1482. }
  1483. else {
  1484. if (*pdwOutputSize < sizeof(IPRIP_MIB_GET_OUTPUT_DATA)) {
  1485. dwBufferSize = 0;
  1486. }
  1487. else {
  1488. dwBufferSize = *pdwOutputSize - sizeof(IPRIP_MIB_GET_OUTPUT_DATA) + 1;
  1489. }
  1490. }
  1491. *pdwOutputSize = 0;
  1492. //
  1493. // determine which type of data is to be returned
  1494. //
  1495. switch (pimgid->IMGID_TypeID) {
  1496. case IPRIP_GLOBAL_STATS_ID: {
  1497. //
  1498. // the global stats structure is constant size.
  1499. // there is only one instance, so if the mode is GETMODE_NEXT
  1500. // we always return ERROR_NO_MORE_ITEMS
  1501. //
  1502. PIPRIP_GLOBAL_STATS pigsdst, pigssrc;
  1503. //
  1504. // set the output size required for this entry,
  1505. // as well as the type of data to be returned
  1506. //
  1507. *pdwOutputSize = sizeof(IPRIP_MIB_GET_OUTPUT_DATA) - 1 +
  1508. sizeof(IPRIP_GLOBAL_STATS);
  1509. if (pimgod) { pimgod->IMGOD_TypeID = IPRIP_GLOBAL_STATS_ID; }
  1510. //
  1511. // only GETMODE_EXACT and GETMODE_FIRST are valid for
  1512. // the global stats object, since there is only one entry
  1513. //
  1514. if (dwGetMode == GETMODE_NEXT) {
  1515. dwErr = ERROR_NO_MORE_ITEMS;
  1516. break;
  1517. }
  1518. if (pimgod == NULL) { dwErr = ERROR_INSUFFICIENT_BUFFER; break; }
  1519. //
  1520. // check that the output buffer is big enough
  1521. //
  1522. if (dwBufferSize < sizeof(IPRIP_GLOBAL_STATS)) {
  1523. dwErr = ERROR_INSUFFICIENT_BUFFER;
  1524. }
  1525. else {
  1526. //
  1527. // since access to this structure is not synchronized,
  1528. // we must copy it field by field
  1529. //
  1530. pigssrc = &ig.IG_Stats;
  1531. pigsdst = (PIPRIP_GLOBAL_STATS)pimgod->IMGOD_Buffer;
  1532. pigsdst->GS_SystemRouteChanges = pigssrc->GS_SystemRouteChanges;
  1533. pigsdst->GS_TotalResponsesSent = pigssrc->GS_TotalResponsesSent;
  1534. }
  1535. break;
  1536. }
  1537. case IPRIP_GLOBAL_CONFIG_ID: {
  1538. //
  1539. // the global config struct is variable length,
  1540. // so we wait until it has been retrieved
  1541. // before we set the size.
  1542. // furthermore, there is only one global config object,
  1543. // so GETMODE_NEXT doesn't make any sense
  1544. //
  1545. if (pimgod) { pimgod->IMGOD_TypeID = IPRIP_GLOBAL_CONFIG_ID; }
  1546. if (dwGetMode == GETMODE_NEXT) {
  1547. dwErr = ERROR_NO_MORE_ITEMS;
  1548. break;
  1549. }
  1550. //
  1551. // Use GetGlobalInfo to retrieve the global information.
  1552. // It will decide whether the buffer is large enough,
  1553. // and if not will set the required size. Then all we need do
  1554. // is write out the size set by GetGlobalInfo() and
  1555. // relay its return-value to the caller
  1556. //
  1557. if (pimgod == NULL) {
  1558. dwErr = GetGlobalInfo(NULL, &dwBufferSize, &ulVersion, &ulSize, &ulCount);
  1559. }
  1560. else {
  1561. dwErr = GetGlobalInfo(
  1562. pimgod->IMGOD_Buffer, &dwBufferSize, &ulVersion, &ulSize, &ulCount
  1563. );
  1564. }
  1565. *pdwOutputSize = sizeof(IPRIP_MIB_GET_OUTPUT_DATA) - 1 +
  1566. dwBufferSize;
  1567. break;
  1568. }
  1569. case IPRIP_IF_STATS_ID: {
  1570. //
  1571. // the interface statistics struct is fixed-length.
  1572. // there may be multiple instances.
  1573. //
  1574. PIF_TABLE pTable;
  1575. PIF_TABLE_ENTRY pite;
  1576. PIPRIP_IF_STATS pissrc, pisdst;
  1577. //
  1578. // set the size needed right away
  1579. //
  1580. *pdwOutputSize = sizeof(IPRIP_MIB_GET_OUTPUT_DATA) - 1 +
  1581. sizeof(IPRIP_IF_STATS);
  1582. if (pimgod) { pimgod->IMGOD_TypeID = IPRIP_IF_STATS_ID; }
  1583. pTable = ig.IG_IfTable;
  1584. ACQUIRE_IF_LOCK_SHARED();
  1585. //
  1586. // retrieve the interface whose stats are to be read
  1587. //
  1588. pite = GetIfByListIndex(
  1589. pTable, pimgid->IMGID_IfIndex, dwGetMode, &dwErr
  1590. );
  1591. //
  1592. // if the interface was not found, it may mean
  1593. // the specified index was invalid, or it may mean
  1594. // that the GETMODE_NEXT was called on the last interface
  1595. // in which case ERROR_NO_MORE_ITEMS was returned.
  1596. // In any case, we make sure dwErr indicates an error
  1597. // and then return the value.
  1598. //
  1599. // if the interface was found but no output buffer was passed,
  1600. // indicate in the error that memory needs to be allocated.
  1601. //
  1602. // otherwise, copy the stats struct of the interface
  1603. //
  1604. if (pite == NULL) {
  1605. if (dwErr == NO_ERROR) { dwErr = ERROR_NOT_FOUND; }
  1606. }
  1607. else
  1608. if (pimgod == NULL) {
  1609. dwErr = ERROR_INSUFFICIENT_BUFFER;
  1610. }
  1611. else {
  1612. //
  1613. // set the index of the interface returned
  1614. //
  1615. pimgod->IMGOD_IfIndex = pite->ITE_Index;
  1616. //
  1617. // if the buffer is large enough, copy over the stats
  1618. //
  1619. if (dwBufferSize < sizeof(IPRIP_IF_STATS)) {
  1620. dwErr = ERROR_INSUFFICIENT_BUFFER;
  1621. }
  1622. else {
  1623. //
  1624. // since access to this structure is not synchronized,
  1625. // we must copy it field by field
  1626. //
  1627. pissrc = &pite->ITE_Stats;
  1628. pisdst = (PIPRIP_IF_STATS)pimgod->IMGOD_Buffer;
  1629. pisdst->IS_State = 0;
  1630. if (IF_IS_ENABLED(pite)) {
  1631. pisdst->IS_State |= IPRIP_STATE_ENABLED;
  1632. }
  1633. if (IF_IS_BOUND(pite)) {
  1634. pisdst->IS_State |= IPRIP_STATE_BOUND;
  1635. }
  1636. pisdst->IS_SendFailures =
  1637. pissrc->IS_SendFailures;
  1638. pisdst->IS_ReceiveFailures =
  1639. pissrc->IS_ReceiveFailures;
  1640. pisdst->IS_RequestsSent =
  1641. pissrc->IS_RequestsSent;
  1642. pisdst->IS_RequestsReceived =
  1643. pissrc->IS_RequestsReceived;
  1644. pisdst->IS_ResponsesSent =
  1645. pissrc->IS_ResponsesSent;
  1646. pisdst->IS_RequestsReceived =
  1647. pissrc->IS_RequestsReceived;
  1648. pisdst->IS_ResponsesReceived =
  1649. pissrc->IS_ResponsesReceived;
  1650. pisdst->IS_BadResponsePacketsReceived =
  1651. pissrc->IS_BadResponsePacketsReceived;
  1652. pisdst->IS_BadResponseEntriesReceived =
  1653. pissrc->IS_BadResponseEntriesReceived;
  1654. pisdst->IS_TriggeredUpdatesSent =
  1655. pissrc->IS_TriggeredUpdatesSent;
  1656. }
  1657. }
  1658. RELEASE_IF_LOCK_SHARED();
  1659. break;
  1660. }
  1661. case IPRIP_IF_CONFIG_ID: {
  1662. //
  1663. // the interface configuration is variable-length.
  1664. // thus we must actually retrieve the requested interface
  1665. // before we know how large a buffer is needed.
  1666. //
  1667. PIF_TABLE pTable;
  1668. PIF_TABLE_ENTRY pite;
  1669. PIPRIP_IF_CONFIG picsrc, picdst;
  1670. if (pimgod) { pimgod->IMGOD_TypeID = IPRIP_IF_CONFIG_ID; }
  1671. pTable = ig.IG_IfTable;
  1672. ACQUIRE_IF_LOCK_SHARED();
  1673. //
  1674. // retrieve the interface whose config is to be read
  1675. //
  1676. pite = GetIfByListIndex(
  1677. pTable, pimgid->IMGID_IfIndex, dwGetMode, &dwErr
  1678. );
  1679. //
  1680. // if the interface was found, it may mean that the index
  1681. // specified was invalid, or it may mean that a GETMODE_NEXT
  1682. // retrieval was attempted on the last interface, in which case
  1683. // ERROR_NO_MORE_ITEMS would have been returned.
  1684. //
  1685. if (pite == NULL) {
  1686. if (dwErr == NO_ERROR) { dwErr = ERROR_NOT_FOUND; }
  1687. }
  1688. else {
  1689. //
  1690. // compute the size of the interface config retrieved,
  1691. // and write it over the caller's supplied size
  1692. //
  1693. picsrc = pite->ITE_Config;
  1694. dwSize = IPRIP_IF_CONFIG_SIZE(picsrc);
  1695. *pdwOutputSize = sizeof(IPRIP_MIB_GET_OUTPUT_DATA) - 1 +
  1696. dwSize;
  1697. //
  1698. // if no buffer was specified, indicate one should be allocated
  1699. //
  1700. if (pimgod == NULL) {
  1701. dwErr = ERROR_INSUFFICIENT_BUFFER;
  1702. }
  1703. else {
  1704. //
  1705. // if the buffer is not large enough,
  1706. // indicate that it should be enlarged
  1707. //
  1708. if (dwBufferSize < dwSize) {
  1709. dwErr = ERROR_INSUFFICIENT_BUFFER;
  1710. }
  1711. else {
  1712. //
  1713. // copy the configuration
  1714. //
  1715. picdst = (PIPRIP_IF_CONFIG)pimgod->IMGOD_Buffer;
  1716. CopyMemory(picdst, picsrc, dwSize);
  1717. ZeroMemory(
  1718. picdst->IC_AuthenticationKey, IPRIP_MAX_AUTHKEY_SIZE
  1719. );
  1720. picdst->IC_State = 0;
  1721. if (IF_IS_ENABLED(pite)) {
  1722. picdst->IC_State |= IPRIP_STATE_ENABLED;
  1723. }
  1724. if (IF_IS_BOUND(pite)) {
  1725. picdst->IC_State |= IPRIP_STATE_BOUND;
  1726. }
  1727. }
  1728. pimgod->IMGOD_IfIndex = pite->ITE_Index;
  1729. }
  1730. }
  1731. RELEASE_IF_LOCK_SHARED();
  1732. break;
  1733. }
  1734. case IPRIP_IF_BINDING_ID: {
  1735. //
  1736. // the interface binding is variable-length
  1737. // thus we must actually retrieve the requested interface
  1738. // before we know how large a buffer is needed.
  1739. //
  1740. PIF_TABLE pTable;
  1741. PIF_TABLE_ENTRY pite;
  1742. PIPRIP_IF_BINDING pibsrc, pibdst;
  1743. if (pimgod) { pimgod->IMGOD_TypeID = IPRIP_IF_BINDING_ID; }
  1744. pTable = ig.IG_IfTable;
  1745. ACQUIRE_IF_LOCK_SHARED();
  1746. //
  1747. // retrieve the interface whose binding is to be read
  1748. //
  1749. pite = GetIfByListIndex(
  1750. pTable, pimgid->IMGID_IfIndex, dwGetMode, &dwErr
  1751. );
  1752. //
  1753. // if the interface was found, it may mean that the index
  1754. // specified was invalid, or it may mean that a GETMODE_NEXT
  1755. // retrieval was attempted on the last interface, in which case
  1756. // ERROR_NO_MORE_ITEMS would have been returned.
  1757. //
  1758. if (pite == NULL) {
  1759. if (dwErr == NO_ERROR) { dwErr = ERROR_NOT_FOUND; }
  1760. }
  1761. else {
  1762. //
  1763. // compute the size of the interface binding retrieved,
  1764. // and write it over the caller's supplied size
  1765. //
  1766. pibsrc = pite->ITE_Binding;
  1767. dwSize = (pibsrc ? IPRIP_IF_BINDING_SIZE(pibsrc)
  1768. : sizeof(IPRIP_IF_BINDING));
  1769. *pdwOutputSize = sizeof(IPRIP_MIB_GET_OUTPUT_DATA) - 1 +
  1770. dwSize;
  1771. //
  1772. // if no buffer was specified, indicate one should be allocated
  1773. //
  1774. if (pimgod == NULL) {
  1775. dwErr = ERROR_INSUFFICIENT_BUFFER;
  1776. }
  1777. else {
  1778. //
  1779. // if the buffer is not large enough,
  1780. // indicate that it should be enlarged
  1781. //
  1782. if (dwBufferSize < dwSize) {
  1783. dwErr = ERROR_INSUFFICIENT_BUFFER;
  1784. }
  1785. else {
  1786. //
  1787. // copy the binding
  1788. //
  1789. pibdst = (PIPRIP_IF_BINDING)pimgod->IMGOD_Buffer;
  1790. if (pibsrc) { CopyMemory(pibdst, pibsrc, dwSize); }
  1791. else { pibdst->IB_AddrCount = 0; }
  1792. pibdst->IB_State = 0;
  1793. if (IF_IS_ENABLED(pite)) {
  1794. pibdst->IB_State |= IPRIP_STATE_ENABLED;
  1795. }
  1796. if (IF_IS_BOUND(pite)) {
  1797. pibdst->IB_State |= IPRIP_STATE_BOUND;
  1798. }
  1799. }
  1800. pimgod->IMGOD_IfIndex = pite->ITE_Index;
  1801. }
  1802. }
  1803. RELEASE_IF_LOCK_SHARED();
  1804. break;
  1805. }
  1806. case IPRIP_PEER_STATS_ID: {
  1807. //
  1808. // the peer statistics struct is fixed-length.
  1809. //
  1810. DWORD dwAddress;
  1811. PPEER_TABLE pTable;
  1812. PPEER_TABLE_ENTRY ppte;
  1813. PIPRIP_PEER_STATS ppssrc, ppsdst;
  1814. //
  1815. // set the output size right away
  1816. //
  1817. *pdwOutputSize = sizeof(IPRIP_MIB_GET_OUTPUT_DATA) - 1 +
  1818. sizeof(IPRIP_PEER_STATS);
  1819. if (pimgod) { pimgod->IMGOD_TypeID = IPRIP_PEER_STATS_ID; }
  1820. pTable = ig.IG_PeerTable;
  1821. dwAddress = pimgid->IMGID_PeerAddress;
  1822. ACQUIRE_PEER_LOCK_SHARED();
  1823. //
  1824. // retrieve the peer specified
  1825. //
  1826. ppte = GetPeerByAddress(pTable, dwAddress, dwGetMode, &dwErr);
  1827. //
  1828. // if no struct was returned, it means that either
  1829. // an invalid address was specifed, or GETMODE_NExT
  1830. // was attempted on the last peer.
  1831. // In either case, we return an error code.
  1832. //
  1833. // if no buffer was specifed, return ERROR_INSUFFICIENT_BUFFER
  1834. // to indicate to the caller that a buffer should be allocated
  1835. //
  1836. if (ppte == NULL) {
  1837. if (dwErr == NO_ERROR) { dwErr = ERROR_NOT_FOUND; }
  1838. }
  1839. else
  1840. if (pimgod == NULL) {
  1841. dwErr = ERROR_INSUFFICIENT_BUFFER;
  1842. }
  1843. else {
  1844. //
  1845. // save the address of the peer retrieved
  1846. //
  1847. pimgod->IMGOD_PeerAddress = ppte->PTE_Address;
  1848. //
  1849. // if the buffer is not large enough,
  1850. // return an error to indicate it should be enlarged
  1851. //
  1852. if (dwBufferSize < sizeof(IPRIP_PEER_STATS)) {
  1853. dwErr = ERROR_INSUFFICIENT_BUFFER;
  1854. }
  1855. else {
  1856. //
  1857. // since access to this structure is not synchronized,
  1858. // we must copy it field by field
  1859. //
  1860. ppssrc = &ppte->PTE_Stats;
  1861. ppsdst = (PIPRIP_PEER_STATS)pimgod->IMGOD_Buffer;
  1862. ppsdst->PS_LastPeerRouteTag =
  1863. ppssrc->PS_LastPeerRouteTag;
  1864. ppsdst->PS_LastPeerUpdateTickCount =
  1865. ppssrc->PS_LastPeerUpdateTickCount;
  1866. ppsdst->PS_LastPeerUpdateVersion =
  1867. ppssrc->PS_LastPeerUpdateVersion;
  1868. ppsdst->PS_BadResponsePacketsFromPeer =
  1869. ppssrc->PS_BadResponsePacketsFromPeer;
  1870. ppsdst->PS_BadResponseEntriesFromPeer =
  1871. ppssrc->PS_BadResponseEntriesFromPeer;
  1872. }
  1873. }
  1874. RELEASE_PEER_LOCK_SHARED();
  1875. break;
  1876. }
  1877. default: {
  1878. dwErr = ERROR_INVALID_PARAMETER;
  1879. }
  1880. }
  1881. return dwErr;
  1882. }