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.

2435 lines
55 KiB

  1. //============================================================================
  2. // Copyright (c) 1995, Microsoft Corporation
  3. //
  4. // File: api.c
  5. //
  6. // History:
  7. // Abolade Gbadegesin August 31, 1995 Created
  8. //
  9. // BOOTP Relay Agent's interface to Router Manager
  10. //============================================================================
  11. #include "pchbootp.h"
  12. IPBOOTP_GLOBALS ig;
  13. DWORD
  14. MibGetInternal(
  15. PIPBOOTP_MIB_GET_INPUT_DATA pimgid,
  16. PIPBOOTP_MIB_GET_OUTPUT_DATA pimgod,
  17. PDWORD pdwOutputSize,
  18. DWORD dwGetMode
  19. );
  20. BOOL
  21. DllStartup(
  22. );
  23. BOOL
  24. DllCleanup(
  25. );
  26. DWORD
  27. ProtocolStartup(
  28. HANDLE hEventEvent,
  29. PSUPPORT_FUNCTIONS pFunctionTable,
  30. PVOID pConfig
  31. );
  32. DWORD
  33. ProtocolCleanup(
  34. BOOL bCleanupWinsock
  35. );
  36. DWORD
  37. BindInterface(
  38. IN DWORD dwIndex,
  39. IN PVOID pBinding
  40. );
  41. DWORD
  42. UnBindInterface(
  43. IN DWORD dwIndex
  44. );
  45. DWORD
  46. EnableInterface(
  47. IN DWORD dwIndex
  48. );
  49. DWORD
  50. DisableInterface(
  51. IN DWORD dwIndex
  52. );
  53. //----------------------------------------------------------------------------
  54. // Function: DLLMAIN
  55. //
  56. // This is the entry-point for IPBOOTP.DLL.
  57. //----------------------------------------------------------------------------
  58. BOOL
  59. WINAPI
  60. DLLMAIN(
  61. HINSTANCE hInstance,
  62. DWORD dwReason,
  63. PVOID pUnused
  64. ) {
  65. BOOL bErr;
  66. bErr = FALSE;
  67. switch(dwReason) {
  68. case DLL_PROCESS_ATTACH:
  69. DisableThreadLibraryCalls(hInstance);
  70. bErr = DllStartup();
  71. break;
  72. case DLL_PROCESS_DETACH:
  73. bErr = DllCleanup();
  74. break;
  75. default:
  76. bErr = TRUE;
  77. break;
  78. }
  79. return bErr;
  80. }
  81. //----------------------------------------------------------------------------
  82. // Function: DllStartup
  83. //
  84. // This function initializes IPBOOTP's global structure
  85. // in preparation for calls to the API functions exported.
  86. // It creates the global critical section, heap, and router-manager
  87. // event message queue.
  88. //----------------------------------------------------------------------------
  89. BOOL
  90. DllStartup(
  91. ) {
  92. BOOL bErr;
  93. DWORD dwErr;
  94. bErr = FALSE;
  95. do {
  96. ZeroMemory(&ig, sizeof(IPBOOTP_GLOBALS));
  97. try {
  98. InitializeCriticalSection(&ig.IG_CS);
  99. }
  100. except (EXCEPTION_EXECUTE_HANDLER) {
  101. dwErr = GetExceptionCode();
  102. break;
  103. }
  104. ig.IG_Status = IPBOOTP_STATUS_STOPPED;
  105. //
  106. // create the global heap for BOOTP
  107. //
  108. ig.IG_GlobalHeap = HeapCreate(0, 0, 0);
  109. if (ig.IG_GlobalHeap == NULL) {
  110. dwErr = GetLastError();
  111. break;
  112. }
  113. //
  114. // allocate space for the Router manager event queue
  115. //
  116. ig.IG_EventQueue = BOOTP_ALLOC(sizeof(LOCKED_LIST));
  117. if (ig.IG_EventQueue == NULL) {
  118. dwErr = GetLastError();
  119. break;
  120. }
  121. //
  122. // now initialize the locked-list allocated
  123. //
  124. try {
  125. CREATE_LOCKED_LIST(ig.IG_EventQueue);
  126. }
  127. except(EXCEPTION_EXECUTE_HANDLER) {
  128. dwErr = GetExceptionCode();
  129. break;
  130. }
  131. bErr = TRUE;
  132. } while(FALSE);
  133. if (!bErr) {
  134. DllCleanup();
  135. }
  136. return bErr;
  137. }
  138. //----------------------------------------------------------------------------
  139. // Function: DllCleanup
  140. //
  141. // This function is called when the IPBOOTP DLL is being unloaded.
  142. // It releases the resources allocated in DllStartup.
  143. //----------------------------------------------------------------------------
  144. BOOL
  145. DllCleanup(
  146. ) {
  147. BOOL bErr;
  148. bErr = TRUE;
  149. do {
  150. //
  151. // delete and deallocate the event message queue
  152. //
  153. if (ig.IG_EventQueue != NULL) {
  154. if (LOCKED_LIST_CREATED(ig.IG_EventQueue)) {
  155. DELETE_LOCKED_LIST(ig.IG_EventQueue);
  156. }
  157. BOOTP_FREE(ig.IG_EventQueue);
  158. }
  159. //
  160. // destroy the global heap
  161. //
  162. if (ig.IG_GlobalHeap != NULL) {
  163. HeapDestroy(ig.IG_GlobalHeap);
  164. }
  165. //
  166. // delete the global critical section
  167. //
  168. DeleteCriticalSection(&ig.IG_CS);
  169. if (ig.IG_LoggingHandle != NULL)
  170. RouterLogDeregister(ig.IG_LoggingHandle);
  171. if (ig.IG_TraceID != INVALID_TRACEID) {
  172. TraceDeregister(ig.IG_TraceID);
  173. }
  174. } while(FALSE);
  175. return bErr;
  176. }
  177. //----------------------------------------------------------------------------
  178. // Function: ProtocolStartup
  179. //
  180. // This function is called by the router manager to start IPBOOTP.
  181. // It sets up the data structures needed and starts the input thread.
  182. //----------------------------------------------------------------------------
  183. DWORD
  184. ProtocolStartup(
  185. HANDLE hEventEvent,
  186. PSUPPORT_FUNCTIONS pFunctionTable,
  187. PVOID pConfig
  188. ) {
  189. WSADATA wd;
  190. HANDLE hThread;
  191. BOOL bCleanupWinsock;
  192. DWORD dwErr, dwSize, dwThread;
  193. PIPBOOTP_GLOBAL_CONFIG pgcsrc, pgcdst;
  194. ig.IG_TraceID = TraceRegister("IPBOOTP");
  195. ig.IG_LoggingHandle = RouterLogRegister("IPBOOTP");
  196. //
  197. // acquire the global critical section
  198. // while we look at the status code
  199. //
  200. EnterCriticalSection(&ig.IG_CS);
  201. //
  202. // make sure that BOOTP has not already started up
  203. //
  204. if (ig.IG_Status != IPBOOTP_STATUS_STOPPED) {
  205. TRACE0(START, "StartProtocol() has already been called");
  206. LOGWARN0(ALREADY_STARTED, 0);
  207. LeaveCriticalSection(&ig.IG_CS);
  208. return ERROR_CAN_NOT_COMPLETE;
  209. }
  210. //
  211. // initialize the global structures:
  212. //
  213. bCleanupWinsock = FALSE;
  214. do { // error break-out loop
  215. TRACE0(START, "IPBOOTP is starting up...");
  216. //
  217. // copy the global configuration passed in:
  218. // find its size, and the allocate space for the copy
  219. //
  220. pgcsrc = (PIPBOOTP_GLOBAL_CONFIG)pConfig;
  221. dwSize = GC_SIZEOF(pgcsrc);
  222. pgcdst = BOOTP_ALLOC(dwSize);
  223. if (pgcdst == NULL) {
  224. dwErr = GetLastError();
  225. TRACE2(
  226. START, "error %d allocating %d bytes for global config",
  227. dwErr, dwSize
  228. );
  229. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  230. break;
  231. }
  232. RtlCopyMemory(pgcdst, pgcsrc, dwSize);
  233. ig.IG_Config = pgcdst;
  234. ig.IG_LoggingLevel = pgcdst->GC_LoggingLevel;
  235. //
  236. // initialize Windows Sockets
  237. //
  238. dwErr = (DWORD)WSAStartup(MAKEWORD(1,1), &wd);
  239. if (dwErr != NO_ERROR) {
  240. TRACE1(START, "error %d initializing Windows Sockets", dwErr);
  241. LOGERR0(INIT_WINSOCK_FAILED, dwErr);
  242. break;
  243. }
  244. bCleanupWinsock = TRUE;
  245. //
  246. // create the global structure lock
  247. //
  248. try {
  249. CREATE_READ_WRITE_LOCK(&ig.IG_RWL);
  250. }
  251. except (EXCEPTION_EXECUTE_HANDLER) {
  252. dwErr = GetExceptionCode();
  253. TRACE1(START, "error %d creating synchronization object", dwErr);
  254. LOGERR0(CREATE_RWL_FAILED, dwErr);
  255. break;
  256. }
  257. //
  258. // initialize the interface table
  259. //
  260. ig.IG_IfTable = BOOTP_ALLOC(sizeof(IF_TABLE));
  261. if (ig.IG_IfTable == NULL) {
  262. dwErr = GetLastError();
  263. TRACE2(
  264. START, "error %d allocating %d bytes for interface table",
  265. dwErr, sizeof(IF_TABLE)
  266. );
  267. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  268. break;
  269. }
  270. //
  271. // initialize the interface table
  272. //
  273. dwErr = CreateIfTable(ig.IG_IfTable);
  274. if (dwErr != NO_ERROR) {
  275. TRACE1(START, "error %d initializing interface table", dwErr);
  276. LOGERR0(CREATE_IF_TABLE_FAILED, dwErr);
  277. break;
  278. }
  279. //
  280. // allocate the receive queue
  281. //
  282. ig.IG_RecvQueue = BOOTP_ALLOC(sizeof(LOCKED_LIST));
  283. if (ig.IG_RecvQueue == NULL) {
  284. dwErr = GetLastError();
  285. TRACE2(
  286. START, "error %d allocating %d bytes for receive queue",
  287. dwErr, sizeof(LOCKED_LIST)
  288. );
  289. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  290. break;
  291. }
  292. //
  293. // initialize the receive queue
  294. //
  295. try {
  296. CREATE_LOCKED_LIST(ig.IG_RecvQueue);
  297. }
  298. except (EXCEPTION_EXECUTE_HANDLER) {
  299. dwErr = GetExceptionCode();
  300. TRACE1(START, "exception %d initializing locked list", dwErr);
  301. LOGERR0(INIT_CRITSEC_FAILED, dwErr);
  302. break;
  303. }
  304. //
  305. // copy the support-function table and Router Manager event
  306. //
  307. ig.IG_FunctionTable = pFunctionTable;
  308. ig.IG_EventEvent = hEventEvent;
  309. //
  310. // initialize count of active threads, and create the semaphore
  311. // signalled by threads exiting API functions and work functions
  312. //
  313. ig.IG_ActivityCount = 0;
  314. ig.IG_ActivitySemaphore = CreateSemaphore(NULL, 0, 0xfffffff, NULL);
  315. if (ig.IG_ActivitySemaphore == NULL) {
  316. dwErr = GetLastError();
  317. TRACE1(START, "error %d creating semaphore", dwErr);
  318. LOGERR0(CREATE_SEMAPHORE_FAILED, dwErr);
  319. break;
  320. }
  321. //
  322. // create the event used to signal on incoming packets
  323. //
  324. ig.IG_InputEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  325. if (ig.IG_InputEvent == NULL) {
  326. dwErr = GetLastError();
  327. TRACE1(START, "error %d creating input-event", dwErr);
  328. LOGERR0(CREATE_EVENT_FAILED, dwErr);
  329. break;
  330. }
  331. //
  332. // register the InputEvent with the NtdllWait thread
  333. //
  334. if (! RegisterWaitForSingleObject(
  335. &ig.IG_InputEventHandle,
  336. ig.IG_InputEvent,
  337. CallbackFunctionNetworkEvents,
  338. NULL, //null context
  339. INFINITE, //no timeout
  340. (WT_EXECUTEINWAITTHREAD|WT_EXECUTEONLYONCE)
  341. )) {
  342. dwErr = GetLastError();
  343. TRACE1(
  344. START, "error %d returned by RegisterWaitForSingleObjectEx",
  345. dwErr
  346. );
  347. LOGERR0(REGISTER_WAIT_FAILED, dwErr);
  348. break;
  349. }
  350. //
  351. // now set the status to running
  352. //
  353. ig.IG_Status = IPBOOTP_STATUS_RUNNING;
  354. #if DBG
  355. //
  356. // register a timer queue with the NtdllTimer thread
  357. //
  358. ig.IG_TimerQueueHandle = CreateTimerQueue();
  359. if (!ig.IG_TimerQueueHandle) {
  360. dwErr = GetLastError();
  361. TRACE1(START, "error %d returned by CreateTimerQueue()", dwErr);
  362. LOGERR0(CREATE_TIMER_QUEUE_FAILED, dwErr);
  363. break;
  364. }
  365. //
  366. // set timer with NtdllTimer thread to display IPBOOTP MIB periodically
  367. //
  368. ig.IG_MibTraceID = TraceRegisterEx("IPBOOTPMIB", TRACE_USE_CONSOLE);
  369. if (ig.IG_MibTraceID != INVALID_TRACEID) {
  370. if (! CreateTimerQueueTimer(
  371. &ig.IG_MibTimerHandle,
  372. ig.IG_TimerQueueHandle,
  373. CallbackFunctionMibDisplay,
  374. NULL, // null context
  375. 10000, // display after 10 seconds
  376. 10000, // display every 10 seconds
  377. 0 // execute in timer thread
  378. )) {
  379. dwErr = GetLastError();
  380. TRACE1(
  381. START, "error %d returned by CreateTimerQueueTimer()",
  382. dwErr
  383. );
  384. break;
  385. }
  386. }
  387. #endif
  388. TRACE0(START, "IP BOOTP started successfully");
  389. LOGINFO0(STARTED, 0);
  390. LeaveCriticalSection(&ig.IG_CS);
  391. return NO_ERROR;
  392. } while(FALSE);
  393. //
  394. // an error occurred if control-flow brings us here
  395. //
  396. TRACE0(START, "IPRIP failed to start");
  397. ProtocolCleanup(bCleanupWinsock);
  398. LeaveCriticalSection(&ig.IG_CS);
  399. return (dwErr == NO_ERROR ? ERROR_CAN_NOT_COMPLETE : dwErr);
  400. }
  401. //----------------------------------------------------------------------------
  402. // Function: ProtocolCleanup
  403. //
  404. // This function cleans up resources used by IPBOOTP while it is
  405. // in operation. Essentially, everything created in ProtocolStartup
  406. // is cleaned up by the function.
  407. //----------------------------------------------------------------------------
  408. DWORD
  409. ProtocolCleanup(
  410. BOOL bCleanupWinsock
  411. ) {
  412. DWORD dwErr;
  413. //
  414. // lock things down while we clean up
  415. //
  416. EnterCriticalSection(&ig.IG_CS);
  417. #if DBG
  418. TraceDeregister(ig.IG_MibTraceID);
  419. #endif
  420. if (ig.IG_InputEvent != NULL) {
  421. CloseHandle(ig.IG_InputEvent);
  422. ig.IG_InputEvent = NULL;
  423. }
  424. if (ig.IG_ActivitySemaphore != NULL) {
  425. CloseHandle(ig.IG_ActivitySemaphore);
  426. ig.IG_ActivitySemaphore = NULL;
  427. }
  428. if (ig.IG_RecvQueue != NULL) {
  429. if (LOCKED_LIST_CREATED(ig.IG_RecvQueue)) {
  430. DELETE_LOCKED_LIST(ig.IG_RecvQueue);
  431. }
  432. BOOTP_FREE(ig.IG_RecvQueue);
  433. ig.IG_RecvQueue = NULL;
  434. }
  435. if (ig.IG_IfTable != NULL) {
  436. if (IF_TABLE_CREATED(ig.IG_IfTable)) {
  437. DeleteIfTable(ig.IG_IfTable);
  438. }
  439. BOOTP_FREE(ig.IG_IfTable);
  440. ig.IG_IfTable = NULL;
  441. }
  442. if (READ_WRITE_LOCK_CREATED(&ig.IG_RWL)) {
  443. try {
  444. DELETE_READ_WRITE_LOCK(&ig.IG_RWL);
  445. }
  446. except (EXCEPTION_EXECUTE_HANDLER) {
  447. dwErr = GetExceptionCode();
  448. }
  449. }
  450. if (bCleanupWinsock) {
  451. WSACleanup();
  452. }
  453. if (ig.IG_Config != NULL) {
  454. BOOTP_FREE(ig.IG_Config);
  455. ig.IG_Config = NULL;
  456. }
  457. ig.IG_Status = IPBOOTP_STATUS_STOPPED;
  458. LeaveCriticalSection(&ig.IG_CS);
  459. return NO_ERROR;
  460. }
  461. //----------------------------------------------------------------------------
  462. // Function: RegisterProtocol
  463. //
  464. // This function is called by the router manager
  465. // to retrieve information about IPBOOTP's capabilities
  466. //----------------------------------------------------------------------------
  467. DWORD
  468. APIENTRY
  469. RegisterProtocol(
  470. IN OUT PMPR_ROUTING_CHARACTERISTICS pRoutingChar,
  471. IN OUT PMPR_SERVICE_CHARACTERISTICS pServiceChar
  472. )
  473. {
  474. if(pRoutingChar->dwProtocolId != MS_IP_BOOTP)
  475. {
  476. return ERROR_NOT_SUPPORTED;
  477. }
  478. pServiceChar->fSupportedFunctionality = 0;
  479. if(!(pRoutingChar->fSupportedFunctionality & RF_ROUTING))
  480. {
  481. return ERROR_NOT_SUPPORTED;
  482. }
  483. pRoutingChar->fSupportedFunctionality = RF_ROUTING;
  484. pRoutingChar->pfnStartProtocol = StartProtocol;
  485. pRoutingChar->pfnStartComplete = StartComplete;
  486. pRoutingChar->pfnStopProtocol = StopProtocol;
  487. pRoutingChar->pfnGetGlobalInfo = GetGlobalInfo;
  488. pRoutingChar->pfnSetGlobalInfo = SetGlobalInfo;
  489. pRoutingChar->pfnQueryPower = NULL;
  490. pRoutingChar->pfnSetPower = NULL;
  491. pRoutingChar->pfnAddInterface = AddInterface;
  492. pRoutingChar->pfnDeleteInterface = DeleteInterface;
  493. pRoutingChar->pfnInterfaceStatus = InterfaceStatus;
  494. pRoutingChar->pfnGetInterfaceInfo = GetInterfaceConfigInfo;
  495. pRoutingChar->pfnSetInterfaceInfo = SetInterfaceConfigInfo;
  496. pRoutingChar->pfnGetEventMessage = GetEventMessage;
  497. pRoutingChar->pfnUpdateRoutes = NULL;
  498. pRoutingChar->pfnConnectClient = NULL;
  499. pRoutingChar->pfnDisconnectClient = NULL;
  500. pRoutingChar->pfnGetNeighbors = NULL;
  501. pRoutingChar->pfnGetMfeStatus = NULL;
  502. pRoutingChar->pfnMibCreateEntry = MibCreate;
  503. pRoutingChar->pfnMibDeleteEntry = MibDelete;
  504. pRoutingChar->pfnMibGetEntry = MibGet;
  505. pRoutingChar->pfnMibSetEntry = MibSet;
  506. pRoutingChar->pfnMibGetFirstEntry = MibGetFirst;
  507. pRoutingChar->pfnMibGetNextEntry = MibGetNext;
  508. return NO_ERROR;
  509. }
  510. //----------------------------------------------------------------------------
  511. // Function: StartProtocol
  512. //
  513. // This function is called by the router manager
  514. // to start IPBOOTP.
  515. //----------------------------------------------------------------------------
  516. DWORD
  517. WINAPI
  518. StartProtocol (
  519. HANDLE NotificationEvent,
  520. SUPPORT_FUNCTIONS *SupportFunctions,
  521. LPVOID GlobalInfo,
  522. ULONG StructureVersion,
  523. ULONG StructureSize,
  524. ULONG StructureCount
  525. )
  526. {
  527. return ProtocolStartup(NotificationEvent, SupportFunctions, GlobalInfo);
  528. }
  529. //----------------------------------------------------------------------------
  530. // Function: StartComplete
  531. //
  532. // This function is called by the router manager
  533. // to start IPBOOTP.
  534. //----------------------------------------------------------------------------
  535. DWORD
  536. WINAPI
  537. StartComplete (
  538. VOID
  539. )
  540. {
  541. return NO_ERROR;
  542. }
  543. //----------------------------------------------------------------------------
  544. // Function: StopProtocol
  545. //
  546. // This function notifies all active threads to stop, and frees resources
  547. // used by IP BOOTP
  548. //----------------------------------------------------------------------------
  549. DWORD
  550. APIENTRY
  551. StopProtocol(
  552. VOID
  553. ) {
  554. DWORD dwErr;
  555. LONG lThreadCount;
  556. HANDLE WaitHandle;
  557. //
  558. // make sure IPBOOTP has not already stopped
  559. //
  560. EnterCriticalSection(&ig.IG_CS);
  561. if (ig.IG_Status != IPBOOTP_STATUS_RUNNING) {
  562. LeaveCriticalSection(&ig.IG_CS);
  563. return ERROR_CAN_NOT_COMPLETE;
  564. }
  565. TRACE0(ENTER, "entering StopProtocol");
  566. //
  567. // update the status to prevent any APIs or worker-functions from running
  568. //
  569. ig.IG_Status = IPBOOTP_STATUS_STOPPING;
  570. //
  571. // see how many threads are already in API calls
  572. // or in worker-function code
  573. //
  574. lThreadCount = ig.IG_ActivityCount;
  575. TRACE1(STOP, "%d threads are active in IPBOOTP", lThreadCount);
  576. LeaveCriticalSection(&ig.IG_CS);
  577. //
  578. // wait for active threads to stop
  579. //
  580. while (lThreadCount-- > 0) {
  581. WaitForSingleObject(ig.IG_ActivitySemaphore, INFINITE);
  582. }
  583. //
  584. // deregister the mib timer from the Ntdll threads
  585. // This has to be done outside IG_CS lock.
  586. //
  587. #if DBG
  588. DeleteTimerQueueEx(ig.IG_TimerQueueHandle, INVALID_HANDLE_VALUE);
  589. #endif
  590. //
  591. // set the handle to NULL, so that Unregister wont be called
  592. //
  593. WaitHandle = InterlockedExchangePointer(&ig.IG_InputEventHandle, NULL);
  594. if (WaitHandle) {
  595. UnregisterWaitEx( WaitHandle, INVALID_HANDLE_VALUE ) ;
  596. }
  597. //
  598. // enter the critical section and leave,
  599. // to make certain all the threads have returned from LeaveBootpWorker
  600. //
  601. EnterCriticalSection(&ig.IG_CS);
  602. LeaveCriticalSection(&ig.IG_CS);
  603. //
  604. // now all threads have stopped
  605. //
  606. TRACE0(STOP, "all threads stopped, BOOTP is cleaning up resources");
  607. LOGINFO0(STOPPED, 0);
  608. ProtocolCleanup(TRUE);
  609. return NO_ERROR;
  610. }
  611. //----------------------------------------------------------------------------
  612. // Function: GetGlobalInfo
  613. //
  614. // Copies BOOTP's global config into the buffer provided.
  615. //----------------------------------------------------------------------------
  616. DWORD WINAPI
  617. GetGlobalInfo (
  618. PVOID OutGlobalInfo,
  619. PULONG GlobalInfoSize,
  620. PULONG StructureVersion,
  621. PULONG StructureSize,
  622. PULONG StructureCount
  623. )
  624. {
  625. DWORD dwErr = NO_ERROR, dwSize;
  626. if (!ENTER_BOOTP_API()) { return ERROR_CAN_NOT_COMPLETE; }
  627. TRACE2(ENTER, "entering GetGlobalInfo: 0x%08x 0x%08x", OutGlobalInfo, GlobalInfoSize);
  628. //
  629. // in order to do anything, we need a valid size pointer
  630. //
  631. if (GlobalInfoSize == NULL) {
  632. dwErr = ERROR_INVALID_PARAMETER;
  633. }
  634. else {
  635. //
  636. // check the size of the config block passed in
  637. // and copy the config if the buffer is large enough
  638. //
  639. ACQUIRE_READ_LOCK(&ig.IG_RWL);
  640. dwSize = GC_SIZEOF(ig.IG_Config);
  641. if (*GlobalInfoSize < dwSize) {
  642. dwErr = ERROR_INSUFFICIENT_BUFFER;
  643. }
  644. else
  645. if (OutGlobalInfo != NULL) {
  646. RtlCopyMemory(
  647. OutGlobalInfo,
  648. ig.IG_Config,
  649. dwSize
  650. );
  651. }
  652. *GlobalInfoSize = dwSize;
  653. if (StructureSize) *StructureSize = *GlobalInfoSize;
  654. if (StructureCount) *StructureCount = 1;
  655. if (StructureVersion) *StructureVersion = BOOTP_CONFIG_VERSION_500;
  656. RELEASE_READ_LOCK(&ig.IG_RWL);
  657. }
  658. TRACE1(LEAVE, "leaving GetGlobalInfo: %d", dwErr);
  659. LEAVE_BOOTP_API();
  660. return dwErr;
  661. }
  662. //----------------------------------------------------------------------------
  663. // Function: SetGlobalInfo
  664. //
  665. // Copies over the specified configuration .
  666. //----------------------------------------------------------------------------
  667. DWORD WINAPI
  668. SetGlobalInfo (
  669. PVOID GlobalInfo,
  670. ULONG StructureVersion,
  671. ULONG StructureSize,
  672. ULONG StructureCount
  673. )
  674. {
  675. DWORD dwErr, dwSize;
  676. PIPBOOTP_GLOBAL_CONFIG pgcsrc, pgcdst;
  677. if (!GlobalInfo || !ENTER_BOOTP_API()) { return ERROR_CAN_NOT_COMPLETE; }
  678. TRACE1(ENTER, "entering SetGlobalInfo: %p", GlobalInfo);
  679. ACQUIRE_WRITE_LOCK(&ig.IG_RWL);
  680. pgcsrc = (PIPBOOTP_GLOBAL_CONFIG)GlobalInfo;
  681. dwSize = GC_SIZEOF(pgcsrc);
  682. //
  683. // allocate memory for the new config block, and copy it over
  684. //
  685. pgcdst = BOOTP_ALLOC(dwSize);
  686. if (pgcdst == NULL) {
  687. dwErr = GetLastError();
  688. TRACE2(
  689. CONFIG, "error %d allocating %d bytes for global config",
  690. dwErr, dwSize
  691. );
  692. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  693. }
  694. else {
  695. RtlCopyMemory(
  696. pgcdst,
  697. pgcsrc,
  698. dwSize
  699. );
  700. BOOTP_FREE(ig.IG_Config);
  701. ig.IG_Config = pgcdst;
  702. dwErr = NO_ERROR;
  703. }
  704. RELEASE_WRITE_LOCK(&ig.IG_RWL);
  705. TRACE1(LEAVE, "leaving SetGlobalInfo: %d", dwErr);
  706. LEAVE_BOOTP_API();
  707. return dwErr;
  708. }
  709. //----------------------------------------------------------------------------
  710. // Function: AddInterface
  711. //
  712. // Adds an interface with the specified index and configuration.
  713. //----------------------------------------------------------------------------
  714. DWORD WINAPI
  715. AddInterface (
  716. PWCHAR pwszInterfaceName,
  717. ULONG InterfaceIndex,
  718. NET_INTERFACE_TYPE InterfaceType,
  719. DWORD MediaType,
  720. WORD AccessType,
  721. WORD ConnectionType,
  722. PVOID InterfaceInfo,
  723. ULONG StructureVersion,
  724. ULONG StructureSize,
  725. ULONG StructureCount
  726. )
  727. {
  728. DWORD dwErr;
  729. PIF_TABLE pTable;
  730. if (!ENTER_BOOTP_API()) { return ERROR_CAN_NOT_COMPLETE; }
  731. TRACE3(
  732. ENTER, "entering AddInterface: %d %d %p",
  733. InterfaceIndex, InterfaceType, InterfaceInfo
  734. );
  735. pTable = ig.IG_IfTable;
  736. ACQUIRE_WRITE_LOCK(&pTable->IT_RWL);
  737. dwErr = CreateIfEntry(pTable, InterfaceIndex, InterfaceInfo);
  738. RELEASE_WRITE_LOCK(&pTable->IT_RWL);
  739. TRACE1(LEAVE, "leaving AddInterface: %d", dwErr);
  740. LEAVE_BOOTP_API();
  741. return dwErr;
  742. }
  743. //----------------------------------------------------------------------------
  744. // Function: DeleteInterface
  745. //
  746. // Removes the interface with the specified index.
  747. //----------------------------------------------------------------------------
  748. DWORD
  749. APIENTRY
  750. DeleteInterface(
  751. IN DWORD dwIndex
  752. ) {
  753. DWORD dwErr;
  754. PIF_TABLE pTable;
  755. if (!ENTER_BOOTP_API()) { return ERROR_CAN_NOT_COMPLETE; }
  756. TRACE1(ENTER, "entering DeleteInterface: %d", dwIndex);
  757. pTable = ig.IG_IfTable;
  758. ACQUIRE_WRITE_LOCK(&pTable->IT_RWL);
  759. dwErr = DeleteIfEntry(pTable, dwIndex);
  760. RELEASE_WRITE_LOCK(&pTable->IT_RWL);
  761. TRACE1(LEAVE, "leaving DeleteInterface: %d", dwErr);
  762. LEAVE_BOOTP_API();
  763. return dwErr;
  764. }
  765. //----------------------------------------------------------------------------
  766. // Function: GetEventMessage
  767. //
  768. // Returns the first event in the ROuter Manager event queue, if any.
  769. //----------------------------------------------------------------------------
  770. DWORD
  771. APIENTRY
  772. GetEventMessage(
  773. OUT ROUTING_PROTOCOL_EVENTS *pEvent,
  774. OUT MESSAGE *pResult
  775. ) {
  776. DWORD dwErr;
  777. PLOCKED_LIST pll;
  778. if (!ENTER_BOOTP_API()) { return ERROR_CAN_NOT_COMPLETE; }
  779. TRACE2(ENTER, "entering GetEventMessage: 0x%08x 0x%08x", pEvent, pResult);
  780. pll = ig.IG_EventQueue;
  781. ACQUIRE_LIST_LOCK(pll);
  782. dwErr = DequeueEvent(pll, pEvent, pResult);
  783. RELEASE_LIST_LOCK(pll);
  784. TRACE1(LEAVE, "leaving GetEventMessage: %d", dwErr);
  785. LEAVE_BOOTP_API();
  786. return dwErr;
  787. }
  788. //----------------------------------------------------------------------------
  789. // Function: GetInterfaceConfigInfo
  790. //
  791. // Returns the configuration for the specified interface.
  792. //----------------------------------------------------------------------------
  793. DWORD WINAPI
  794. GetInterfaceConfigInfo (
  795. ULONG InterfaceIndex,
  796. PVOID OutInterfaceInfo,
  797. PULONG InterfaceInfoSize,
  798. PULONG StructureVersion,
  799. PULONG StructureSize,
  800. PULONG StructureCount
  801. )
  802. {
  803. PIF_TABLE pTable;
  804. DWORD dwErr, dwSize;
  805. PIF_TABLE_ENTRY pite;
  806. if (!ENTER_BOOTP_API()) { return ERROR_CAN_NOT_COMPLETE; }
  807. TRACE3(
  808. ENTER, "entering GetInterfaceConfigInfo: %d %p %p",
  809. InterfaceIndex, InterfaceInfoSize, OutInterfaceInfo
  810. );
  811. //
  812. // in order to do anything, we need a valid size pointer
  813. //
  814. if (InterfaceInfoSize == NULL) {
  815. dwErr = ERROR_INVALID_PARAMETER;
  816. }
  817. else {
  818. pTable = ig.IG_IfTable;
  819. ACQUIRE_READ_LOCK(&pTable->IT_RWL);
  820. //
  821. // retrieve the interface to be re-configured
  822. //
  823. pite = GetIfByIndex(pTable, InterfaceIndex);
  824. if (pite == NULL) {
  825. dwErr = ERROR_INVALID_PARAMETER;
  826. }
  827. else {
  828. //
  829. // compute the interface configuration's size,
  830. // and copy the config to the caller's buffer
  831. // if the caller's buffer is large enough
  832. //
  833. dwSize = IC_SIZEOF(pite->ITE_Config);
  834. if (*InterfaceInfoSize < dwSize || OutInterfaceInfo == NULL) {
  835. dwErr = ERROR_INSUFFICIENT_BUFFER;
  836. }
  837. else {
  838. PIPBOOTP_IF_CONFIG picdst = OutInterfaceInfo;
  839. CopyMemory(picdst, pite->ITE_Config, dwSize);
  840. picdst->IC_State = 0;
  841. if (IF_IS_ENABLED(pite)) {
  842. picdst->IC_State |= IPBOOTP_STATE_ENABLED;
  843. }
  844. if (IF_IS_BOUND(pite)) {
  845. picdst->IC_State |= IPBOOTP_STATE_BOUND;
  846. }
  847. dwErr = NO_ERROR;
  848. }
  849. *InterfaceInfoSize = dwSize;
  850. if (StructureSize) *StructureSize = *InterfaceInfoSize;
  851. if (StructureCount) *StructureCount = 1;
  852. if (StructureVersion) *StructureVersion = BOOTP_CONFIG_VERSION_500;
  853. }
  854. RELEASE_READ_LOCK(&pTable->IT_RWL);
  855. }
  856. TRACE1(LEAVE, "leaving GetInterfaceConfigInfo: %d", dwErr);
  857. LEAVE_BOOTP_API();
  858. return dwErr;
  859. }
  860. //----------------------------------------------------------------------------
  861. // Function: SetInterfaceConfigInfo
  862. //
  863. // Copies over the specified interface configuration.
  864. //----------------------------------------------------------------------------
  865. DWORD WINAPI
  866. SetInterfaceConfigInfo (
  867. ULONG InterfaceIndex,
  868. PVOID InterfaceInfo,
  869. ULONG StructureVersion,
  870. ULONG StructureSize,
  871. ULONG StructureCount
  872. )
  873. {
  874. PIF_TABLE pTable;
  875. DWORD dwErr, dwSize;
  876. PIF_TABLE_ENTRY pite;
  877. PIPBOOTP_IF_CONFIG picsrc, picdst;
  878. if (!ENTER_BOOTP_API()) { return ERROR_CAN_NOT_COMPLETE; }
  879. TRACE2(
  880. ENTER, "entering SetInterfaceConfigInfo: %d %p", InterfaceIndex, InterfaceInfo
  881. );
  882. pTable = ig.IG_IfTable;
  883. ACQUIRE_WRITE_LOCK(&pTable->IT_RWL);
  884. dwErr = ConfigureIfEntry(pTable, InterfaceIndex, InterfaceInfo);
  885. RELEASE_WRITE_LOCK(&pTable->IT_RWL);
  886. TRACE1(LEAVE, "leaving SetInterfaceConfigInfo: %d", dwErr);
  887. LEAVE_BOOTP_API();
  888. return dwErr;
  889. }
  890. DWORD WINAPI
  891. InterfaceStatus(
  892. ULONG InterfaceIndex,
  893. BOOL InterfaceActive,
  894. DWORD StatusType,
  895. PVOID StatusInfo
  896. )
  897. {
  898. DWORD dwResult;
  899. if (!ENTER_BOOTP_API()) { return ERROR_CAN_NOT_COMPLETE; }
  900. switch(StatusType)
  901. {
  902. case RIS_INTERFACE_ADDRESS_CHANGE:
  903. {
  904. PIP_ADAPTER_BINDING_INFO pBindInfo;
  905. pBindInfo = (PIP_ADAPTER_BINDING_INFO)StatusInfo;
  906. if(pBindInfo->AddressCount)
  907. {
  908. dwResult = BindInterface(InterfaceIndex,
  909. pBindInfo);
  910. }
  911. else
  912. {
  913. dwResult = UnBindInterface(InterfaceIndex);
  914. }
  915. break;
  916. }
  917. case RIS_INTERFACE_ENABLED:
  918. {
  919. dwResult = EnableInterface(InterfaceIndex);
  920. break;
  921. }
  922. case RIS_INTERFACE_DISABLED:
  923. {
  924. dwResult = DisableInterface(InterfaceIndex);
  925. break;
  926. }
  927. default:
  928. {
  929. RTASSERT(FALSE);
  930. dwResult = ERROR_INVALID_PARAMETER;
  931. }
  932. }
  933. LEAVE_BOOTP_API();
  934. return dwResult;
  935. }
  936. //----------------------------------------------------------------------------
  937. // Function: BindInterface
  938. //
  939. // Sets the IP address and network mask for the specified interface.
  940. //----------------------------------------------------------------------------
  941. DWORD
  942. APIENTRY
  943. BindInterface(
  944. IN DWORD dwIndex,
  945. IN PVOID pBinding
  946. ) {
  947. DWORD dwErr;
  948. PIF_TABLE pTable;
  949. TRACE2(ENTER, "entering BindInterface: %d 0x%08x", dwIndex, pBinding);
  950. pTable = ig.IG_IfTable;
  951. ACQUIRE_WRITE_LOCK(&pTable->IT_RWL);
  952. dwErr = BindIfEntry(pTable, dwIndex, pBinding);
  953. RELEASE_WRITE_LOCK(&pTable->IT_RWL);
  954. TRACE1(LEAVE, "leaving BindInterface: %d", dwErr);
  955. return dwErr;
  956. }
  957. //----------------------------------------------------------------------------
  958. // Function: UnBindInterface
  959. //
  960. // Removes the IP address associated with the specified interface
  961. //----------------------------------------------------------------------------
  962. DWORD
  963. APIENTRY
  964. UnBindInterface(
  965. IN DWORD dwIndex
  966. ) {
  967. DWORD dwErr;
  968. PIF_TABLE pTable;
  969. TRACE1(ENTER, "entering UnBindInterface: %d", dwIndex);
  970. pTable = ig.IG_IfTable;
  971. ACQUIRE_WRITE_LOCK(&pTable->IT_RWL);
  972. dwErr = UnBindIfEntry(pTable, dwIndex);
  973. RELEASE_WRITE_LOCK(&pTable->IT_RWL);
  974. TRACE1(LEAVE, "leaving UnBindInterface: %d", dwErr);
  975. return dwErr;
  976. }
  977. //----------------------------------------------------------------------------
  978. // Function: EnableInterface
  979. //
  980. //----------------------------------------------------------------------------
  981. DWORD
  982. APIENTRY
  983. EnableInterface(
  984. IN DWORD dwIndex
  985. ) {
  986. DWORD dwErr;
  987. PIF_TABLE pTable;
  988. TRACE1(ENTER, "entering EnableInterface: %d", dwIndex);
  989. pTable = ig.IG_IfTable;
  990. ACQUIRE_WRITE_LOCK(&pTable->IT_RWL);
  991. dwErr = EnableIfEntry(pTable, dwIndex);
  992. RELEASE_WRITE_LOCK(&pTable->IT_RWL);
  993. TRACE1(LEAVE, "leaving EnableInterface: %d", dwErr);
  994. return dwErr;
  995. }
  996. //----------------------------------------------------------------------------
  997. // Function: DisableInterface
  998. //
  999. //----------------------------------------------------------------------------
  1000. DWORD
  1001. APIENTRY
  1002. DisableInterface(
  1003. IN DWORD dwIndex
  1004. ) {
  1005. DWORD dwErr;
  1006. PIF_TABLE pTable;
  1007. PIF_TABLE_ENTRY pite;
  1008. TRACE1(ENTER, "entering DisableInterface: %d", dwIndex);
  1009. pTable = ig.IG_IfTable;
  1010. ACQUIRE_WRITE_LOCK(&pTable->IT_RWL);
  1011. dwErr = DisableIfEntry(pTable, dwIndex);
  1012. RELEASE_WRITE_LOCK(&pTable->IT_RWL);
  1013. TRACE1(LEAVE, "leaving DisableInterface: %d", dwErr);
  1014. return dwErr;
  1015. }
  1016. //----------------------------------------------------------------------------
  1017. // Function: DoUpdateRoutes
  1018. //
  1019. // This API is unsupported since BOOTP is not a routing protocol.
  1020. //----------------------------------------------------------------------------
  1021. DWORD
  1022. APIENTRY
  1023. DoUpdateRoutes(
  1024. IN DWORD dwIndex
  1025. ) {
  1026. return ERROR_CAN_NOT_COMPLETE;
  1027. }
  1028. //----------------------------------------------------------------------------
  1029. // Function: MibCreate
  1030. //
  1031. // BOOTP does not have create-able MIB fields.
  1032. //----------------------------------------------------------------------------
  1033. DWORD
  1034. APIENTRY
  1035. MibCreate(
  1036. IN DWORD dwInputSize,
  1037. IN PVOID pInputData
  1038. ) {
  1039. return ERROR_CAN_NOT_COMPLETE;
  1040. }
  1041. //----------------------------------------------------------------------------
  1042. // Function: MibDelete
  1043. //
  1044. // BOOTP does not have delete-able MIB fields
  1045. //----------------------------------------------------------------------------
  1046. DWORD
  1047. APIENTRY
  1048. MibDelete(
  1049. IN DWORD dwInputSize,
  1050. IN PVOID pInputData
  1051. ) {
  1052. return ERROR_CAN_NOT_COMPLETE;
  1053. }
  1054. //----------------------------------------------------------------------------
  1055. // Function: MibSet
  1056. //
  1057. // This is called to modify writable MIB variables.
  1058. // The writable entries are the global config and interface config.
  1059. //----------------------------------------------------------------------------
  1060. DWORD
  1061. APIENTRY
  1062. MibSet(
  1063. IN DWORD dwInputSize,
  1064. IN PVOID pInputData
  1065. ) {
  1066. DWORD dwErr;
  1067. PIPBOOTP_MIB_SET_INPUT_DATA pimsid;
  1068. if (!ENTER_BOOTP_API()) { return ERROR_CAN_NOT_COMPLETE; }
  1069. TRACE2(ENTER, "entering MibSet: %d 0x%08x", dwInputSize, pInputData);
  1070. dwErr = NO_ERROR;
  1071. do { // breakout loop
  1072. //
  1073. // make certain the parameters are acceptable
  1074. //
  1075. if (pInputData == NULL ||
  1076. dwInputSize < sizeof(IPBOOTP_MIB_SET_INPUT_DATA)) {
  1077. dwErr = ERROR_INVALID_PARAMETER;
  1078. break;
  1079. }
  1080. //
  1081. // see which entry type is to be set
  1082. //
  1083. pimsid = (PIPBOOTP_MIB_SET_INPUT_DATA)pInputData;
  1084. switch(pimsid->IMSID_TypeID) {
  1085. case IPBOOTP_GLOBAL_CONFIG_ID: {
  1086. PIPBOOTP_GLOBAL_CONFIG pigc;
  1087. //
  1088. // make sure the buffer is big enough
  1089. // to hold a global config block
  1090. //
  1091. if (pimsid->IMSID_BufferSize < sizeof(IPBOOTP_GLOBAL_CONFIG)) {
  1092. dwErr = ERROR_INSUFFICIENT_BUFFER;
  1093. break;
  1094. }
  1095. //
  1096. // call the router manager API to set the config
  1097. //
  1098. dwErr = SetGlobalInfo(pimsid->IMSID_Buffer,
  1099. 1,
  1100. sizeof(IPBOOTP_GLOBAL_CONFIG),
  1101. 1);
  1102. if (dwErr == NO_ERROR) {
  1103. //
  1104. // the set succeeded, so notify the router manager
  1105. // that the global config has changed and should be saved
  1106. //
  1107. MESSAGE msg = {0, 0, 0};
  1108. ACQUIRE_LIST_LOCK(ig.IG_EventQueue);
  1109. EnqueueEvent(
  1110. ig.IG_EventQueue,
  1111. SAVE_GLOBAL_CONFIG_INFO,
  1112. msg
  1113. );
  1114. SetEvent(ig.IG_EventEvent);
  1115. RELEASE_LIST_LOCK(ig.IG_EventQueue);
  1116. }
  1117. break;
  1118. }
  1119. case IPBOOTP_IF_CONFIG_ID: {
  1120. DWORD dwSize;
  1121. PIF_TABLE pTable;
  1122. PIF_TABLE_ENTRY pite;
  1123. PIPBOOTP_IF_CONFIG pic;
  1124. //
  1125. // make sure the buffer is big enough
  1126. // to hold an interface config block
  1127. //
  1128. if (pimsid->IMSID_BufferSize < sizeof(IPBOOTP_IF_CONFIG)) {
  1129. dwErr = ERROR_INSUFFICIENT_BUFFER;
  1130. break;
  1131. }
  1132. pic = (PIPBOOTP_IF_CONFIG)pimsid->IMSID_Buffer;
  1133. pTable = ig.IG_IfTable;
  1134. ACQUIRE_WRITE_LOCK(&pTable->IT_RWL);
  1135. //
  1136. // find the interface and update its config
  1137. //
  1138. pite = GetIfByIndex(
  1139. pTable,
  1140. pimsid->IMSID_IfIndex
  1141. );
  1142. if (pite == NULL) {
  1143. TRACE1(
  1144. CONFIG, "MibSet: could not find interface %d",
  1145. pimsid->IMSID_IfIndex
  1146. );
  1147. dwErr = ERROR_INVALID_PARAMETER;
  1148. }
  1149. else {
  1150. //
  1151. // configure the interface
  1152. //
  1153. dwErr = ConfigureIfEntry(pTable, pite->ITE_Index, pic);
  1154. }
  1155. if (dwErr == NO_ERROR) {
  1156. //
  1157. // notify Router manager that config has changed
  1158. //
  1159. MESSAGE msg = {0, 0, 0};
  1160. msg.InterfaceIndex = pite->ITE_Index;
  1161. ACQUIRE_LIST_LOCK(ig.IG_EventQueue);
  1162. EnqueueEvent(
  1163. ig.IG_EventQueue,
  1164. SAVE_INTERFACE_CONFIG_INFO,
  1165. msg
  1166. );
  1167. SetEvent(ig.IG_EventEvent);
  1168. RELEASE_LIST_LOCK(ig.IG_EventQueue);
  1169. }
  1170. RELEASE_WRITE_LOCK(&pTable->IT_RWL);
  1171. break;
  1172. }
  1173. default: {
  1174. dwErr = ERROR_INVALID_PARAMETER;
  1175. }
  1176. }
  1177. } while(FALSE);
  1178. LEAVE_BOOTP_API();
  1179. return dwErr;
  1180. }
  1181. //----------------------------------------------------------------------------
  1182. // Function: MibGet
  1183. //
  1184. // This function retrieves a MIB entry.
  1185. //----------------------------------------------------------------------------
  1186. DWORD
  1187. APIENTRY
  1188. MibGet(
  1189. IN DWORD dwInputSize,
  1190. IN PVOID pInputData,
  1191. IN OUT PDWORD pdwOutputSize,
  1192. OUT PVOID pOutputData
  1193. ) {
  1194. DWORD dwErr;
  1195. PIPBOOTP_MIB_GET_INPUT_DATA pimgid;
  1196. PIPBOOTP_MIB_GET_OUTPUT_DATA pimgod;
  1197. if (!ENTER_BOOTP_API()) { return ERROR_CAN_NOT_COMPLETE; }
  1198. TRACE4(
  1199. ENTER, "entering MibGet: %d 0x%08x 0x%08x 0x%08x",
  1200. dwInputSize, pInputData, pdwOutputSize, pOutputData
  1201. );
  1202. if (pInputData == NULL ||
  1203. dwInputSize < sizeof(IPBOOTP_MIB_GET_INPUT_DATA) ||
  1204. pdwOutputSize == NULL) {
  1205. dwErr = ERROR_INVALID_PARAMETER;
  1206. }
  1207. else {
  1208. //
  1209. // invoke the internal function for retrieving the MIB
  1210. //
  1211. pimgid = (PIPBOOTP_MIB_GET_INPUT_DATA)pInputData;
  1212. pimgod = (PIPBOOTP_MIB_GET_OUTPUT_DATA)pOutputData;
  1213. dwErr = MibGetInternal(pimgid, pimgod, pdwOutputSize, GETMODE_EXACT);
  1214. }
  1215. TRACE1(LEAVE, "leaving MibGet: %d", dwErr);
  1216. LEAVE_BOOTP_API();
  1217. return dwErr;
  1218. }
  1219. //----------------------------------------------------------------------------
  1220. // Function: MibGetFirst
  1221. //
  1222. // This function retrieve a MIB entry from one of the MIB tables,
  1223. // but it differs from MibGet in that it always returns the first entry
  1224. // in the table specified.
  1225. //----------------------------------------------------------------------------
  1226. DWORD
  1227. APIENTRY
  1228. MibGetFirst(
  1229. IN DWORD dwInputSize,
  1230. IN PVOID pInputData,
  1231. IN OUT PDWORD pdwOutputSize,
  1232. OUT PVOID pOutputData
  1233. ) {
  1234. DWORD dwErr;
  1235. PIPBOOTP_MIB_GET_INPUT_DATA pimgid;
  1236. PIPBOOTP_MIB_GET_OUTPUT_DATA pimgod;
  1237. if (!ENTER_BOOTP_API()) { return ERROR_CAN_NOT_COMPLETE; }
  1238. TRACE4(
  1239. ENTER, "entering MibGetFirst: %d 0x%08x 0x%08x 0x%08x",
  1240. dwInputSize, pInputData, pdwOutputSize, pOutputData
  1241. );
  1242. if (pInputData == NULL ||
  1243. dwInputSize < sizeof(IPBOOTP_MIB_GET_INPUT_DATA) ||
  1244. pdwOutputSize == NULL) {
  1245. dwErr = ERROR_INVALID_PARAMETER;
  1246. }
  1247. else {
  1248. pimgid = (PIPBOOTP_MIB_GET_INPUT_DATA)pInputData;
  1249. pimgod = (PIPBOOTP_MIB_GET_OUTPUT_DATA)pOutputData;
  1250. dwErr = MibGetInternal(pimgid, pimgod, pdwOutputSize, GETMODE_FIRST);
  1251. }
  1252. TRACE1(LEAVE, "leaving MibGetFirst: %d", dwErr);
  1253. LEAVE_BOOTP_API();
  1254. return dwErr;
  1255. }
  1256. //----------------------------------------------------------------------------
  1257. // Function: MibGetNext
  1258. //
  1259. // This function retrieves a MIB entry from one of the MIB tables.
  1260. // It differs from MibGet() and MibGetFirst() in that the input
  1261. // specifies the index of a MIB entry, and this entry returns the MIB entry
  1262. // which is AFTER the entry whose index is specified.
  1263. //
  1264. // If the index specified is that of the last entry in the specified table,
  1265. // this function wraps to the FIRST entry in the NEXT table, where "NEXT"
  1266. // here means the table whose ID is one greater than the ID passed in.
  1267. // Thus calling MibGetNext() for the last entry in the interface stats table
  1268. // will return the first entry in the interface config table.
  1269. //----------------------------------------------------------------------------
  1270. DWORD
  1271. APIENTRY
  1272. MibGetNext(
  1273. IN DWORD dwInputSize,
  1274. IN PVOID pInputData,
  1275. IN OUT PDWORD pdwOutputSize,
  1276. OUT PVOID pOutputData
  1277. ) {
  1278. DWORD dwErr, dwOutSize = 0, dwBufSize = 0;
  1279. PIPBOOTP_MIB_GET_INPUT_DATA pimgid;
  1280. PIPBOOTP_MIB_GET_OUTPUT_DATA pimgod;
  1281. if (!ENTER_BOOTP_API()) { return ERROR_CAN_NOT_COMPLETE; }
  1282. TRACE4(
  1283. ENTER, "entering MibGetNext: %d 0x%08x 0x%08x 0x%08x",
  1284. dwInputSize, pInputData, pdwOutputSize, pOutputData
  1285. );
  1286. if (pInputData == NULL ||
  1287. dwInputSize < sizeof(IPBOOTP_MIB_GET_INPUT_DATA) ||
  1288. pdwOutputSize == NULL) {
  1289. dwErr = ERROR_INVALID_PARAMETER;
  1290. }
  1291. else {
  1292. pimgid = (PIPBOOTP_MIB_GET_INPUT_DATA)pInputData;
  1293. pimgod = (PIPBOOTP_MIB_GET_OUTPUT_DATA)pOutputData;
  1294. dwOutSize = *pdwOutputSize;
  1295. dwErr = MibGetInternal(pimgid, pimgod, pdwOutputSize, GETMODE_NEXT);
  1296. if (dwErr == ERROR_NO_MORE_ITEMS) {
  1297. //
  1298. // wrap to the first entry in the next table
  1299. //
  1300. TRACE1(
  1301. CONFIG, "MibGetNext is wrapping to table %d",
  1302. pimgid->IMGID_TypeID + 1
  1303. );
  1304. //
  1305. // restore the size passed in
  1306. //
  1307. *pdwOutputSize = dwOutSize;
  1308. //
  1309. // wrap to the next table by incrementing the type ID
  1310. //
  1311. ++pimgid->IMGID_TypeID;
  1312. dwErr = MibGetInternal(
  1313. pimgid, pimgod, pdwOutputSize, GETMODE_FIRST
  1314. );
  1315. --pimgid->IMGID_TypeID;
  1316. }
  1317. }
  1318. TRACE1(LEAVE, "leaving MibGetNext: %d", dwErr);
  1319. LEAVE_BOOTP_API();
  1320. return dwErr;
  1321. }
  1322. //----------------------------------------------------------------------------
  1323. // Function: MibGetInternal
  1324. //
  1325. // This function handles the structure queries necessary to read MIB data.
  1326. // Each table exposed by IPBOOTP supports three types of queries:
  1327. // EXACT, FIRST, and NEXT, which correspond to the functions MibGet(),
  1328. // MibGetFirst(), and MibGetNext() respectively.
  1329. //----------------------------------------------------------------------------
  1330. DWORD
  1331. MibGetInternal(
  1332. PIPBOOTP_MIB_GET_INPUT_DATA pimgid,
  1333. PIPBOOTP_MIB_GET_OUTPUT_DATA pimgod,
  1334. PDWORD pdwOutputSize,
  1335. DWORD dwGetMode
  1336. ) {
  1337. DWORD dwErr, dwBufSize, dwSize;
  1338. ULONG ulVersion, ulSize,ulCount;
  1339. dwErr = NO_ERROR;
  1340. //
  1341. // first we use pdwOutputSize to compute the size of the buffer
  1342. // available (i.e. the size of IMGOD_Buffer
  1343. //
  1344. if (pimgod == NULL ||
  1345. *pdwOutputSize < sizeof(IPBOOTP_MIB_GET_OUTPUT_DATA)) {
  1346. dwBufSize = 0;
  1347. }
  1348. else {
  1349. dwBufSize = *pdwOutputSize - sizeof(IPBOOTP_MIB_GET_OUTPUT_DATA) + 1;
  1350. }
  1351. *pdwOutputSize = 0;
  1352. //
  1353. // determine which type of data is to be returned
  1354. //
  1355. switch (pimgid->IMGID_TypeID) {
  1356. case IPBOOTP_GLOBAL_CONFIG_ID: {
  1357. //
  1358. // the global config struct is variable-length,
  1359. // so we wait until it has been retrieved before setting the size;
  1360. // GETMODE_NEXT is invalid since there is only one global config
  1361. //
  1362. if (pimgod) { pimgod->IMGOD_TypeID = IPBOOTP_GLOBAL_CONFIG_ID; }
  1363. if (dwGetMode == GETMODE_NEXT) {
  1364. dwErr = ERROR_NO_MORE_ITEMS;
  1365. break;
  1366. }
  1367. //
  1368. // Use GetGlobalInfo to retrieve the global information;
  1369. // It will decide whether the buffer is large enough,
  1370. // and it will set the required size. Then all we need to do
  1371. // is write out the size set by GetGlobalInfo.
  1372. //
  1373. if (pimgod == NULL) {
  1374. dwErr = GetGlobalInfo(NULL, &dwBufSize, NULL, NULL, NULL);
  1375. }
  1376. else {
  1377. dwErr = GetGlobalInfo(
  1378. pimgod->IMGOD_Buffer, &dwBufSize, &ulVersion, &ulSize, &ulCount
  1379. );
  1380. }
  1381. *pdwOutputSize = sizeof(IPBOOTP_MIB_GET_OUTPUT_DATA) - 1 +
  1382. dwBufSize;
  1383. break;
  1384. }
  1385. case IPBOOTP_IF_STATS_ID: {
  1386. //
  1387. // the interface stats struct is fixed-length,
  1388. // with as many entries as there are interfaces
  1389. //
  1390. PIF_TABLE pTable;
  1391. PIF_TABLE_ENTRY pite;
  1392. PIPBOOTP_IF_STATS pissrc, pisdst;
  1393. //
  1394. // set the size needed right away
  1395. //
  1396. *pdwOutputSize = sizeof(IPBOOTP_MIB_GET_OUTPUT_DATA) - 1 +
  1397. sizeof(IPBOOTP_IF_STATS);
  1398. if (pimgod) { pimgod->IMGOD_TypeID = IPBOOTP_IF_STATS_ID; }
  1399. pTable = ig.IG_IfTable;
  1400. ACQUIRE_READ_LOCK(&pTable->IT_RWL);
  1401. pite = GetIfByListIndex(
  1402. pTable,
  1403. pimgid->IMGID_IfIndex,
  1404. dwGetMode,
  1405. &dwErr
  1406. );
  1407. //
  1408. // if the interface was not found, it may mean
  1409. // the specified index was invalid, or it may mean that
  1410. // GETMODE_NEXT was attempted on the last interface,
  1411. // in which case dwErr contains ERROR_NO_MORE_ITEMS.
  1412. // In any case, we make sure dwErr contains an error code
  1413. // and then return.
  1414. //
  1415. if (pite == NULL) {
  1416. if (dwErr == NO_ERROR) { dwErr = ERROR_INVALID_PARAMETER; }
  1417. }
  1418. else
  1419. if (pimgod == NULL) {
  1420. dwErr = ERROR_INSUFFICIENT_BUFFER;
  1421. }
  1422. else {
  1423. //
  1424. // write the index of the interface
  1425. // whose stats are to be returned
  1426. //
  1427. pimgod->IMGOD_IfIndex = pite->ITE_Index;
  1428. //
  1429. // if the buffer is large enough, copy the stats to it
  1430. //
  1431. if (dwBufSize < sizeof(IPBOOTP_IF_STATS)) {
  1432. dwErr = ERROR_INSUFFICIENT_BUFFER;
  1433. }
  1434. else {
  1435. //
  1436. // since access to this structure is not synchronized
  1437. // we must copy it field by field
  1438. //
  1439. pissrc = &pite->ITE_Stats;
  1440. pisdst = (PIPBOOTP_IF_STATS)pimgod->IMGOD_Buffer;
  1441. pisdst->IS_State = 0;
  1442. if (IF_IS_ENABLED(pite)) {
  1443. pisdst->IS_State |= IPBOOTP_STATE_ENABLED;
  1444. }
  1445. if (IF_IS_BOUND(pite)) {
  1446. pisdst->IS_State |= IPBOOTP_STATE_BOUND;
  1447. }
  1448. pisdst->IS_SendFailures =
  1449. pissrc->IS_SendFailures;
  1450. pisdst->IS_ReceiveFailures =
  1451. pissrc->IS_ReceiveFailures;
  1452. pisdst->IS_ArpUpdateFailures =
  1453. pissrc->IS_ArpUpdateFailures;
  1454. pisdst->IS_RequestsReceived =
  1455. pissrc->IS_RequestsReceived;
  1456. pisdst->IS_RequestsDiscarded =
  1457. pissrc->IS_RequestsDiscarded;
  1458. pisdst->IS_RepliesReceived =
  1459. pissrc->IS_RepliesReceived;
  1460. pisdst->IS_RepliesDiscarded =
  1461. pissrc->IS_RepliesDiscarded;
  1462. }
  1463. }
  1464. RELEASE_READ_LOCK(&pTable->IT_RWL);
  1465. break;
  1466. }
  1467. case IPBOOTP_IF_CONFIG_ID: {
  1468. PIF_TABLE pTable;
  1469. PIF_TABLE_ENTRY pite;
  1470. PIPBOOTP_IF_CONFIG picsrc, picdst;
  1471. if (pimgod) { pimgod->IMGOD_TypeID = IPBOOTP_IF_CONFIG_ID; }
  1472. pTable = ig.IG_IfTable;
  1473. ACQUIRE_READ_LOCK(&pTable->IT_RWL);
  1474. //
  1475. // retrieve the interface whose config is to be read
  1476. //
  1477. pite = GetIfByListIndex(
  1478. pTable, pimgid->IMGID_IfIndex, dwGetMode, &dwErr
  1479. );
  1480. //
  1481. // if the interface was not found, it may mean that the index
  1482. // specified was invalid, or it may mean that a GETMODE_NEXT
  1483. // retrieval was attempted on the last interface, in which case
  1484. // ERROR_NO_MORE_ITEMS would have been returned
  1485. //
  1486. if (pite == NULL) {
  1487. if (dwErr == NO_ERROR) { dwErr = ERROR_INVALID_PARAMETER; }
  1488. }
  1489. else {
  1490. picsrc = pite->ITE_Config;
  1491. dwSize = IC_SIZEOF(picsrc);
  1492. *pdwOutputSize = sizeof(IPBOOTP_MIB_GET_OUTPUT_DATA) - 1 +
  1493. dwSize;
  1494. //
  1495. // if no buffer was specified, indicate one should be allocated
  1496. //
  1497. if (pimgod == NULL) {
  1498. dwErr = ERROR_INSUFFICIENT_BUFFER;
  1499. }
  1500. else {
  1501. //
  1502. // if the buffer is not large enough,
  1503. // indicate that it should be enlarged
  1504. //
  1505. if (dwBufSize < dwSize) {
  1506. dwErr = ERROR_INSUFFICIENT_BUFFER;
  1507. }
  1508. else {
  1509. //
  1510. // copy the configuration
  1511. //
  1512. picdst = (PIPBOOTP_IF_CONFIG)pimgod->IMGOD_Buffer;
  1513. CopyMemory(picdst, picsrc, dwSize);
  1514. picdst->IC_State = 0;
  1515. if (IF_IS_ENABLED(pite)) {
  1516. picdst->IC_State |= IPBOOTP_STATE_ENABLED;
  1517. }
  1518. if (IF_IS_BOUND(pite)) {
  1519. picdst->IC_State |= IPBOOTP_STATE_BOUND;
  1520. }
  1521. }
  1522. pimgod->IMGOD_IfIndex = pite->ITE_Index;
  1523. }
  1524. }
  1525. RELEASE_READ_LOCK(&pTable->IT_RWL);
  1526. break;
  1527. }
  1528. case IPBOOTP_IF_BINDING_ID: {
  1529. PIF_TABLE pTable;
  1530. PIF_TABLE_ENTRY pite;
  1531. PIPBOOTP_IF_BINDING pibsrc, pibdst;
  1532. if (pimgod) { pimgod->IMGOD_TypeID = IPBOOTP_IF_BINDING_ID; }
  1533. pTable = ig.IG_IfTable;
  1534. ACQUIRE_READ_LOCK(&pTable->IT_RWL);
  1535. //
  1536. // retrieve the interface whose binding is to be read
  1537. //
  1538. pite = GetIfByListIndex(
  1539. pTable, pimgid->IMGID_IfIndex, dwGetMode, &dwErr
  1540. );
  1541. //
  1542. // if the interface was not found, it may mean that the index
  1543. // specified was invalid, or it may mean that a GETMODE_NEXT
  1544. // retrieval was attempted on the last interface, in which case
  1545. // ERROR_NO_MORE_ITEMS would have been returned
  1546. //
  1547. if (pite == NULL) {
  1548. if (dwErr == NO_ERROR) { dwErr = ERROR_INVALID_PARAMETER; }
  1549. }
  1550. else {
  1551. pibsrc = pite->ITE_Binding;
  1552. if (pibsrc == NULL ) {
  1553. TRACE1(
  1554. IF, "MibGetInternal: interface %d not bound",
  1555. pimgid->IMGID_IfIndex
  1556. );
  1557. dwErr = ERROR_INVALID_PARAMETER;
  1558. }
  1559. else {
  1560. dwSize = (pibsrc ? IPBOOTP_IF_BINDING_SIZE(pibsrc)
  1561. : sizeof(IPBOOTP_IF_BINDING));
  1562. *pdwOutputSize = sizeof(IPBOOTP_MIB_GET_OUTPUT_DATA) - 1 +
  1563. dwSize;
  1564. //
  1565. // if no buffer was specified, indicate one should be allocated
  1566. //
  1567. if (pimgod == NULL) {
  1568. dwErr = ERROR_INSUFFICIENT_BUFFER;
  1569. }
  1570. else {
  1571. //
  1572. // if the buffer is not large enough,
  1573. // indicate that it should be enlarged
  1574. //
  1575. if (dwBufSize < dwSize) {
  1576. dwErr = ERROR_INSUFFICIENT_BUFFER;
  1577. }
  1578. else {
  1579. //
  1580. // copy the binding
  1581. //
  1582. pibdst = (PIPBOOTP_IF_BINDING)pimgod->IMGOD_Buffer;
  1583. if (pibsrc) { CopyMemory(pibdst, pibsrc, dwSize); }
  1584. else { pibdst->IB_AddrCount = 0; }
  1585. pibdst->IB_State = 0;
  1586. if (IF_IS_ENABLED(pite)) {
  1587. pibdst->IB_State |= IPBOOTP_STATE_ENABLED;
  1588. }
  1589. if (IF_IS_BOUND(pite)) {
  1590. pibdst->IB_State |= IPBOOTP_STATE_BOUND;
  1591. }
  1592. }
  1593. pimgod->IMGOD_IfIndex = pite->ITE_Index;
  1594. }
  1595. }
  1596. }
  1597. RELEASE_READ_LOCK(&pTable->IT_RWL);
  1598. break;
  1599. }
  1600. default: {
  1601. dwErr = ERROR_INVALID_PARAMETER;
  1602. }
  1603. }
  1604. return dwErr;
  1605. }
  1606. //----------------------------------------------------------------------------
  1607. // Function: EnableDhcpInformServer
  1608. //
  1609. // Called to supply the address of a server to whom DHCP inform messages
  1610. // will be redirected. Note that this is an exported routine, invoked
  1611. // in the context of the caller's process, whatever that might be;
  1612. // the assumption is that it will be called from within the router process.
  1613. //
  1614. // If the relay-agent is configured, then this sets an address which will
  1615. // be picked up in 'ProcessRequest' for every incoming request.
  1616. // If the relay-agent is not configured, the routine has no effect.
  1617. // If the relay-agent is configured *after* this routine is called,
  1618. // then the DHCP inform server will be encountered as soon as the relay-agent
  1619. // starts, since it is saved directly into the relay-agents 'IPBOOTP_GLOBALS'.
  1620. //----------------------------------------------------------------------------
  1621. VOID APIENTRY
  1622. EnableDhcpInformServer(
  1623. DWORD DhcpInformServer
  1624. ) {
  1625. InterlockedExchange(&ig.IG_DhcpInformServer, DhcpInformServer);
  1626. }
  1627. //----------------------------------------------------------------------------
  1628. // Function: DisableDhcpInformServer
  1629. //
  1630. // Called to clear the previously-enabled DHCP inform server, if any.
  1631. //----------------------------------------------------------------------------
  1632. VOID APIENTRY
  1633. DisableDhcpInformServer(
  1634. VOID
  1635. ) {
  1636. InterlockedExchange(&ig.IG_DhcpInformServer, 0);
  1637. }