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.

1433 lines
32 KiB

  1. //============================================================================
  2. // Copyright (c) 1995, Microsoft Corporation
  3. //
  4. // File: table.c
  5. //
  6. // History:
  7. // Abolade Gbadegesin August 31, 1995 Created
  8. //
  9. // Interface table and stats tables management routines
  10. //============================================================================
  11. #include "pchbootp.h"
  12. //----------------------------------------------------------------------------
  13. // Function: CreateIfTable
  14. //
  15. // Initializes an interface table.
  16. //----------------------------------------------------------------------------
  17. DWORD
  18. CreateIfTable(
  19. PIF_TABLE pTable
  20. ) {
  21. DWORD dwErr;
  22. PLIST_ENTRY ple, plend;
  23. //
  24. // return an error if the table is already created
  25. //
  26. if ( IF_TABLE_CREATED(pTable) ) {
  27. TRACE0( IF, "interface table already initialized" );
  28. return ERROR_ALREADY_EXISTS;
  29. }
  30. //
  31. // initialize the by-address and by-index lists of interfaces
  32. //
  33. InitializeListHead( &pTable->IT_ListByAddress );
  34. InitializeListHead(&pTable->IT_ListByIndex);
  35. //
  36. // initialize the by-index hash-table of interfaces
  37. //
  38. plend = pTable->IT_HashTableByIndex + IF_HASHTABLE_SIZE;
  39. for ( ple = pTable->IT_HashTableByIndex; ple < plend; ple++ ) {
  40. InitializeListHead( ple );
  41. }
  42. //
  43. // initialize the lock which will protect the table
  44. //
  45. dwErr = NO_ERROR;
  46. try {
  47. CREATE_READ_WRITE_LOCK( &pTable->IT_RWL );
  48. }
  49. except ( EXCEPTION_EXECUTE_HANDLER ) {
  50. dwErr = GetExceptionCode( );
  51. TRACE1( IF, "error %d initializing interface table lock", dwErr );
  52. }
  53. if ( dwErr == NO_ERROR ) {
  54. pTable->IT_Created = 0x12345678;
  55. }
  56. return dwErr;
  57. }
  58. //----------------------------------------------------------------------------
  59. // Function: DeleteIfTable
  60. //
  61. // Deinitializes an interface table, and releases all resources used.
  62. // Assumes the table is locked exclusively
  63. //----------------------------------------------------------------------------
  64. DWORD
  65. DeleteIfTable(
  66. PIF_TABLE pTable
  67. ) {
  68. DWORD dwErr;
  69. PIF_TABLE_ENTRY pite;
  70. PLIST_ENTRY ple, plend, phead;
  71. //
  72. // clear the creation flag on the table
  73. //
  74. pTable->IT_Created = 0;
  75. //
  76. // free memory used by all entries
  77. //
  78. plend = pTable->IT_HashTableByIndex + IF_HASHTABLE_SIZE;
  79. for ( phead = pTable->IT_HashTableByIndex; phead < plend; phead++ ) {
  80. while ( !IsListEmpty( phead ) ) {
  81. ple = RemoveHeadList( phead );
  82. pite = CONTAINING_RECORD(ple, IF_TABLE_ENTRY, ITE_HTLinkByIndex);
  83. if (IF_IS_BOUND(pite)) {
  84. DeleteIfSocket(pite);
  85. if (IF_IS_ENABLED(pite)) {
  86. RemoveEntryList(&pite->ITE_LinkByAddress);
  87. }
  88. BOOTP_FREE(pite->ITE_Binding);
  89. }
  90. if (pite->ITE_Config) {
  91. BOOTP_FREE(pite->ITE_Config);
  92. }
  93. BOOTP_FREE( pite );
  94. }
  95. }
  96. dwErr = NO_ERROR;
  97. try {
  98. DELETE_READ_WRITE_LOCK( &pTable->IT_RWL );
  99. }
  100. except( EXCEPTION_EXECUTE_HANDLER ) {
  101. dwErr = GetExceptionCode( );
  102. TRACE1( IF, "error %d deleting interface table lock", dwErr );
  103. }
  104. return dwErr;
  105. }
  106. //----------------------------------------------------------------------------
  107. // Function: CreateIfEntry
  108. //
  109. // Allocates and initializes an entry for an interface in the table,
  110. // using the supplied configuration. Assumes table is locked exclusively.
  111. //----------------------------------------------------------------------------
  112. DWORD
  113. CreateIfEntry(
  114. PIF_TABLE pTable,
  115. DWORD dwIndex,
  116. PVOID pConfig
  117. ) {
  118. DWORD dwErr, dwSize;
  119. PIF_TABLE_ENTRY pite;
  120. PLIST_ENTRY ple, phead;
  121. PIPBOOTP_IF_CONFIG picsrc, picdst;
  122. dwErr = NO_ERROR;
  123. do { // error breakout loop
  124. //
  125. // see if the interface already exists
  126. //
  127. pite = GetIfByIndex( pTable, dwIndex );
  128. if ( pite != NULL ) {
  129. TRACE1( IF, "interface %d already exists", dwIndex );
  130. dwErr = ERROR_ALREADY_EXISTS; pite = NULL; break;
  131. }
  132. //
  133. // now allocate memory for the interface
  134. //
  135. pite = BOOTP_ALLOC( sizeof(IF_TABLE_ENTRY) );
  136. if ( pite == NULL ) {
  137. dwErr = GetLastError( );
  138. TRACE2(
  139. IF, "error %d allocating %d bytes for interface entry",
  140. dwErr, sizeof(IF_TABLE_ENTRY)
  141. );
  142. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  143. break;
  144. }
  145. //
  146. // initialize struct fields
  147. //
  148. pite->ITE_Index = dwIndex;
  149. //
  150. // We come up in disabled state
  151. //
  152. pite->ITE_Flags = 0;
  153. pite->ITE_Sockets = NULL;
  154. pite->ITE_Config = NULL;
  155. //
  156. // get the size of the configuration block
  157. //
  158. picsrc = (PIPBOOTP_IF_CONFIG)pConfig;
  159. dwSize = IC_SIZEOF( picsrc );
  160. //
  161. // validate the configuration parameters
  162. //
  163. dwErr = ValidateIfConfig(pConfig);
  164. if (dwErr != NO_ERROR) {
  165. TRACE1(IF, "invalid config specified for interface %d", dwIndex);
  166. break;
  167. }
  168. //
  169. // allocate space for the configuration
  170. //
  171. picdst = BOOTP_ALLOC( dwSize );
  172. if ( picdst == NULL ) {
  173. dwErr = GetLastError( );
  174. TRACE2(
  175. IF, "error %d allocating %d bytes for interface configuration",
  176. dwErr, dwSize
  177. );
  178. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  179. pite->ITE_Config = NULL; break;
  180. }
  181. //
  182. // copy the configuration
  183. //
  184. CopyMemory(picdst, picsrc, dwSize);
  185. pite->ITE_Config = picdst;
  186. //
  187. // initialize binding information and interface stats
  188. //
  189. pite->ITE_Binding = NULL;
  190. ZeroMemory(&pite->ITE_Stats, sizeof(IPBOOTP_IF_STATS));
  191. //
  192. // insert the interface in the hash table
  193. //
  194. phead = pTable->IT_HashTableByIndex + IF_HASHVALUE( dwIndex );
  195. InsertHeadList( phead, &pite->ITE_HTLinkByIndex );
  196. //
  197. // insert the interface in the list ordered by index
  198. //
  199. phead = &pTable->IT_ListByIndex;
  200. for (ple = phead->Flink; ple != phead; ple = ple->Flink) {
  201. PIF_TABLE_ENTRY ptemp;
  202. ptemp = CONTAINING_RECORD(ple, IF_TABLE_ENTRY, ITE_LinkByIndex);
  203. if (pite->ITE_Index < ptemp->ITE_Index) { break; }
  204. }
  205. InsertTailList(ple, &pite->ITE_LinkByIndex);
  206. } while( FALSE );
  207. if ( dwErr != NO_ERROR && pite != NULL ) {
  208. if ( pite->ITE_Config != NULL ) {
  209. BOOTP_FREE( pite->ITE_Config );
  210. }
  211. BOOTP_FREE( pite );
  212. }
  213. return dwErr;
  214. }
  215. //----------------------------------------------------------------------------
  216. // Function: DeleteIfEntry
  217. //
  218. // Removes an interface from the interface table.
  219. // Assumes the table is locked exclusively.
  220. //----------------------------------------------------------------------------
  221. DWORD
  222. DeleteIfEntry(
  223. PIF_TABLE pTable,
  224. DWORD dwIndex
  225. ) {
  226. DWORD dwErr;
  227. PIF_TABLE_ENTRY pite;
  228. //
  229. // make certain the interface exists
  230. //
  231. pite = GetIfByIndex( pTable, dwIndex );
  232. if ( pite == NULL ) {
  233. TRACE1( IF, "deleting interface: interface %d not found", dwIndex );
  234. return ERROR_INVALID_PARAMETER;
  235. }
  236. //
  237. // cleanup the socket depending on its state
  238. //
  239. if (IF_IS_BOUND(pite)) {
  240. DeleteIfSocket(pite);
  241. if (IF_IS_ENABLED(pite)) {
  242. RemoveEntryList(&pite->ITE_LinkByAddress);
  243. }
  244. BOOTP_FREE(pite->ITE_Binding);
  245. }
  246. //
  247. // remove the entry from the hash table and the list sorted by index
  248. //
  249. RemoveEntryList( &pite->ITE_HTLinkByIndex );
  250. RemoveEntryList( &pite->ITE_LinkByIndex );
  251. BOOTP_FREE( pite->ITE_Config );
  252. BOOTP_FREE( pite );
  253. return NO_ERROR;
  254. }
  255. //----------------------------------------------------------------------------
  256. // Function: ValidateIfConfig
  257. //
  258. // Validates the contents of the specified IPBOOTP_IF_CONFIG structure.
  259. //----------------------------------------------------------------------------
  260. DWORD
  261. ValidateIfConfig(
  262. PIPBOOTP_IF_CONFIG pic
  263. ) {
  264. CHAR szStr[12];
  265. if (pic->IC_RelayMode != IPBOOTP_RELAY_ENABLED &&
  266. pic->IC_RelayMode != IPBOOTP_RELAY_DISABLED) {
  267. TRACE1(
  268. IF, "Invalid value for relay mode %d",
  269. pic->IC_RelayMode
  270. );
  271. _ltoa(pic->IC_RelayMode, szStr, 10);
  272. LOGERR2(
  273. INVALID_IF_CONFIG, "Relay Mode", szStr,
  274. ERROR_INVALID_PARAMETER
  275. );
  276. return ERROR_INVALID_PARAMETER;
  277. }
  278. if (pic->IC_MaxHopCount > IPBOOTP_MAX_HOP_COUNT) {
  279. TRACE1(
  280. IF, "Invalid value for max hop count %d",
  281. pic->IC_MaxHopCount
  282. );
  283. _ltoa(pic->IC_MaxHopCount, szStr, 10);
  284. LOGERR2(
  285. INVALID_IF_CONFIG, "Max Hop Count", szStr,
  286. ERROR_INVALID_PARAMETER
  287. );
  288. return ERROR_INVALID_PARAMETER;
  289. }
  290. return NO_ERROR;
  291. }
  292. //----------------------------------------------------------------------------
  293. // Function: CreateIfSocket
  294. //
  295. // Initializes the socket for an interface. Assumes the interface table lock
  296. // is held exclusively.
  297. //----------------------------------------------------------------------------
  298. DWORD
  299. CreateIfSocket(
  300. PIF_TABLE_ENTRY pITE
  301. ) {
  302. SOCKADDR_IN sinaddr;
  303. PIPBOOTP_IF_BINDING pib;
  304. PIPBOOTP_IP_ADDRESS paddr;
  305. DWORD i, dwErr, dwOption;
  306. pib = pITE->ITE_Binding;
  307. paddr = IPBOOTP_IF_ADDRESS_TABLE(pib);
  308. //
  309. // allocate memory for the array of sockets
  310. //
  311. pITE->ITE_Sockets = BOOTP_ALLOC(pib->IB_AddrCount * sizeof(SOCKET));
  312. if (pITE->ITE_Sockets == NULL) {
  313. dwErr = GetLastError();
  314. TRACE3(
  315. IF, "error %d allocating %d bytes for sockets on interface %d",
  316. dwErr, pib->IB_AddrCount * sizeof(SOCKET), pITE->ITE_Index
  317. );
  318. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  319. return dwErr;
  320. }
  321. //
  322. // initialize the array
  323. //
  324. for (i = 0; i < pib->IB_AddrCount; i++) {
  325. pITE->ITE_Sockets[i] = INVALID_SOCKET;
  326. }
  327. //
  328. // go through the table of addresses in the binding,
  329. // creating a socket for each address
  330. //
  331. for (i = 0; i < pib->IB_AddrCount; i++, paddr++) {
  332. //
  333. // create a socket
  334. //
  335. pITE->ITE_Sockets[i] = WSASocket( AF_INET, SOCK_DGRAM, 0, NULL, 0, 0 );
  336. if (pITE->ITE_Sockets[i] == INVALID_SOCKET) {
  337. LPSTR lpszAddr;
  338. dwErr = WSAGetLastError( );
  339. lpszAddr = INET_NTOA( paddr->IA_Address );
  340. TRACE3(
  341. IF, "error %d creating socket for interface %d (%s)",
  342. dwErr, pITE->ITE_Index, lpszAddr
  343. );
  344. LOGERR1(CREATE_SOCKET_FAILED, lpszAddr, dwErr);
  345. break;
  346. }
  347. //
  348. // enable address re-use on this socket
  349. //
  350. dwOption = 1;
  351. dwErr = setsockopt(
  352. pITE->ITE_Sockets[i], SOL_SOCKET, SO_REUSEADDR,
  353. (PBYTE)&dwOption, sizeof( DWORD )
  354. );
  355. if ( dwErr == SOCKET_ERROR ) {
  356. //
  357. // this is a non-fatal error, so print a warning,
  358. // but continue initializing the socket
  359. //
  360. dwErr = WSAGetLastError( );
  361. TRACE3(
  362. IF, "error %d enabling address re-use for interface %d (%s)",
  363. dwErr, pITE->ITE_Index, INET_NTOA( paddr->IA_Address )
  364. );
  365. }
  366. //
  367. // enable broadcasting on the socket
  368. //
  369. dwOption = 1;
  370. dwErr = setsockopt(
  371. pITE->ITE_Sockets[i], SOL_SOCKET, SO_BROADCAST,
  372. (PBYTE)&dwOption, sizeof( DWORD )
  373. );
  374. if ( dwErr == SOCKET_ERROR ) {
  375. LPSTR lpszAddr;
  376. dwErr = WSAGetLastError( );
  377. lpszAddr = INET_NTOA( paddr->IA_Address );
  378. TRACE3(
  379. IF, "error %d enabling broadcast for interface %d (%s)",
  380. dwErr, pITE->ITE_Index, lpszAddr
  381. );
  382. LOGERR1(ENABLE_BROADCAST_FAILED, lpszAddr, dwErr);
  383. break;
  384. }
  385. //
  386. // bind to the address and the BOOTP Server port
  387. //
  388. sinaddr.sin_port = htons( IPBOOTP_SERVER_PORT );
  389. sinaddr.sin_family = AF_INET;
  390. sinaddr.sin_addr.s_addr = paddr->IA_Address;
  391. dwErr = bind(
  392. pITE->ITE_Sockets[i], (PSOCKADDR)&sinaddr,
  393. sizeof(SOCKADDR_IN)
  394. );
  395. if ( dwErr == SOCKET_ERROR ) {
  396. dwErr = WSAGetLastError( );
  397. TRACE3(
  398. IF, "error %d binding interface %d (%s) to BOOTP port",
  399. dwErr, pITE->ITE_Index, INET_NTOA( paddr->IA_Address )
  400. );
  401. break;
  402. }
  403. dwErr = NO_ERROR;
  404. }
  405. if ( i < pib->IB_AddrCount ) {
  406. //
  407. // an error occurred, so clean up
  408. //
  409. DeleteIfSocket( pITE );
  410. }
  411. return dwErr;
  412. }
  413. //----------------------------------------------------------------------------
  414. // Function: DeleteIfSocket
  415. //
  416. // This function closes the socket used by an interface.
  417. // It assumes the interface table lock is held exclusively.
  418. //----------------------------------------------------------------------------
  419. DWORD
  420. DeleteIfSocket(
  421. PIF_TABLE_ENTRY pITE
  422. ) {
  423. DWORD i, dwErr = NO_ERROR;
  424. PIPBOOTP_IF_BINDING pib;
  425. PIPBOOTP_IP_ADDRESS paddr;
  426. pib = pITE->ITE_Binding;
  427. if (!pib) { return ERROR_INVALID_PARAMETER; }
  428. paddr = IPBOOTP_IF_ADDRESS_TABLE(pib);
  429. for (i = 0; i < pib->IB_AddrCount; i++) {
  430. if ( pITE->ITE_Sockets[i] == INVALID_SOCKET ) { continue; }
  431. dwErr = closesocket( pITE->ITE_Sockets[i] );
  432. if ( dwErr == SOCKET_ERROR ) {
  433. dwErr = WSAGetLastError( );
  434. TRACE3(
  435. IF, "error %d closing socket for interface %d (%s)",
  436. dwErr, pITE->ITE_Index, INET_NTOA( paddr->IA_Address )
  437. );
  438. }
  439. }
  440. BOOTP_FREE(pITE->ITE_Sockets);
  441. pITE->ITE_Sockets = NULL;
  442. return dwErr;
  443. }
  444. //----------------------------------------------------------------------------
  445. // Function: BindIfEntry
  446. //
  447. // This function updates the binding information for an interface.
  448. // It assumes the interface table is locked for writing.
  449. //----------------------------------------------------------------------------
  450. DWORD
  451. BindIfEntry(
  452. PIF_TABLE pTable,
  453. DWORD dwIndex,
  454. PIP_ADAPTER_BINDING_INFO pBinding
  455. ) {
  456. DWORD i, dwErr = NO_ERROR, dwSize;
  457. PIF_TABLE_ENTRY pite = (PIF_TABLE_ENTRY) NULL;
  458. PIPBOOTP_IF_BINDING pib = (PIPBOOTP_IF_BINDING) NULL;
  459. PIPBOOTP_IP_ADDRESS paddr = (PIPBOOTP_IP_ADDRESS) NULL;
  460. do {
  461. //
  462. // retrieve the interface to be bound
  463. //
  464. pite = GetIfByIndex( pTable, dwIndex );
  465. if ( pite == NULL ) {
  466. TRACE1( IF, "binding interface: interface %d not found", dwIndex );
  467. dwErr = ERROR_INVALID_PARAMETER;
  468. break;
  469. }
  470. //
  471. // make sure the interface is not bound
  472. //
  473. if ( IF_IS_BOUND(pite) ) {
  474. TRACE1( IF, "interface %d is already bound", dwIndex );
  475. break;
  476. }
  477. //
  478. // make sure there is at least one address
  479. //
  480. if (pBinding->AddressCount == 0) { break; }
  481. dwSize = sizeof(IPBOOTP_IF_BINDING) +
  482. pBinding->AddressCount * sizeof(IPBOOTP_IP_ADDRESS);
  483. //
  484. // allocate memory to store the binding
  485. // in our format
  486. //
  487. pib = BOOTP_ALLOC(dwSize);
  488. if (pib == NULL) {
  489. dwErr = GetLastError();
  490. TRACE3(
  491. IF, "error %d allocating %d bytes for binding on interface %d",
  492. dwErr, dwSize, dwIndex
  493. );
  494. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  495. break;
  496. }
  497. //
  498. // convert the binding into our format
  499. //
  500. pib->IB_AddrCount = pBinding->AddressCount;
  501. paddr = IPBOOTP_IF_ADDRESS_TABLE(pib);
  502. for (i = 0; i < pib->IB_AddrCount; i++, paddr++) {
  503. paddr->IA_Address = pBinding->Address[i].Address;
  504. paddr->IA_Netmask = pBinding->Address[i].Mask;
  505. }
  506. //
  507. // save the binding in the interface entry
  508. //
  509. pite->ITE_Binding = pib;
  510. dwErr = CreateIfSocket(pite);
  511. if (dwErr != NO_ERROR) { break; }
  512. pite->ITE_Flags |= ITEFLAG_BOUND;
  513. //
  514. // if the interface is also enabled, it is now active
  515. // so we put it on the active list
  516. //
  517. if (IF_IS_ENABLED(pite)) {
  518. //
  519. // place interface on the list of active interfaces
  520. //
  521. dwErr = InsertIfByAddress(pTable, pite);
  522. if (dwErr != NO_ERROR) {
  523. TRACE2(
  524. IF, "error %d inserting interface %d in active list",
  525. dwErr, dwIndex
  526. );
  527. pite->ITE_Flags &= ~ITEFLAG_BOUND;
  528. DeleteIfSocket( pite );
  529. break;
  530. }
  531. //
  532. // request notification of input events from Winsock
  533. //
  534. paddr = IPBOOTP_IF_ADDRESS_TABLE(pib);
  535. for (i = 0; i < pib->IB_AddrCount; i++, paddr++) {
  536. dwErr = WSAEventSelect(
  537. pite->ITE_Sockets[i], ig.IG_InputEvent, FD_READ
  538. );
  539. if (dwErr != NO_ERROR) {
  540. LPSTR lpszAddr = INET_NTOA(paddr->IA_Address);
  541. TRACE3(
  542. IF, "WSAEventSelect returned %d for interface %d (%s)",
  543. dwErr, dwIndex, lpszAddr
  544. );
  545. LOGERR1(EVENTSELECT_FAILED, lpszAddr, dwErr);
  546. RemoveEntryList(&pite->ITE_LinkByAddress);
  547. pite->ITE_Flags &= ~ITEFLAG_BOUND;
  548. DeleteIfSocket( pite );
  549. break;
  550. }
  551. }
  552. if (i < pib->IB_AddrCount) { break; }
  553. }
  554. } while(FALSE);
  555. if (dwErr != NO_ERROR) {
  556. if (pib) { BOOTP_FREE(pib); }
  557. if (pite) { pite->ITE_Binding = NULL; }
  558. }
  559. return dwErr;
  560. }
  561. //----------------------------------------------------------------------------
  562. // Function: UnBindIfEntry
  563. //
  564. // removes the binding for the specified interface.
  565. // Assumes the interface table is locked for writing.
  566. //----------------------------------------------------------------------------
  567. DWORD
  568. UnBindIfEntry(
  569. PIF_TABLE pTable,
  570. DWORD dwIndex
  571. ) {
  572. DWORD dwErr;
  573. PIF_TABLE_ENTRY pite;
  574. dwErr = NO_ERROR;
  575. do {
  576. //
  577. // retrieve the interface to be unbound
  578. //
  579. pite = GetIfByIndex( pTable, dwIndex );
  580. if ( pite == NULL ) {
  581. TRACE1(IF, "unbinding interface: interface %d not found", dwIndex);
  582. return ERROR_INVALID_PARAMETER;
  583. }
  584. //
  585. // quit if interface is already unbound
  586. //
  587. if ( IF_IS_UNBOUND( pite ) ) {
  588. TRACE1( IF, "interface %d is already unbound", dwIndex );
  589. break;
  590. }
  591. //
  592. // if the interface was active (i.e. bound and enabled)
  593. // it is no longer, so remove it from the active list
  594. //
  595. if ( IF_IS_ENABLED( pite ) ) {
  596. RemoveEntryList( &pite->ITE_LinkByAddress );
  597. }
  598. pite->ITE_Flags &= ~ITEFLAG_BOUND;
  599. DeleteIfSocket( pite );
  600. BOOTP_FREE(pite->ITE_Binding);
  601. pite->ITE_Binding = NULL;
  602. } while(FALSE);
  603. return dwErr;
  604. }
  605. //----------------------------------------------------------------------------
  606. // Function: EnableIfEntry
  607. //
  608. // This function initiates BOOTP relay activity on the specified interface.
  609. // It assumes the interface table lock is held exclusively.
  610. //----------------------------------------------------------------------------
  611. DWORD
  612. EnableIfEntry(
  613. PIF_TABLE pTable,
  614. DWORD dwIndex
  615. ) {
  616. DWORD i, dwErr;
  617. PIF_TABLE_ENTRY pite;
  618. PIPBOOTP_IF_BINDING pib;
  619. PIPBOOTP_IP_ADDRESS paddr;
  620. dwErr = NO_ERROR;
  621. do {
  622. //
  623. // make certain the interface exists
  624. //
  625. pite = GetIfByIndex( pTable, dwIndex );
  626. if ( pite == NULL ) {
  627. TRACE1( IF, "enabling interface: interface %d not found", dwIndex );
  628. dwErr = ERROR_INVALID_PARAMETER;
  629. break;
  630. }
  631. //
  632. // make certain the interface is disabled
  633. //
  634. if ( IF_IS_ENABLED( pite ) ) {
  635. TRACE1( IF, "interface %d is already enabled", dwIndex );
  636. //
  637. // He shouldnt call us twice but we will still handle it
  638. //
  639. break;
  640. }
  641. pite->ITE_Flags |= ITEFLAG_ENABLED;
  642. //
  643. // if the interface was already bound, it is now active,
  644. // so place it on the active list
  645. //
  646. if ( IF_IS_BOUND( pite ) ) {
  647. //
  648. // insert the interface in the by-address list of interfaces
  649. //
  650. dwErr = InsertIfByAddress( pTable, pite );
  651. if (dwErr != NO_ERROR) {
  652. TRACE2(
  653. IF, "error %d inserting interface %d in active list",
  654. dwErr, dwIndex
  655. );
  656. pite->ITE_Flags &= ~ITEFLAG_ENABLED;
  657. break;
  658. }
  659. pib = pite->ITE_Binding;
  660. paddr = IPBOOTP_IF_ADDRESS_TABLE(pib);
  661. //
  662. // request notification of input events from Winsock
  663. //
  664. for (i = 0; i < pib->IB_AddrCount; i++, paddr++) {
  665. dwErr = WSAEventSelect(
  666. pite->ITE_Sockets[i], ig.IG_InputEvent, FD_READ
  667. );
  668. if (dwErr != NO_ERROR) {
  669. INT j;
  670. LPSTR lpszAddr = INET_NTOA(paddr->IA_Address);
  671. TRACE3(
  672. IF, "WSAEventSelect returned %d for interface %d (%s)",
  673. dwErr, dwIndex, lpszAddr
  674. );
  675. LOGERR1(EVENTSELECT_FAILED, lpszAddr, dwErr);
  676. RemoveEntryList(&pite->ITE_LinkByAddress);
  677. pite->ITE_Flags &= ~ITEFLAG_ENABLED;
  678. //
  679. // clear the requests for events
  680. //
  681. for (j = i - 1; j >= 0; j--) {
  682. dwErr = WSAEventSelect(
  683. pite->ITE_Sockets[j], ig.IG_InputEvent, 0
  684. );
  685. }
  686. break;
  687. }
  688. }
  689. if (i < pib->IB_AddrCount) { break; }
  690. }
  691. } while(FALSE);
  692. return dwErr;
  693. }
  694. //----------------------------------------------------------------------------
  695. // Function: ConfigureIfEntry
  696. //
  697. // modifies the configuration for an already-existing interface.
  698. // This assumes the table is locked for writing.
  699. //----------------------------------------------------------------------------
  700. DWORD
  701. ConfigureIfEntry(
  702. PIF_TABLE pTable,
  703. DWORD dwIndex,
  704. PVOID pConfig
  705. ) {
  706. DWORD dwErr, dwSize;
  707. PIF_TABLE_ENTRY pite;
  708. PIPBOOTP_IF_CONFIG picsrc, picdst;
  709. //
  710. // retrieve the interface to be reconfigured
  711. //
  712. pite = GetIfByIndex(pTable, dwIndex);
  713. if (pite == NULL) {
  714. TRACE1( IF, "configuring interface: interface %d not found", dwIndex );
  715. return ERROR_INVALID_PARAMETER;
  716. }
  717. do { // breakout loop
  718. //
  719. // compute the size needed to store the new configuration
  720. //
  721. picsrc = (PIPBOOTP_IF_CONFIG)pConfig;
  722. dwSize = IC_SIZEOF(picsrc);
  723. //
  724. // make sure the new parameters are valid
  725. //
  726. dwErr = ValidateIfConfig(pConfig);
  727. if (dwErr != NO_ERROR) {
  728. TRACE1(IF, "invalid config specified for interface %d", dwIndex);
  729. break;
  730. }
  731. //
  732. // allocate space for the new configuration
  733. //
  734. picdst = BOOTP_ALLOC(dwSize);
  735. if (picdst == NULL) {
  736. dwErr = GetLastError();
  737. TRACE3(
  738. IF, "error %d allocating %d bytes for interface %d config",
  739. dwErr, dwSize, dwIndex
  740. );
  741. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  742. break;
  743. }
  744. CopyMemory(picdst, picsrc, dwSize);
  745. if (pite->ITE_Config) { BOOTP_FREE(pite->ITE_Config); }
  746. pite->ITE_Config = picdst;
  747. dwErr = NO_ERROR;
  748. } while(FALSE);
  749. return dwErr;
  750. }
  751. //----------------------------------------------------------------------------
  752. // Function: DisableIfEntry
  753. //
  754. // This function stops RIP activaty on the specified interface.
  755. // It assumes the interface table is locked for writing.
  756. //----------------------------------------------------------------------------
  757. DWORD
  758. DisableIfEntry(
  759. PIF_TABLE pTable,
  760. DWORD dwIndex
  761. ) {
  762. DWORD i, dwErr;
  763. PIF_TABLE_ENTRY pite;
  764. PIPBOOTP_IF_BINDING pib;
  765. PIPBOOTP_IP_ADDRESS paddr;
  766. dwErr = NO_ERROR;
  767. do {
  768. //
  769. // make certain the interface exists
  770. //
  771. pite = GetIfByIndex( pTable, dwIndex );
  772. if ( pite == NULL ) {
  773. TRACE1( IF, "disabling interface: interface %d not found", dwIndex );
  774. dwErr = ERROR_INVALID_PARAMETER;
  775. break;
  776. }
  777. //
  778. // make certain the interface is enabled
  779. //
  780. if ( IF_IS_DISABLED( pite ) ) {
  781. TRACE1( IF, "interface %d is already disabled", dwIndex );
  782. //
  783. // This is NOT AN ERROR.
  784. //
  785. break;
  786. }
  787. //
  788. // if the interface was active (i.e. bound and enabled)
  789. // it isn't anymore, so deactivate it here.
  790. //
  791. if ( IF_IS_BOUND( pite ) ) {
  792. //
  793. // remove the interface from the by-address list
  794. //
  795. RemoveEntryList( &pite->ITE_LinkByAddress );
  796. //
  797. // tell Winsock to stop notifying us of input events
  798. //
  799. pib = pite->ITE_Binding;
  800. paddr = IPBOOTP_IF_ADDRESS_TABLE(pib);
  801. for (i = 0; i < pib->IB_AddrCount; i++) {
  802. WSAEventSelect(pite->ITE_Sockets[i], ig.IG_InputEvent, 0);
  803. }
  804. }
  805. //
  806. // clear the enabled flag on the interface
  807. //
  808. pite->ITE_Flags &= ~ITEFLAG_ENABLED;
  809. } while(FALSE);
  810. return dwErr;
  811. }
  812. //----------------------------------------------------------------------------
  813. // Function: GetIfByIndex
  814. //
  815. // returns the interface with the given index.
  816. // Assumes the table is locked.
  817. //----------------------------------------------------------------------------
  818. PIF_TABLE_ENTRY
  819. GetIfByIndex(
  820. PIF_TABLE pTable,
  821. DWORD dwIndex
  822. ) {
  823. DWORD dwErr;
  824. PIF_TABLE_ENTRY pite, pitefound = NULL;
  825. PLIST_ENTRY ple, phead;
  826. phead = pTable->IT_HashTableByIndex + IF_HASHVALUE( dwIndex );
  827. for ( ple = phead->Flink; ple != phead; ple = ple->Flink ) {
  828. pite = CONTAINING_RECORD(ple, IF_TABLE_ENTRY, ITE_HTLinkByIndex);
  829. if (pite->ITE_Index == dwIndex ) { pitefound = pite; break; }
  830. }
  831. return pitefound;
  832. }
  833. //----------------------------------------------------------------------------
  834. // Function: GetIfByAddress
  835. //
  836. // Returns the interface bound with the given address.
  837. // Assumes the table is locked for reading or writing.
  838. //----------------------------------------------------------------------------
  839. PIF_TABLE_ENTRY
  840. GetIfByAddress(
  841. PIF_TABLE pTable,
  842. DWORD dwAddress,
  843. PDWORD pdwAddrIndex
  844. ) {
  845. INT cmp;
  846. DWORD i, dwErr;
  847. PLIST_ENTRY ple, phead;
  848. PIPBOOTP_IF_BINDING pib;
  849. PIPBOOTP_IP_ADDRESS paddr;
  850. PIF_TABLE_ENTRY pite, pitefound = NULL;
  851. if ( pdwAddrIndex ) { *pdwAddrIndex = 0; }
  852. phead = &pTable->IT_ListByAddress;
  853. for ( ple = phead->Flink; ple != phead; ple = ple->Flink ) {
  854. pite = CONTAINING_RECORD(ple, IF_TABLE_ENTRY, ITE_LinkByAddress);
  855. pib = pite->ITE_Binding;
  856. paddr = IPBOOTP_IF_ADDRESS_TABLE(pib);
  857. for (i = 0; i < pib->IB_AddrCount; i++, paddr++) {
  858. if ( dwAddress == paddr->IA_Address ) { pitefound = pite; break; }
  859. }
  860. if (pitefound) {
  861. if (pdwAddrIndex) { *pdwAddrIndex = i; }
  862. break;
  863. }
  864. }
  865. return pitefound;
  866. }
  867. //----------------------------------------------------------------------------
  868. // Function: GetIfByListIndex
  869. //
  870. // This function is similar to GetIfByAddress in that it supports
  871. // three modes of retrieval, but it is different in that it looks
  872. // in the list of interfaces sorted by index.
  873. //----------------------------------------------------------------------------
  874. PIF_TABLE_ENTRY
  875. GetIfByListIndex(
  876. PIF_TABLE pTable,
  877. DWORD dwIndex,
  878. DWORD dwGetMode,
  879. PDWORD pdwErr
  880. ) {
  881. PIF_TABLE_ENTRY pite;
  882. PLIST_ENTRY ple, phead;
  883. if (pdwErr != NULL) { *pdwErr = NO_ERROR; }
  884. phead = &pTable->IT_ListByIndex;
  885. pite = NULL;
  886. //
  887. // return record at head of list if mode is GETMODE_FIRST;
  888. // if list is empty, return NULL.
  889. //
  890. if (dwGetMode == GETMODE_FIRST) {
  891. if (phead->Flink == phead) { return NULL; }
  892. else {
  893. ple = phead->Flink;
  894. return CONTAINING_RECORD(ple, IF_TABLE_ENTRY, ITE_LinkByIndex);
  895. }
  896. }
  897. //
  898. // get the entry requested
  899. //
  900. pite = GetIfByIndex(pTable, dwIndex);
  901. //
  902. // if mode is GETMODE_NEXT, return the item after the one retrieved
  903. //
  904. if (dwGetMode == GETMODE_NEXT && pite != NULL) {
  905. ple = &pite->ITE_LinkByIndex;
  906. //
  907. // if entry found is last one, return NULL,
  908. // otherwise return the following entry
  909. //
  910. if (ple->Flink == phead) {
  911. if (pdwErr != NULL) { *pdwErr = ERROR_NO_MORE_ITEMS; }
  912. pite = NULL;
  913. }
  914. else {
  915. ple = ple->Flink;
  916. pite = CONTAINING_RECORD(ple, IF_TABLE_ENTRY, ITE_LinkByIndex);
  917. }
  918. }
  919. return pite;
  920. }
  921. //----------------------------------------------------------------------------
  922. // Function: InsertIfByAddress
  923. //
  924. // This function inserts an interface in the list sorted by index
  925. // Assumes the table is locked for writing.
  926. //----------------------------------------------------------------------------
  927. DWORD
  928. InsertIfByAddress(
  929. PIF_TABLE pTable,
  930. PIF_TABLE_ENTRY pITE
  931. ) {
  932. INT cmp;
  933. PIF_TABLE_ENTRY pite;
  934. PIPBOOTP_IF_BINDING pib;
  935. PIPBOOTP_IP_ADDRESS paddr;
  936. PLIST_ENTRY pfl, phead;
  937. DWORD dwAddress, dwEntryAddr;
  938. if ( pITE == NULL || pITE->ITE_Binding == NULL ) {
  939. return ERROR_INVALID_PARAMETER;
  940. }
  941. pib = pITE->ITE_Binding;
  942. paddr = IPBOOTP_IF_ADDRESS_TABLE(pib);
  943. dwAddress = paddr->IA_Address;
  944. phead = &pTable->IT_ListByAddress;
  945. for ( pfl = phead->Flink; pfl != phead; pfl = pfl->Flink ) {
  946. pite = CONTAINING_RECORD( pfl, IF_TABLE_ENTRY, ITE_LinkByAddress );
  947. paddr = IPBOOTP_IF_ADDRESS_TABLE(pite->ITE_Binding);
  948. dwEntryAddr = paddr->IA_Address;
  949. if ( INET_CMP( dwAddress, dwEntryAddr, cmp ) < 0 ) { break; }
  950. else
  951. if (cmp == 0) { return ERROR_ALREADY_EXISTS; }
  952. }
  953. InsertTailList( pfl, &pITE->ITE_LinkByAddress );
  954. return NO_ERROR;
  955. }