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.

1011 lines
31 KiB

  1. /*++
  2. Copyright (c) 1994-1997 Microsoft Corporation
  3. Module Name: //KERNEL/RAZZLE3/src/sockets/tcpcmd/ipconfig/adaptlst.c
  4. Abstract:
  5. This module contains functions for retrieving adapter information from
  6. TCP/IP device driver
  7. Contents:
  8. GetAdapterList
  9. GetAdapterList2
  10. AddIpAddress
  11. AddIpAddressString
  12. ConvertIpAddressToString
  13. CopyString
  14. (CleanDescription)
  15. Author:
  16. Richard L Firth (rfirth) 20-May-1994
  17. Revision History:
  18. 20-May-1994 rfirth Created
  19. 30-Apr-97 MohsinA Cleaned Up.
  20. --*/
  21. #include "precomp.h"
  22. #pragma hdrstop
  23. #define OVERFLOW_COUNT 10
  24. //
  25. // prototypes
  26. //
  27. void CleanDescription(LPSTR);
  28. extern PIP_ADAPTER_ORDER_MAP APIENTRY GetAdapterOrderMap();
  29. //
  30. // functions
  31. //
  32. /*******************************************************************************
  33. *
  34. * GetAdapterList
  35. *
  36. * Returns a linked list of IP_ADAPTER_INFO structures. The adapter info is
  37. * queried from the TCP/IP stack. Only those instances corresponding to
  38. * physical adapters are returned
  39. *
  40. * This function only fills in the information in the IP_ADAPTER_INFO
  41. * structure pertaining to the physical adapter (like MAC address, adapter
  42. * type, etc.) and IP address info
  43. *
  44. * ENTRY nothing
  45. *
  46. * EXIT nothing
  47. *
  48. * RETURNS Success - pointer to linked list of IP_ADAPTER_INFO structures,
  49. * 0 terminated
  50. * Failure - NULL
  51. *
  52. * ASSUMES
  53. *
  54. ******************************************************************************/
  55. PIP_ADAPTER_INFO GetAdapterList()
  56. {
  57. TCP_REQUEST_QUERY_INFORMATION_EX req;
  58. TDIObjectID id;
  59. PIP_ADAPTER_INFO list = NULL, prev = NULL;
  60. PIP_ADAPTER_INFO this, UniList = NULL, tmp;
  61. UINT numberOfEntities;
  62. TDIEntityID* pEntity = NULL;
  63. TDIEntityID* entityList;
  64. UINT i;
  65. UINT j;
  66. DWORD status;
  67. DWORD inputLen;
  68. DWORD outputLen;
  69. PIP_ADAPTER_ORDER_MAP adapterOrderMap;
  70. PIP_UNIDIRECTIONAL_ADAPTER_ADDRESS pUniInfo=NULL;
  71. ULONG OutBufLen;
  72. //
  73. // get the list of entities supported by TCP/IP then make 2 passes on the
  74. // list. Pass 1 scans for IF_ENTITY's (interface entities perhaps?) which
  75. // describe adapter instances (physical and virtual). Once we have our list
  76. // of adapters, on pass 2 we look for CL_NL_ENTITY's (connection-less
  77. // network layer entities peut-etre?) which will give us the list of IP
  78. // addresses for the adapters we found in pass 1
  79. //
  80. entityList = GetEntityList(&numberOfEntities);
  81. if (!entityList) {
  82. DEBUG_PRINT(("GetAdapterList: failed to get entity list\n"));
  83. return NULL;
  84. }
  85. adapterOrderMap = GetAdapterOrderMap();
  86. if (!adapterOrderMap) {
  87. DEBUG_PRINT(("GetAdapterList: failed to get adapter order map\n"));
  88. ReleaseMemory(entityList);
  89. return NULL;
  90. }
  91. // ====================================================================
  92. // pass 1
  93. // ====================================================================
  94. for (i = 0, pEntity = entityList; i < numberOfEntities; ++i, ++pEntity) {
  95. DEBUG_PRINT(("Pass 1: Entity %lx [%s] Instance %ld\n",
  96. pEntity->tei_entity,
  97. entity$(pEntity->tei_entity),
  98. pEntity->tei_instance
  99. ));
  100. if (pEntity->tei_entity == IF_ENTITY) {
  101. //
  102. // IF_ENTITY: this entity/instance describes an adapter
  103. //
  104. DWORD isMib;
  105. BYTE info[sizeof(IFEntry) + MAX_ADAPTER_DESCRIPTION_LENGTH + 1];
  106. IFEntry* pIfEntry = (IFEntry*)info;
  107. int len;
  108. //
  109. // find out if this entity supports MIB requests
  110. //
  111. memset(&req, 0, sizeof(req));
  112. id.toi_entity = *pEntity;
  113. id.toi_class = INFO_CLASS_GENERIC;
  114. id.toi_type = INFO_TYPE_PROVIDER;
  115. id.toi_id = ENTITY_TYPE_ID;
  116. req.ID = id;
  117. inputLen = sizeof(req);
  118. outputLen = sizeof(isMib);
  119. status = WsControl(IPPROTO_TCP,
  120. WSCNTL_TCPIP_QUERY_INFO,
  121. (LPVOID)&req,
  122. &inputLen,
  123. (LPVOID)&isMib,
  124. &outputLen
  125. );
  126. if (status != TDI_SUCCESS) {
  127. //
  128. // unexpected results - bail out
  129. //
  130. DEBUG_PRINT(("GetAdapterList: WsControl(ENTITY_TYPE_ID): status = %ld, outputLen = %ld\n",
  131. status,
  132. outputLen
  133. ));
  134. // goto error_exit;
  135. continue;
  136. }
  137. if (isMib != IF_MIB) {
  138. //
  139. // entity doesn't support MIB requests - try another
  140. //
  141. DEBUG_PRINT(("GetAdapterList: Entity %lx, Instance %ld doesn't support MIB (%lx)\n",
  142. id.toi_entity.tei_entity,
  143. id.toi_entity.tei_instance,
  144. isMib
  145. ));
  146. continue;
  147. }
  148. //
  149. // MIB requests supported - query the adapter info
  150. //
  151. id.toi_class = INFO_CLASS_PROTOCOL;
  152. id.toi_id = IF_MIB_STATS_ID;
  153. memset(&req, 0, sizeof(req));
  154. req.ID = id;
  155. inputLen = sizeof(req);
  156. outputLen = sizeof(info);
  157. status = WsControl(IPPROTO_TCP,
  158. WSCNTL_TCPIP_QUERY_INFO,
  159. (LPVOID)&req,
  160. &inputLen,
  161. (LPVOID)&info,
  162. &outputLen
  163. );
  164. if (status != TDI_SUCCESS && status != ERROR_MORE_DATA) {
  165. //
  166. // unexpected results - bail out
  167. //
  168. DEBUG_PRINT(("GetAdapterList: WsControl(IF_MIB_STATS_ID) returns %ld\n",
  169. status
  170. ));
  171. // goto error_exit;
  172. continue;
  173. }
  174. #ifdef DBG
  175. if( MyTrace ){
  176. print_IFEntry( "GetAdapterList", pIfEntry );
  177. }
  178. #endif
  179. //
  180. // we only want physical adapters
  181. //
  182. if (!IS_INTERESTING_ADAPTER(pIfEntry)) {
  183. DEBUG_PRINT(("GetAdapterList: ignoring adapter #%ld [%s]\n",
  184. pIfEntry->if_index,
  185. if_type$(pIfEntry->if_type)
  186. ));
  187. continue;
  188. }
  189. //
  190. // got this adapter info ok. Create a new IP_ADAPTER_INFO and
  191. // fill in what we can
  192. //
  193. this = NEW(IP_ADAPTER_INFO);
  194. if (!this) {
  195. DEBUG_PRINT(("GetAdapterList: no mem for this IP_ADAPTER_INFO\n"));
  196. goto error_exit;
  197. }
  198. memset( this, 0, sizeof( IP_ADAPTER_INFO ) );
  199. len = (int) min(MAX_ADAPTER_DESCRIPTION_LENGTH,
  200. (size_t)pIfEntry->if_descrlen);
  201. strncpy(this->Description, pIfEntry->if_descr, len);
  202. this->Description[len] = 0;
  203. //
  204. // if the last word of the description is " Adapter", remove it (its
  205. // redundant) and if the description is terminated with a period,
  206. // remove that too
  207. //
  208. // CleanDescription(this->Description);
  209. len = (int) min(MAX_ADAPTER_ADDRESS_LENGTH,
  210. (size_t)pIfEntry->if_physaddrlen);
  211. this->AddressLength = (BYTE)len;
  212. memcpy(this->Address, pIfEntry->if_physaddr, len);
  213. this->Index = (UINT)pIfEntry->if_index;
  214. this->Type = (UINT)pIfEntry->if_type;
  215. //
  216. // add this IP_ADAPTER_INFO to our list.
  217. // We build the list sorted according to the adapter order
  218. // specified for TCP/IP under its Linkage key.
  219. // In order to put this new entry in the right place in the list,
  220. // we determine its position in the adapter-order, store that
  221. // position in the (unused) 'ComboIndex' field, and then use that
  222. // index for comparison on subsequent insertions.
  223. // If this IP_ADAPTER_INFO doesn't appear in our list at all,
  224. // we put it at the end of the current list.
  225. //
  226. for (j = 0; j < adapterOrderMap->NumAdapters; j++) {
  227. if (adapterOrderMap->AdapterOrder[j] == this->Index) {
  228. break;
  229. }
  230. }
  231. //
  232. // 'j' now contains the 'order' for the new entry.
  233. // Put the entry in the right place in the list.
  234. //
  235. this->ComboIndex = j;
  236. for (prev = NULL, this->Next = list;
  237. this->Next;
  238. prev = this->Next, this->Next = this->Next->Next) {
  239. if (this->ComboIndex >= this->Next->ComboIndex) {
  240. continue;
  241. } else {
  242. break;
  243. }
  244. }
  245. if (prev) { prev->Next = this; }
  246. if (list == this->Next) { list = this; }
  247. }
  248. }
  249. OutBufLen = sizeof(IP_UNIDIRECTIONAL_ADAPTER_ADDRESS) + MAX_UNI_ADAPTERS*sizeof(IPAddr);
  250. pUniInfo = MALLOC(OutBufLen);
  251. if(!pUniInfo) {
  252. printf("GetAdapterList: IP_UNIDIRECTIONAL_ADAPTER_ADDRESS resource failure= %ld\n",status);
  253. DEBUG_PRINT(("GetAdapterList: IP_UNIDIRECTIONAL_ADAPTER_ADDRESS resource failure= %ld\n",status));
  254. goto error_exit;
  255. }
  256. pUniInfo->NumAdapters = 0;
  257. status = GetUniDirectionalAdapterInfo(pUniInfo, &OutBufLen);
  258. if (status == ERROR_MORE_DATA) {
  259. OutBufLen = sizeof(IP_UNIDIRECTIONAL_ADAPTER_ADDRESS)+pUniInfo->NumAdapters*sizeof(IPAddr);
  260. pUniInfo = MALLOC(OutBufLen);
  261. if(!pUniInfo) {
  262. DEBUG_PRINT(("GetAdapterList: IP_UNIDIRECTIONAL_ADAPTER_ADDRESS resource failure= %ld\n",status));
  263. goto error_exit;
  264. }
  265. status = GetUniDirectionalAdapterInfo(pUniInfo, &OutBufLen);
  266. }
  267. if(status != NO_ERROR) {
  268. DEBUG_PRINT(("GetAdapterList: GetUniDirectionalAdapterInfo returned status= %ld\n",status));
  269. goto error_exit;
  270. }
  271. // ====================================================================
  272. // pass 2
  273. // ====================================================================
  274. for (i = 0, pEntity = entityList; i < numberOfEntities; ++i, ++pEntity) {
  275. DEBUG_PRINT(("Pass 2: Entity %lx [%s] Instance %ld\n",
  276. pEntity->tei_entity,
  277. entity$(pEntity->tei_entity),
  278. pEntity->tei_instance
  279. ));
  280. if (pEntity->tei_entity == CL_NL_ENTITY) {
  281. IPSNMPInfo info;
  282. DWORD type;
  283. //
  284. // first off, see if this network layer entity supports IP
  285. //
  286. memset(&req, 0, sizeof(req));
  287. id.toi_entity = *pEntity;
  288. id.toi_class = INFO_CLASS_GENERIC;
  289. id.toi_type = INFO_TYPE_PROVIDER;
  290. id.toi_id = ENTITY_TYPE_ID;
  291. req.ID = id;
  292. inputLen = sizeof(req);
  293. outputLen = sizeof(type);
  294. status = WsControl(IPPROTO_TCP,
  295. WSCNTL_TCPIP_QUERY_INFO,
  296. (LPVOID)&req,
  297. &inputLen,
  298. (LPVOID)&type,
  299. &outputLen
  300. );
  301. if (status != TDI_SUCCESS) {
  302. //
  303. // unexpected results - bail out
  304. //
  305. DEBUG_PRINT(("GetAdapterList: WsControl(ENTITY_TYPE_ID): status = %ld, outputLen = %ld\n",
  306. status,
  307. outputLen
  308. ));
  309. // goto error_exit;
  310. continue;
  311. }
  312. if (type != CL_NL_IP) {
  313. //
  314. // nope, not IP - try next one
  315. //
  316. DEBUG_PRINT(("GetAdapterList: CL_NL_ENTITY #%ld not CL_NL_IP\n",
  317. pEntity->tei_instance
  318. ));
  319. continue;
  320. }
  321. //
  322. // okay, this NL provider supports IP. Let's get them addresses:
  323. // First we find out how many by getting the SNMP stats and looking
  324. // at the number of addresses supported by this interface
  325. //
  326. memset(&req, 0, sizeof(req));
  327. id.toi_class = INFO_CLASS_PROTOCOL;
  328. id.toi_id = IP_MIB_STATS_ID;
  329. req.ID = id;
  330. inputLen = sizeof(req);
  331. outputLen = sizeof(info);
  332. status = WsControl(IPPROTO_TCP,
  333. WSCNTL_TCPIP_QUERY_INFO,
  334. (LPVOID)&req,
  335. &inputLen,
  336. (LPVOID)&info,
  337. &outputLen
  338. );
  339. if ((status != TDI_SUCCESS) || (outputLen != sizeof(info))) {
  340. //
  341. // unexpected results - bail out
  342. //
  343. DEBUG_PRINT(("GetAdapterList: WsControl(IP_MIB_STATS_ID): status = %ld, outputLen = %ld\n",
  344. status,
  345. outputLen
  346. ));
  347. // goto error_exit;
  348. continue;
  349. }
  350. //
  351. // get the IP addresses & subnet masks
  352. //
  353. if (info.ipsi_numaddr) {
  354. //
  355. // this interface has some addresses. What are they?
  356. //
  357. LPVOID buffer;
  358. UINT numberOfAddresses;
  359. IPAddrEntry* pAddr;
  360. UINT i;
  361. outputLen = (info.ipsi_numaddr + OVERFLOW_COUNT) *
  362. sizeof(IPAddrEntry);
  363. buffer = (LPVOID)NEW_MEMORY((size_t)outputLen);
  364. if (!buffer) {
  365. DEBUG_PRINT(("GetAdapterList:NEW_MEMORY failed.\n" ));
  366. goto error_exit;
  367. }
  368. memset(&req, 0, sizeof(req));
  369. id.toi_id = IP_MIB_ADDRTABLE_ENTRY_ID;
  370. req.ID = id;
  371. inputLen = sizeof(req);
  372. status = WsControl(IPPROTO_TCP,
  373. WSCNTL_TCPIP_QUERY_INFO,
  374. (LPVOID)&req,
  375. &inputLen,
  376. (LPVOID)buffer,
  377. &outputLen
  378. );
  379. if (status != TDI_SUCCESS) {
  380. //
  381. // unexpected results - bail out
  382. //
  383. DEBUG_PRINT(("GetAdapterList: WsControl(IP_MIB_ADDRTABLE_ENTRY_ID): status = %ld, outputLen = %ld\n",
  384. status,
  385. outputLen
  386. ));
  387. // goto error_exit;
  388. ReleaseMemory((void*)buffer);
  389. continue;
  390. }
  391. //
  392. // now loop through this list of IP addresses, applying them
  393. // to the correct adapter
  394. //
  395. numberOfAddresses = min((UINT)(outputLen / sizeof(IPAddrEntry)),
  396. (UINT)info.ipsi_numaddr
  397. );
  398. DEBUG_PRINT(("GetAdapterList: %d IP addresses\n", numberOfAddresses));
  399. pAddr = (IPAddrEntry*)buffer;
  400. for (i = 0; i < numberOfAddresses; ++i, ++pAddr) {
  401. PIP_ADAPTER_INFO pAdapterInfo;
  402. DEBUG_PRINT(("GetAdapterList: IP address %d.%d.%d.%d, index %ld, context %ld\n",
  403. ((LPBYTE)&pAddr->iae_addr)[0] & 0xff,
  404. ((LPBYTE)&pAddr->iae_addr)[1] & 0xff,
  405. ((LPBYTE)&pAddr->iae_addr)[2] & 0xff,
  406. ((LPBYTE)&pAddr->iae_addr)[3] & 0xff,
  407. pAddr->iae_index,
  408. pAddr->iae_context
  409. ));
  410. for (pAdapterInfo = list; pAdapterInfo; pAdapterInfo = pAdapterInfo->Next) {
  411. if (pAdapterInfo->Index == (UINT)pAddr->iae_index) {
  412. DEBUG_PRINT(("GetAdapterList: adding IP address %d.%d.%d.%d, index %d, context %d\n",
  413. ((LPBYTE)&pAddr->iae_addr)[0] & 0xff,
  414. ((LPBYTE)&pAddr->iae_addr)[1] & 0xff,
  415. ((LPBYTE)&pAddr->iae_addr)[2] & 0xff,
  416. ((LPBYTE)&pAddr->iae_addr)[3] & 0xff,
  417. pAddr->iae_index,
  418. pAddr->iae_context
  419. ));
  420. //
  421. // Append the IP address to the list.
  422. // Note that this operation preserves the order
  423. // of the IP address list returned by TCP/IP.
  424. // This is important because that list contains
  425. // entries listed in the *reverse* of the order
  426. // specified for each adapter. A number of clients
  427. // depend upon this fact when calling this and
  428. // other API routines.
  429. //
  430. if (!AddIpAddress(&pAdapterInfo->IpAddressList,
  431. pAddr->iae_addr,
  432. pAddr->iae_mask,
  433. pAddr->iae_context
  434. )) {
  435. ReleaseMemory((void*)buffer);
  436. goto error_exit;
  437. }
  438. for (j = 0; j < pUniInfo->NumAdapters ; j++) {
  439. if (pAddr->iae_index == pUniInfo->Address[j] ) {
  440. //
  441. // Use DhcpEnabled field as a temporary
  442. // storage to remember the type
  443. //
  444. pAdapterInfo->DhcpEnabled = IF_TYPE_RECEIVE_ONLY;
  445. break;
  446. }
  447. }
  448. break;
  449. }
  450. }
  451. }
  452. ReleaseMemory((void*)buffer);
  453. }
  454. //
  455. // get the gateway server IP address(es)
  456. //
  457. if (info.ipsi_numroutes) {
  458. IPRouteEntry* routeTable;
  459. IPRouteEntry* pRoute;
  460. UINT numberOfRoutes;
  461. UINT i;
  462. int moreRoutes = TRUE;
  463. memset(&req, 0, sizeof(req));
  464. id.toi_id = IP_MIB_RTTABLE_ENTRY_ID;
  465. req.ID = id;
  466. inputLen = sizeof(req);
  467. outputLen = sizeof(IPRouteEntry) * info.ipsi_numroutes;
  468. routeTable = NULL;
  469. //
  470. // the route table may have grown since we got the SNMP stats
  471. //
  472. while (moreRoutes) {
  473. DWORD previousOutputLen;
  474. previousOutputLen = outputLen;
  475. if (routeTable) {
  476. ReleaseMemory((void*)routeTable);
  477. routeTable = NULL;
  478. }
  479. routeTable = (IPRouteEntry*)NEW_MEMORY((size_t)outputLen);
  480. if (!routeTable) {
  481. goto error_exit;
  482. }
  483. status = WsControl(IPPROTO_TCP,
  484. WSCNTL_TCPIP_QUERY_INFO,
  485. (LPVOID)&req,
  486. &inputLen,
  487. (LPVOID)routeTable,
  488. &outputLen
  489. );
  490. if (status != TDI_SUCCESS) {
  491. //
  492. // unexpected results - bail out
  493. //
  494. DEBUG_PRINT(("GetAdapterList: WsControl(IP_MIB_RTTABLE_ENTRY_ID): status = %ld, outputLen = %ld\n",
  495. status,
  496. outputLen
  497. ));
  498. if (status == ERROR_MORE_DATA) {
  499. TCP_REQUEST_QUERY_INFORMATION_EX statsReq;
  500. IPSNMPInfo statsInfo;
  501. DWORD inLen;
  502. DWORD outLen;
  503. memset(&statsReq, 0, sizeof(statsReq));
  504. id.toi_id = IP_MIB_STATS_ID;
  505. statsReq.ID = id;
  506. inLen = sizeof(statsReq);
  507. outLen = sizeof(statsInfo);
  508. status = WsControl( IPPROTO_TCP,
  509. WSCNTL_TCPIP_QUERY_INFO,
  510. (LPVOID)&statsReq,
  511. &inLen,
  512. (LPVOID)&statsInfo,
  513. &outLen);
  514. if (status != TDI_SUCCESS || outLen != sizeof(statsInfo)) {
  515. ReleaseMemory((void*)routeTable);
  516. goto error_exit;
  517. } else {
  518. outputLen = sizeof(IPRouteEntry) * statsInfo.ipsi_numroutes;
  519. }
  520. } else {
  521. ReleaseMemory((void*)routeTable);
  522. goto error_exit;
  523. }
  524. }
  525. if (outputLen <= previousOutputLen) {
  526. moreRoutes = FALSE;
  527. }
  528. }
  529. numberOfRoutes = (UINT)(outputLen / sizeof(IPRouteEntry));
  530. for (i = 0, pRoute = routeTable; i < numberOfRoutes; ++i, ++pRoute)
  531. {
  532. //
  533. // the gateway address has a destination of 0.0.0.0
  534. //
  535. if (pRoute->ire_dest == INADDR_ANY) {
  536. PIP_ADAPTER_INFO pAdapterInfo = list;
  537. for (; pAdapterInfo; pAdapterInfo = pAdapterInfo->Next) {
  538. if (pAdapterInfo->Index == (UINT)pRoute->ire_index) {
  539. TRACE_PRINT(("GetAdapterList: gw=0x%08x.\n",
  540. pRoute->ire_nexthop ));
  541. if (!AddIpAddress(&pAdapterInfo->GatewayList,
  542. pRoute->ire_nexthop,
  543. //
  544. // gateway IP address doesn't
  545. // have corresponding IP mask
  546. //
  547. INADDR_ANY,
  548. 0
  549. )) {
  550. ReleaseMemory((void*)routeTable);
  551. goto error_exit;
  552. }
  553. // MohsinA, 22-Jul-97.
  554. // break;
  555. }
  556. }
  557. }
  558. }
  559. ReleaseMemory((void*)routeTable);
  560. }
  561. }
  562. }
  563. // ====================================================================
  564. ReleaseMemory((void*)entityList);
  565. ReleaseMemory(adapterOrderMap);
  566. //
  567. // If there are any unidirectional adapters
  568. // move them to the end of the list
  569. //
  570. tmp = list;
  571. if (pUniInfo->NumAdapters) {
  572. this = list;
  573. prev = NULL;
  574. while (this) {
  575. if (this->DhcpEnabled == IF_TYPE_RECEIVE_ONLY) {
  576. //
  577. // Remove "this" from the list
  578. //
  579. if (prev) {
  580. prev->Next = this->Next;
  581. } else {
  582. prev = this->Next;
  583. list = this->Next;
  584. }
  585. tmp = this->Next;
  586. //
  587. // Restore DhcbEnabled
  588. //
  589. this->DhcpEnabled = FALSE;
  590. //
  591. // Chain this to list of TV adapters
  592. //
  593. this->Next = UniList;
  594. UniList = this;
  595. this = tmp;
  596. } else {
  597. prev = this;
  598. this = this->Next;
  599. }
  600. }
  601. //
  602. // Insert UniList at the end.
  603. //
  604. if (prev) {
  605. prev->Next = UniList;
  606. } else {
  607. ASSERT(list == NULL);
  608. list = UniList;
  609. }
  610. }
  611. FREE(pUniInfo);
  612. return list;
  613. error_exit:
  614. DEBUG_PRINT(("GetAdapterList: <= failed\n"));
  615. if (entityList) {
  616. ReleaseMemory((void*)entityList);
  617. }
  618. if (adapterOrderMap) {
  619. ReleaseMemory(adapterOrderMap);
  620. }
  621. if (pUniInfo) {
  622. FREE(pUniInfo);
  623. }
  624. KillAdapterInfo(list);
  625. return NULL;
  626. }
  627. /*******************************************************************************
  628. *
  629. * AddIpAddress
  630. *
  631. * Adds an IP_ADDR_STRING to a list. If the input IP_ADDR_STRING is empty this
  632. * is filled in, else a new IP_ADDR_STRING is allocated and chained to the
  633. * input IP_ADDR_STRING
  634. *
  635. * ENTRY AddressList - pointer to IP_ADDR which may or may not already hold
  636. * an IP address
  637. * Address - IP address to add
  638. * Mask - corresponding IP subnet mask
  639. * Context - address context
  640. *
  641. * EXIT AddressList - updated with new info
  642. *
  643. * RETURNS Success - 1
  644. * Failure - 0
  645. *
  646. * ASSUMES 1. INADDR_ANY (ulong 0) indicates inactive IP address
  647. *
  648. ******************************************************************************/
  649. int AddIpAddress(PIP_ADDR_STRING AddressList, DWORD Address, DWORD Mask, DWORD Context)
  650. {
  651. PIP_ADDR_STRING ipAddr;
  652. if (AddressList->IpAddress.String[0]) {
  653. for (ipAddr = AddressList; ipAddr->Next; ipAddr = ipAddr->Next) {
  654. ;
  655. }
  656. ipAddr->Next = NEW(IP_ADDR_STRING);
  657. if (!ipAddr->Next) {
  658. DEBUG_PRINT(("AddIpAddress: failed to allocate memory for IP_ADDR_STRING\n"));
  659. return FALSE;
  660. }
  661. ipAddr = ipAddr->Next;
  662. } else {
  663. ipAddr = AddressList;
  664. }
  665. ConvertIpAddressToString(Address, ipAddr->IpAddress.String);
  666. ConvertIpAddressToString(Mask, ipAddr->IpMask.String);
  667. ipAddr->Context = Context;
  668. ipAddr->Next = NULL;
  669. return TRUE;
  670. }
  671. /*******************************************************************************
  672. *
  673. * AddIpAddressString
  674. *
  675. * Same as AddIpAddress, except the arguments are already converted to strings
  676. *
  677. * ENTRY AddressList - pointer to IP_ADDR which may or may not already hold
  678. * an IP address
  679. * Address - IP address to add, as a string
  680. * Mask - corresponding IP subnet mask, as a string
  681. *
  682. * EXIT AddressList - updated with new info
  683. *
  684. * RETURNS Success - 1
  685. * Failure - 0
  686. *
  687. * ASSUMES nothing
  688. *
  689. ******************************************************************************/
  690. int AddIpAddressString(PIP_ADDR_STRING AddressList, LPSTR Address, LPSTR Mask)
  691. {
  692. PIP_ADDR_STRING ipAddr;
  693. if (AddressList->IpAddress.String[0]) {
  694. for (ipAddr = AddressList; ipAddr->Next; ipAddr = ipAddr->Next) {
  695. if (!strncmp(ipAddr->IpAddress.String, Address, sizeof(ipAddr->IpAddress.String))) {
  696. return FALSE;
  697. }
  698. }
  699. if (!strncmp(ipAddr->IpAddress.String, Address, sizeof(ipAddr->IpAddress.String))) {
  700. return FALSE;
  701. }
  702. ipAddr->Next = NEW(IP_ADDR_STRING);
  703. if (!ipAddr->Next) {
  704. DEBUG_PRINT(("AddIpAddressString: failed to allocate memory for IP_ADDR_STRING\n"));
  705. return FALSE;
  706. }
  707. ipAddr = ipAddr->Next;
  708. } else {
  709. ipAddr = AddressList;
  710. }
  711. CopyString(ipAddr->IpAddress.String, sizeof(ipAddr->IpAddress.String), Address);
  712. CopyString(ipAddr->IpMask.String, sizeof(ipAddr->IpMask.String), Mask);
  713. return TRUE;
  714. }
  715. /*******************************************************************************
  716. *
  717. * ConvertIpAddressToString
  718. *
  719. * Converts a DWORD IP address or subnet mask to dotted decimal string
  720. *
  721. * ENTRY IpAddress - IP Address to convert
  722. * String - pointer to place to store dotted decimal string
  723. *
  724. * EXIT String contains ASCII representation of IpAddress
  725. *
  726. * RETURNS nothing
  727. *
  728. * ASSUMES 1. IP address fits in a DWORD
  729. *
  730. ******************************************************************************/
  731. VOID ConvertIpAddressToString(DWORD IpAddress, LPSTR String)
  732. {
  733. IP_ADDRESS ipAddr;
  734. ipAddr.d = IpAddress;
  735. sprintf(String,
  736. "%d.%d.%d.%d",
  737. ipAddr.b[0],
  738. ipAddr.b[1],
  739. ipAddr.b[2],
  740. ipAddr.b[3]
  741. );
  742. }
  743. /*******************************************************************************
  744. *
  745. * CopyString
  746. *
  747. * Copies a string to a buffer. If the buffer would overflow, the string is
  748. * truncated
  749. *
  750. * ENTRY Destination - destination buffer to copy to
  751. * DestinationLength - size of Destination
  752. * Source - source string to copy
  753. *
  754. * EXIT Destination updated
  755. *
  756. * RETURNS nothing
  757. *
  758. * ASSUMES
  759. *
  760. ******************************************************************************/
  761. VOID CopyString(LPSTR Destination, DWORD DestinationLength, LPSTR Source)
  762. {
  763. DWORD maximumCharacters = min(DestinationLength - 1, STRLEN(Source));
  764. strncpy(Destination, Source, maximumCharacters);
  765. Destination[maximumCharacters] = '\0';
  766. }
  767. /*******************************************************************************
  768. *
  769. * CleanDescription
  770. *
  771. * Given an adapter description string retrieved from TCP/IP, remove the
  772. * trailing substring " Adapter". If there is a trailing period, remove that
  773. * too
  774. *
  775. * ENTRY String - pointer to description string to clean up
  776. *
  777. * EXIT String - possibly bits removed
  778. *
  779. * RETURNS voidsville
  780. *
  781. * ASSUMES
  782. *
  783. ******************************************************************************/
  784. void CleanDescription(LPSTR String)
  785. {
  786. int len = STRLEN(String);
  787. if (String[len - 1] == '.') {
  788. String[--len] = 0;
  789. }
  790. if (!STRICMP(String + len - (sizeof(" Adapter") - 1), " Adapter")) {
  791. len -= sizeof(" Adapter") - 1;
  792. String[len] = 0;
  793. }
  794. }