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.

5830 lines
172 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name: //KERNEL/RAZZLE3/src/sockets/tcpcmd/ipconfigext/ipcfgdll/ipconfig.c
  4. SYNOPSIS: IPCFGDLL.DLL exports routines
  5. Abstract:
  6. Author: Richard L Firth (rfirth) 05-Feb-1994
  7. Revision History:
  8. 05-Feb-1994 rfirth
  9. Created
  10. 04-Mar-1994 rfirth
  11. * Pick non-Dhcp registry values if DHCP not enabled
  12. * TCP and IP have been consolidated
  13. 27-Apr-1994 rfirth
  14. * added /release and /renew
  15. 06-Aug-1994 rfirth
  16. * Get IP address values from TCP/IP stack, not registry
  17. 30-Apr-97 MohsinA
  18. * Cleaning up for NT50.
  19. 17-Jan-98 RameshV
  20. * Removed ScopeId display as new UI does not have this...
  21. * Made ReadRegistryIpAddrString read both MULTI_SZ and REG_SZ
  22. * Changed domainname and Dns server list from global to per-adapter
  23. * Display DhcpServer only if address is NOT autoconfigured..
  24. * AutoconfigEnabled is decided based on regval "AddressType"
  25. * Friendly names stubs are used....
  26. * Error codes are converted first thru system library..
  27. 06-Mar-98 chunye
  28. * Made this a DLL for support IPHLPAPI etc.
  29. --*/
  30. #include "precomp.h"
  31. #include "ipcfgmsg.h"
  32. #include <iprtrmib.h>
  33. #include <ws2tcpip.h> // for in6addr_any
  34. #include <ntddip.h>
  35. #include <ntddip6.h>
  36. #include <iphlpstk.h>
  37. #include <nhapi.h>
  38. #include <netconp.h>
  39. //
  40. // manifests
  41. //
  42. #define DEVICE_PREFIX "\\Device\\"
  43. #define TCPIP_DEVICE_PREFIX "\\Device\\Tcpip_"
  44. const CHAR c_szDevice[] = "\\Device\\";
  45. const CHAR c_szDeviceTcpip[] = "\\Device\\Tcpip_";
  46. const WCHAR c_szDeviceNdiswanIp[] = L"\\Device\\NdiswanIp";
  47. #define INITIAL_CAPABILITY 0x00000001
  48. #define TCPIP_CAPABILITY 0x00000002
  49. #define NETBT_CAPABILITY 0x00000004
  50. #define STRING_ARRAY_DELIMITERS " \t,;"
  51. #define MSG_NO_MESSAGE 0
  52. #define KEY_TCP 1
  53. #define KEY_NBT 2
  54. #define KEY_TCP6 3
  55. #define BNODE BROADCAST_NODETYPE
  56. #define PNODE PEER_TO_PEER_NODETYPE
  57. #define MNODE MIXED_NODETYPE
  58. #define HNODE HYBRID_NODETYPE
  59. #define MAX_FRIENDLY_NAME_LENGTH 80
  60. #ifdef DBG
  61. #define SET_DHCP_MODE 1
  62. #define SET_AUTO_MODE 2
  63. #endif
  64. // ========================================================================
  65. // macros
  66. // ========================================================================
  67. #define REG_OPEN_KEY(_hKey, _lpSubKey, _phkResult) \
  68. RegOpenKeyEx(_hKey, _lpSubKey, 0, KEY_READ, _phkResult)
  69. #define ALIGN_DOWN(length, type) \
  70. ((ULONG)(length) & ~(sizeof(type) - 1))
  71. #define ALIGN_UP(length, type) \
  72. (ALIGN_DOWN(((ULONG)(length) + sizeof(type) - 1), type))
  73. #define ALIGN_DOWN_PTR(length, type) \
  74. ((ULONG_PTR)(length) & ~(sizeof(type) - 1))
  75. #define ALIGN_UP_PTR(length, type) \
  76. (ALIGN_DOWN_PTR(((ULONG_PTR)(length) + sizeof(type) - 1), type))
  77. // ========================================================================
  78. // types
  79. // ========================================================================
  80. typedef struct {
  81. DWORD Message;
  82. LPSTR String;
  83. } MESSAGE_STRING, *PMESSAGE_STRING;
  84. #define MAX_STRING_LIST_LENGTH 32 // arbitrary
  85. // ========================================================================
  86. // macros
  87. // ========================================================================
  88. // #define IS_ARG(c) (((c) == '-') || ((c) == '/'))
  89. // #define ReleaseMemory(p) LocalFree((HLOCAL)(p))
  90. // #define MAP_YES_NO(i) ((i) ? MISC_MESSAGE(MI_YES) : MISC_MESSAGE(MI_NO))
  91. #define ZERO_IP_ADDRESS(a) !strcmp((a), "0.0.0.0")
  92. // ========================================================================
  93. // prototypes
  94. // ========================================================================
  95. BOOL Initialize(PDWORD);
  96. VOID LoadMessages(VOID);
  97. VOID LoadMessageTable(PMESSAGE_STRING, UINT);
  98. BOOL ConvertOemToUnicode(LPSTR, LPWSTR);
  99. BOOL WriteRegistryDword(HKEY hKey, LPSTR szParameter, DWORD *pdwValue );
  100. BOOL WriteRegistryMultiString(HKEY, LPSTR, LPSTR);
  101. static
  102. BOOL OpenAdapterKey(DWORD, const LPSTR, REGSAM, PHKEY);
  103. BOOL MyReadRegistryDword(HKEY, LPSTR, LPDWORD);
  104. BOOL ReadRegistryString(HKEY, LPSTR, LPSTR, LPDWORD);
  105. BOOL ReadRegistryOemString(HKEY, LPWSTR, LPSTR, LPDWORD);
  106. BOOL ReadRegistryIpAddrString(HKEY, LPSTR, PIP_ADDR_STRING);
  107. BOOL GetDnsServerList(PIP_ADDR_STRING);
  108. LPSTR* GetBoundAdapterList(HKEY);
  109. LPSTR MapNodeType(UINT);
  110. LPSTR MapNodeTypeEx(UINT);
  111. LPSTR MapAdapterType(UINT);
  112. LPSTR MapAdapterTypeEx(UINT);
  113. LPSTR MapAdapterAddress(PIP_ADAPTER_INFO, LPSTR);
  114. LPSTR MapTime(PIP_ADAPTER_INFO, DWORD_PTR);
  115. LPSTR MapTimeEx(PPIP_ADAPTER_INFO, DWORD_PTR);
  116. LPSTR MapScopeId(PVOID);
  117. VOID KillFixedInfo(PFIXED_INFO);
  118. VOID KillPerAdapterInfo(PIP_PER_ADAPTER_INFO);
  119. VOID KillAdapterAddresses(PIP_ADAPTER_ADDRESSES);
  120. VOID Terminate(VOID);
  121. LPVOID GrabMemory(DWORD);
  122. VOID DisplayMessage(BOOL, DWORD, ...);
  123. BOOL IsIncluded(DWORD Context, DWORD contextlist[], int len_contextlist);
  124. BOOL ReadRegistryList(HKEY Key, LPSTR ParameterName,
  125. DWORD NumList[], int *MaxList);
  126. DWORD GetIgmpList(DWORD NTEAddr, DWORD *pIgmpList, PULONG dwOutBufLen);
  127. DWORD WINAPI GetIpAddrTable(PMIB_IPADDRTABLE, PULONG, BOOL);
  128. // ========================================================================
  129. // data
  130. // ========================================================================
  131. HKEY TcpipLinkageKey = INVALID_HANDLE_VALUE;
  132. HKEY TcpipParametersKey = INVALID_HANDLE_VALUE;
  133. HKEY NetbtParametersKey = INVALID_HANDLE_VALUE;
  134. HKEY NetbtInterfacesKey = INVALID_HANDLE_VALUE;
  135. // PHRLANCONNECTIONNAMEFROMGUIDORPATH HrLanConnectionNameFromGuid = NULL;
  136. // HANDLE hNetMan = NULL;
  137. //
  138. // Note: The following variable caches whether IPv6 was installed and running
  139. // at the time GetAdaptersAddresses() was called. If multiple threads
  140. // are calling GetAdaptersAddresses() during an install/uninstall, its
  141. // value may change. However, this is not really a problem. The set of
  142. // IPv6 DNS server addresses may or may not be present on an interface,
  143. // but this is the same as the behavior of the set of IPv6 addresses, which
  144. // doesn't use this variable.
  145. //
  146. BOOL bIp6DriverInstalled;
  147. #ifdef DBG
  148. UINT uChangeMode = 0;
  149. #endif
  150. #define FIELD_JUSTIFICATION_TEXT " "
  151. // ========================================================================
  152. // MESSAGE_STRING arrays - contain internationalizable strings loaded from this
  153. // module. If a load error occurs, we use the English language defaults
  154. // ========================================================================
  155. LPSTR NodeTypesEx[] = {
  156. "",
  157. "Broadcast",
  158. "Peer-Peer",
  159. "Mixed",
  160. "Hybrid"
  161. };
  162. MESSAGE_STRING NodeTypes[] =
  163. {
  164. MSG_NO_MESSAGE, TEXT(""),
  165. MSG_BNODE, TEXT("Broadcast"),
  166. MSG_PNODE, TEXT("Peer-Peer"),
  167. MSG_MNODE, TEXT("Mixed"),
  168. MSG_HNODE, TEXT("Hybrid")
  169. };
  170. #define NUMBER_OF_NODE_TYPES (sizeof(NodeTypes)/sizeof(NodeTypes[0]))
  171. #define FIRST_NODE_TYPE 1
  172. #define LAST_NODE_TYPE 4
  173. LPSTR AdapterTypesEx[] = {
  174. "Other",
  175. "Ethernet",
  176. "Token Ring",
  177. "FDDI",
  178. "PPP",
  179. "Loopback",
  180. "SLIP"
  181. };
  182. MESSAGE_STRING AdapterTypes[] =
  183. {
  184. MSG_IF_TYPE_OTHER, TEXT("Other"),
  185. MSG_IF_TYPE_ETHERNET, TEXT("Ethernet"),
  186. MSG_IF_TYPE_TOKEN_RING, TEXT("Token Ring"),
  187. MSG_IF_TYPE_FDDI, TEXT("FDDI"),
  188. MSG_IF_TYPE_PPP, TEXT("PPP"),
  189. MSG_IF_TYPE_LOOPBACK, TEXT("Loopback"),
  190. MSG_IF_TYPE_SLIP, TEXT("SLIP")
  191. };
  192. #define NUMBER_OF_ADAPTER_TYPES (sizeof(AdapterTypes)/sizeof(AdapterTypes[0]))
  193. MESSAGE_STRING MiscMessages[] =
  194. {
  195. MSG_YES, TEXT("Yes"),
  196. MSG_NO, TEXT("No"),
  197. MSG_INIT_FAILED, TEXT("Failed to initialize"),
  198. MSG_TCP_NOT_RUNNING, TEXT("TCP/IP is not running on this system"),
  199. MSG_REG_BINDINGS_ERROR, TEXT("Cannot access adapter bindings registry key"),
  200. MSG_REG_INCONSISTENT_ERROR, TEXT("Inconsistent registry contents"),
  201. MSG_TCP_BINDING_ERROR, TEXT("TCP/IP not bound to any adapters"),
  202. MSG_MEMORY_ERROR, TEXT("Allocating memory"),
  203. MSG_ALL, TEXT("all"),
  204. MSG_RELEASE, TEXT("Release"),
  205. MSG_RENEW, TEXT("Renew"),
  206. MSG_ACCESS_DENIED, TEXT("Access Denied"),
  207. MSG_SERVER_UNAVAILABLE, TEXT("DHCP Server Unavailable"),
  208. MSG_ADDRESS_CONFLICT, TEXT("The DHCP client obtained an address that is already in use on the network.")
  209. };
  210. #define NUMBER_OF_MISC_MESSAGES (sizeof(MiscMessages)/sizeof(MiscMessages[0]))
  211. #define MISC_MESSAGE(i) MiscMessages[i].String
  212. #define ADAPTER_TYPE(i) AdapterTypes[i].String
  213. #define ADAPTER_TYPE_EX(i) AdapterTypesEx[i]
  214. #define MI_IF_OTHER 0
  215. #define MI_IF_ETHERNET 1
  216. #define MI_IF_TOKEN_RING 2
  217. #define MI_IF_FDDI 3
  218. #define MI_IF_PPP 4
  219. #define MI_IF_LOOPBACK 5
  220. #define MI_IF_SLIP 6
  221. #define MI_YES 0
  222. #define MI_NO 1
  223. #define MI_INIT_FAILED 2
  224. #define MI_TCP_NOT_RUNNING 3
  225. #define MI_REG_BINDINGS_ERROR 4
  226. #define MI_REG_INCONSISTENT_ERROR 5
  227. #define MI_TCP_BINDINGS_ERROR 6
  228. #define MI_MEMORY_ERROR 7
  229. #define MI_ALL 8
  230. #define MI_RELEASE 9
  231. #define MI_RENEW 10
  232. #define MI_ACCESS_DENIED 11
  233. #define MI_SERVER_UNAVAILABLE 12
  234. #define MI_ADDRESS_CONFLICT 13
  235. //
  236. // Debugging
  237. //
  238. #if defined(DEBUG)
  239. BOOL Debugging = FALSE;
  240. int MyTrace = 0;
  241. #endif
  242. // ========================================================================
  243. // functions
  244. // ========================================================================
  245. BOOL
  246. IpcfgdllInit(
  247. HINSTANCE hInstDll,
  248. DWORD fdwReason,
  249. LPVOID pReserved
  250. )
  251. {
  252. DWORD capability;
  253. switch (fdwReason) {
  254. case DLL_PROCESS_ATTACH:
  255. // DisableThreadLibraryCalls(hInstDll);
  256. //
  257. // load all possible internationalizable strings
  258. //
  259. LoadMessages();
  260. //
  261. // what debug version is this?
  262. //
  263. DEBUG_PRINT(("IpcfgdllInit" __DATE__ " " __TIME__ "\n"));
  264. //
  265. // opens all the required registry keys
  266. //
  267. if (!Initialize(&capability)) {
  268. LPSTR str = NULL;
  269. //
  270. // exit if we couldn't open the registry services key or
  271. // IP or TCP keys.
  272. // We will continue if the NetBT key couldn't be opened
  273. //
  274. if (!(capability & INITIAL_CAPABILITY)) {
  275. str = MISC_MESSAGE(MI_INIT_FAILED);
  276. } else if (!(capability & TCPIP_CAPABILITY)) {
  277. str = MISC_MESSAGE(MI_TCP_NOT_RUNNING);
  278. }
  279. if (str) {
  280. //DisplayMessage(FALSE, MSG_ERROR_STRING, str);
  281. Terminate();
  282. return FALSE;
  283. }
  284. }
  285. break;
  286. case DLL_PROCESS_DETACH:
  287. Terminate();
  288. break;
  289. default:
  290. break;
  291. }
  292. return TRUE;
  293. }
  294. /*******************************************************************************
  295. *
  296. * Initialize
  297. *
  298. * Opens all the required registry keys
  299. *
  300. * ENTRY Capability
  301. * Pointer to returned set of capabilities (bitmap)
  302. *
  303. * EXIT *Capability
  304. * INITIAL_CAPABILITY
  305. *
  306. * TCPIP_CAPABILITY
  307. * we could open the Tcpip\Linkage and Tcpip\Parameters keys
  308. * TcpipLinkageKey and TcpipParametersKey contain the open handles
  309. *
  310. * NETBT_CAPABILITY
  311. * we could open the NetBT\Parameters key
  312. * NetbtInterfacesKey contains the open handle
  313. *
  314. *
  315. * RETURNS TRUE = success
  316. * FALSE = failure
  317. *
  318. * ASSUMES
  319. *
  320. ******************************************************************************/
  321. #define TCPIP_LINKAGE_KEY "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Linkage"
  322. #define TCPIP_PARAMS_KEY "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\"
  323. #define TCPIP_PARAMS_INTER_KEY "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\"
  324. #define TCPIP6_PARAMS_INTER_KEY "SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters\\Interfaces\\"
  325. #define NETBT_PARAMS_KEY "SYSTEM\\CurrentControlSet\\Services\\NetBT\\Parameters"
  326. #define NETBT_INTERFACE_KEY "SYSTEM\\CurrentControlSet\\Services\\NetBT\\Parameters\\Interfaces"
  327. #define NETBT_ADAPTER_KEY "SYSTEM\\CurrentControlSet\\Services\\NetBT\\Adapters\\"
  328. BOOL Initialize(PDWORD Capability)
  329. {
  330. LONG err;
  331. char * name;
  332. *Capability = INITIAL_CAPABILITY;
  333. name = TCPIP_LINKAGE_KEY;
  334. TRACE_PRINT(("Initialize: RegOpenKey TcpipLinkageKey %s\n", name ));
  335. err = REG_OPEN_KEY(HKEY_LOCAL_MACHINE, name, &TcpipLinkageKey );
  336. if (err == ERROR_SUCCESS) {
  337. *Capability |= TCPIP_CAPABILITY;
  338. name = TCPIP_PARAMS_KEY;
  339. TRACE_PRINT(("Initialize: RegOpenKey TcpipParametersKey %s\n",
  340. name ));
  341. err = REG_OPEN_KEY(HKEY_LOCAL_MACHINE, name, &TcpipParametersKey );
  342. if (err == ERROR_SUCCESS) {
  343. name = NETBT_INTERFACE_KEY;
  344. TRACE_PRINT(("Initialize: RegOpenKey NetbtInterfacesKey %s\n",
  345. name ));
  346. err = REG_OPEN_KEY(HKEY_LOCAL_MACHINE, name, &NetbtInterfacesKey );
  347. if (err == ERROR_SUCCESS) {
  348. *Capability |= NETBT_CAPABILITY;
  349. } else {
  350. NetbtInterfacesKey = INVALID_HANDLE_VALUE;
  351. }
  352. } else {
  353. *Capability &= ~TCPIP_CAPABILITY;
  354. TcpipParametersKey = INVALID_HANDLE_VALUE;
  355. }
  356. } else {
  357. TcpipLinkageKey = INVALID_HANDLE_VALUE;
  358. }
  359. // =======================================================
  360. name = NETBT_PARAMS_KEY;
  361. TRACE_PRINT(("Initialize: RegOpenKey NetbtParametersKey %s.\n", name ));
  362. err = REG_OPEN_KEY(HKEY_LOCAL_MACHINE, name, &NetbtParametersKey );
  363. // ======================================================
  364. if( err != ERROR_SUCCESS ){
  365. DEBUG_PRINT(("Initialize: RegOpenKey %s failed, err=%d\n",
  366. name, GetLastError() ));
  367. }
  368. TRACE_PRINT(("Initialize RegOpenKey ok: \n"
  369. " TcpipLinkageKey = %p\n"
  370. " TcpipParametersKey = %p\n"
  371. " NetbtInterfacesKey = %p\n"
  372. " NetbtParametersKey = %p\n",
  373. TcpipLinkageKey,
  374. TcpipParametersKey,
  375. NetbtInterfacesKey,
  376. NetbtParametersKey
  377. ));
  378. return err == ERROR_SUCCESS;
  379. }
  380. /*******************************************************************************
  381. *
  382. * LoadMessages
  383. *
  384. * Loads all internationalizable messages into the various tables
  385. *
  386. * ENTRY
  387. *
  388. * EXIT AdapterTypes, MiscMessages updated
  389. *
  390. * RETURNS
  391. *
  392. * ASSUMES
  393. *
  394. * COHESION Temporal
  395. *
  396. ******************************************************************************/
  397. VOID LoadMessages()
  398. {
  399. LoadMessageTable(NodeTypes, NUMBER_OF_NODE_TYPES);
  400. LoadMessageTable(AdapterTypes, NUMBER_OF_ADAPTER_TYPES);
  401. LoadMessageTable(MiscMessages, NUMBER_OF_MISC_MESSAGES);
  402. }
  403. /*******************************************************************************
  404. *
  405. * LoadMessageTable
  406. *
  407. * Loads internationalizable strings into a table, replacing the default for
  408. * each. If an error occurs, the English language default is left in place
  409. *
  410. * ENTRY Table
  411. * Pointer to table containing message ID and pointer to string
  412. *
  413. * MessageCount
  414. * Number of messages in Table
  415. *
  416. * EXIT Table updated
  417. *
  418. * RETURNS
  419. *
  420. * ASSUMES
  421. *
  422. ******************************************************************************/
  423. VOID LoadMessageTable(PMESSAGE_STRING Table, UINT MessageCount)
  424. {
  425. LPSTR string;
  426. DWORD count;
  427. //
  428. // for all messages in a MESSAGE_STRING table, load the string from this
  429. // module, replacing the default string in the table (only there in case
  430. // we get an error while loading the string, so we at least have English
  431. // to fall back on)
  432. //
  433. while (MessageCount--) {
  434. if (Table->Message != MSG_NO_MESSAGE) {
  435. //
  436. // we really want LoadString here, but LoadString doesn't indicate
  437. // how big the string is, so it doesn't give us an opportunity to
  438. // allocate exactly the right buffer size. FormatMessage does the
  439. // right thing
  440. //
  441. count = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
  442. | FORMAT_MESSAGE_FROM_HMODULE,
  443. NULL, // use default hModule
  444. Table->Message,
  445. 0, // use default language
  446. (LPTSTR)&string,
  447. 0, // minimum size to allocate
  448. NULL // no arguments for inclusion in strings
  449. );
  450. if (count) {
  451. //
  452. // Format message returned the string: replace the English
  453. // language default
  454. //
  455. Table->String = string;
  456. } else {
  457. DEBUG_PRINT(("FormatMessage(%d) failed: %d\n", Table->Message, GetLastError()));
  458. //
  459. // this is ok if there is no string (e.g. just %0) in the .mc
  460. // file
  461. //
  462. Table->String = "";
  463. }
  464. }
  465. ++Table;
  466. }
  467. }
  468. /*******************************************************************************
  469. *
  470. * ConvertOemToUnicode
  471. *
  472. * Title says it all. Required because DhcpAcquireParameters etc. require the
  473. * adapter name to be UNICODE
  474. *
  475. * ENTRY OemString
  476. * Pointer to ANSI/OEM string to convert
  477. *
  478. * UnicodeString
  479. * Pointer to place to store converted results
  480. *
  481. * EXIT UnicodeString contains converted string if successful
  482. *
  483. * RETURNS TRUE - it worked
  484. * FALSE - it failed
  485. *
  486. * ASSUMES
  487. *
  488. ******************************************************************************/
  489. BOOL ConvertOemToUnicode(LPSTR OemString, LPWSTR UnicodeString)
  490. {
  491. OEM_STRING oString;
  492. UNICODE_STRING uString;
  493. RtlInitString(&oString, OemString);
  494. uString.Buffer = UnicodeString;
  495. uString.MaximumLength = (USHORT)RtlOemStringToUnicodeSize(&oString);
  496. if (NT_SUCCESS(RtlOemStringToUnicodeString(&uString, &oString, FALSE))) {
  497. return TRUE;
  498. }
  499. return FALSE;
  500. }
  501. /*******************************************************************************
  502. *
  503. * GetFixedInfo
  504. *
  505. * Retrieves the fixed information we wish to display by querying it from the
  506. * various registry keys
  507. *
  508. * ENTRY nothing
  509. *
  510. * EXIT nothing
  511. *
  512. * RETURNS pointer to allocated FIXED_INFO structure
  513. *
  514. * ASSUMES
  515. *
  516. ******************************************************************************/
  517. PFIXED_INFO GetFixedInfo()
  518. {
  519. PFIXED_INFO fixedInfo = NEW(FIXED_INFO);
  520. TRACE_PRINT(("Entered GetFixedInfo\n"));
  521. if (fixedInfo) {
  522. DWORD length;
  523. BOOL ok;
  524. HKEY transientKey;
  525. length = sizeof(fixedInfo->HostName);
  526. ok = ReadRegistryOemString(TcpipParametersKey,
  527. L"Hostname",
  528. fixedInfo->HostName,
  529. &length
  530. );
  531. //
  532. // domain: first try Domain then DhcpDomain
  533. //
  534. length = sizeof(fixedInfo->DomainName);
  535. ok = ReadRegistryOemString(TcpipParametersKey,
  536. L"Domain",
  537. fixedInfo->DomainName,
  538. &length
  539. );
  540. if (!ok) {
  541. length = sizeof(fixedInfo->DomainName);
  542. ok = ReadRegistryOemString(TcpipParametersKey,
  543. L"DhcpDomain",
  544. fixedInfo->DomainName,
  545. &length
  546. );
  547. }
  548. //
  549. // DNS Server list: first try NameServer and then DhcpNameServer
  550. //
  551. #if 0
  552. ok = ReadRegistryIpAddrString(TcpipParametersKey,
  553. TEXT("NameServer"),
  554. &fixedInfo->DnsServerList
  555. );
  556. if (ok) {
  557. TRACE_PRINT(("GetFixedInfo: NameServer %s\n",
  558. fixedInfo->DnsServerList ));
  559. }
  560. if (!ok) {
  561. ok = ReadRegistryIpAddrString(TcpipParametersKey,
  562. TEXT("DhcpNameServer"),
  563. &fixedInfo->DnsServerList
  564. );
  565. if (ok) {
  566. TRACE_PRINT(("GetFixedInfo: DhcpNameServer %s\n",
  567. fixedInfo->DnsServerList));
  568. }
  569. }
  570. #else
  571. ok = GetDnsServerList(&fixedInfo->DnsServerList);
  572. if (ok) {
  573. TRACE_PRINT(("GetFixedInfo: DnsServerList %s\n",
  574. fixedInfo->DnsServerList));
  575. }
  576. #endif
  577. //
  578. // NodeType: static then DHCP
  579. //
  580. ok = MyReadRegistryDword(NetbtParametersKey,
  581. TEXT("NodeType"),
  582. &fixedInfo->NodeType
  583. );
  584. if (!ok) {
  585. ok = MyReadRegistryDword(NetbtParametersKey,
  586. TEXT("DhcpNodeType"),
  587. &fixedInfo->NodeType
  588. );
  589. }
  590. //
  591. // ScopeId: static then DHCP
  592. //
  593. length = sizeof(fixedInfo->ScopeId);
  594. ok = ReadRegistryString(NetbtParametersKey,
  595. TEXT("ScopeId"),
  596. fixedInfo->ScopeId,
  597. &length
  598. );
  599. if (!ok) {
  600. length = sizeof(fixedInfo->ScopeId);
  601. ok = ReadRegistryString(NetbtParametersKey,
  602. TEXT("DhcpScopeId"),
  603. fixedInfo->ScopeId,
  604. &length
  605. );
  606. }
  607. ok = MyReadRegistryDword(TcpipParametersKey,
  608. TEXT("IPEnableRouter"),
  609. &fixedInfo->EnableRouting
  610. );
  611. ok = MyReadRegistryDword(NetbtParametersKey,
  612. TEXT("EnableProxy"),
  613. &fixedInfo->EnableProxy
  614. );
  615. ok = MyReadRegistryDword(NetbtParametersKey,
  616. TEXT("EnableDNS"),
  617. &fixedInfo->EnableDns
  618. );
  619. }else{
  620. DEBUG_PRINT(("No memory for fixedInfo\n"));
  621. }
  622. TRACE_PRINT(("Exit GetFixedInfo @ %p\n", fixedInfo ));
  623. return fixedInfo;
  624. }
  625. /*******************************************************************************
  626. *
  627. * GetAdapterNameToIndexInfo
  628. *
  629. * Gets the mapping between IP if_index and AdapterName.
  630. *
  631. * RETURNS pointer to a PIP_INTERFACE_INFO structure that has been allocated.
  632. *
  633. ******************************************************************************/
  634. PIP_INTERFACE_INFO GetAdapterNameToIndexInfo( VOID )
  635. {
  636. PIP_INTERFACE_INFO pInfo;
  637. ULONG dwSize, dwError;
  638. dwSize = 0; pInfo = NULL;
  639. while( 1 ) {
  640. dwError = GetInterfaceInfo( pInfo, &dwSize );
  641. if( (ERROR_INSUFFICIENT_BUFFER != dwError) && (ERROR_BUFFER_OVERFLOW != dwError) ) break;
  642. if( NULL != pInfo ) ReleaseMemory(pInfo);
  643. if( 0 == dwSize ) return NULL;
  644. pInfo = GrabMemory(dwSize);
  645. if( NULL == pInfo ) return NULL;
  646. }
  647. if( ERROR_SUCCESS != dwError || 0 == pInfo->NumAdapters ) {
  648. if( NULL != pInfo ) ReleaseMemory(pInfo);
  649. return NULL;
  650. }
  651. return pInfo;
  652. }
  653. /*******************************************************************************
  654. *
  655. * GetAdapterInfo
  656. *
  657. * Gets a list of all adapters to which TCP/IP is bound and reads the per-
  658. * adapter information that we want to display. Most of the information now
  659. * comes from the TCP/IP stack itself. In order to keep the 'short' names that
  660. * exist in the registry to refer to the individual adapters, we read the names
  661. * from the registry then match them to the adapters returned by TCP/IP by
  662. * matching the IPInterfaceContext value with the adapter which owns the IP
  663. * address with that context value
  664. *
  665. * ENTRY nothing
  666. *
  667. * EXIT nothing
  668. *
  669. * RETURNS pointer to linked list of IP_ADAPTER_INFO structures
  670. *
  671. * ASSUMES
  672. *
  673. ******************************************************************************/
  674. PIP_ADAPTER_INFO GetAdapterInfo(VOID)
  675. {
  676. PIP_ADAPTER_INFO adapterList;
  677. PIP_ADAPTER_INFO adapter;
  678. PIP_INTERFACE_INFO currentAdapterNames;
  679. LPSTR name;
  680. int i;
  681. HKEY key;
  682. TRACE_PRINT(("Entered GetAdapterInfo\n"));
  683. if (currentAdapterNames = GetAdapterNameToIndexInfo()) {
  684. if (adapterList = GetAdapterList()) {
  685. //
  686. // apply the short name to the right adapter info by comparing
  687. // the IPInterfaceContext value in the adapter\Parameters\Tcpip
  688. // section with the context values read from the stack for the
  689. // IP addresses
  690. //
  691. for (i = 0; i < currentAdapterNames->NumAdapters; ++i) {
  692. ULONG dwLength;
  693. DWORD dwIfIndex = currentAdapterNames->Adapter[i].Index;
  694. TRACE_PRINT(("currentAdapterNames[%d]=%ws (if_index 0x%lx)\n",
  695. i, currentAdapterNames->Adapter[i].Name, dwIfIndex ));
  696. //
  697. // now search through the list of adapters, looking for the one
  698. // that has the IP address with the same index value as that
  699. // just read. When found, apply the short name to that adapter
  700. //
  701. for (adapter = adapterList;
  702. adapter ;
  703. adapter = adapter->Next
  704. )
  705. {
  706. if( adapter->Index == dwIfIndex ) {
  707. dwLength = wcslen(currentAdapterNames->Adapter[i].Name) + 1 - strlen(TCPIP_DEVICE_PREFIX);
  708. dwLength = wcstombs(adapter->AdapterName,
  709. currentAdapterNames->Adapter[i].Name + strlen(TCPIP_DEVICE_PREFIX),
  710. dwLength);
  711. if( -1 == dwLength ) {
  712. adapter->AdapterName[0] = '\0';
  713. }
  714. break;
  715. }
  716. }
  717. }
  718. }
  719. else
  720. {
  721. DEBUG_PRINT(("GetAdapterInfo: GetAdapterInfo gave NULL\n"));
  722. }
  723. ReleaseMemory(currentAdapterNames);
  724. //
  725. // now get the other pieces of info from the registry for each adapter
  726. //
  727. for (adapter = adapterList; adapter; adapter = adapter->Next) {
  728. TRACE_PRINT(("GetAdapterInfo: '%s'\n", adapter->AdapterName ));
  729. if (adapter->AdapterName[0] &&
  730. OpenAdapterKey(KEY_TCP, adapter->AdapterName, KEY_READ, &key)) {
  731. char dhcpServerAddress[4 * 4];
  732. DWORD addressLength;
  733. ULONG length;
  734. BOOL ok;
  735. MyReadRegistryDword(key,
  736. TEXT("EnableDHCP"),
  737. &adapter->DhcpEnabled
  738. );
  739. TRACE_PRINT(("..'EnableDHCP' %d\n", adapter->DhcpEnabled ));
  740. #ifdef DBG
  741. if ( uChangeMode )
  742. {
  743. DWORD dwAutoconfigEnabled =
  744. ( uChangeMode == SET_AUTO_MODE );
  745. WriteRegistryDword(
  746. key,
  747. "IPAutoconfigurationEnabled",
  748. &dwAutoconfigEnabled
  749. );
  750. }
  751. #endif
  752. if (adapter->DhcpEnabled) {
  753. DWORD Temp;
  754. MyReadRegistryDword(key,
  755. TEXT("LeaseObtainedTime"),
  756. &Temp
  757. );
  758. adapter->LeaseObtained = Temp;
  759. MyReadRegistryDword(key,
  760. TEXT("LeaseTerminatesTime"),
  761. &Temp
  762. );
  763. adapter->LeaseExpires = Temp;
  764. }
  765. addressLength = sizeof( dhcpServerAddress );
  766. if (ReadRegistryString(key,
  767. TEXT("DhcpServer"),
  768. dhcpServerAddress,
  769. &addressLength
  770. )) {
  771. AddIpAddressString(&adapter->DhcpServer,
  772. dhcpServerAddress,
  773. ""
  774. );
  775. }
  776. RegCloseKey(key);
  777. } else {
  778. DEBUG_PRINT(("Cannot OpenAdapterKey KEY_TCP '%s', gle=%d\n",
  779. adapter->AdapterName,
  780. GetLastError()));
  781. }
  782. //
  783. // get the info from the NetBT key - the WINS addresses
  784. //
  785. GetWinsServers(adapter);
  786. }
  787. } else {
  788. DEBUG_PRINT(("GetAdapterInfo: GetBoundAdapterList gave NULL\n"));
  789. adapterList = NULL;
  790. }
  791. TRACE_PRINT(("Exit GetAdapterInfo %p\n", adapterList));
  792. return adapterList;
  793. }
  794. /*******************************************************************************
  795. * AddIPv6UnicastAddressInfo
  796. *
  797. * This routine adds an IP_ADAPTER_UNICAST_ADDRESS entry for an IPv6 address
  798. * to a list of entries.
  799. *
  800. * ENTRY IF - IPv6 interface information
  801. * ADE - IPv6 address entry
  802. * ppNext - Previous unicast entry's "next" pointer to update
  803. *
  804. * EXIT Entry added and args updated
  805. *
  806. * RETURNS Error status
  807. *
  808. ******************************************************************************/
  809. DWORD AddIPv6UnicastAddressInfo(IPV6_INFO_INTERFACE *IF, IPV6_INFO_ADDRESS *ADE, PIP_ADAPTER_UNICAST_ADDRESS **ppNext)
  810. {
  811. DWORD dwErr = NO_ERROR;
  812. PIP_ADAPTER_UNICAST_ADDRESS pCurr;
  813. SOCKADDR_IN6 *pAddr;
  814. ASSERT(ADE->Type == ADE_UNICAST);
  815. pCurr = MALLOC(sizeof(IP_ADAPTER_UNICAST_ADDRESS));
  816. if (!pCurr) {
  817. return ERROR_NOT_ENOUGH_MEMORY;
  818. }
  819. pAddr = MALLOC(sizeof(SOCKADDR_IN6));
  820. if (!pAddr) {
  821. FREE(pCurr);
  822. return ERROR_NOT_ENOUGH_MEMORY;
  823. }
  824. memset(pAddr, 0, sizeof(SOCKADDR_IN6));
  825. pAddr->sin6_family = AF_INET6;
  826. pAddr->sin6_scope_id = ADE->ScopeId;
  827. memcpy(&pAddr->sin6_addr, &ADE->This.Address, sizeof(ADE->This.Address));
  828. // Add address to linked list
  829. **ppNext = pCurr;
  830. *ppNext = &pCurr->Next;
  831. pCurr->Next = NULL;
  832. pCurr->Length = sizeof(IP_ADAPTER_UNICAST_ADDRESS);
  833. pCurr->ValidLifetime = ADE->ValidLifetime;
  834. pCurr->PreferredLifetime = ADE->PreferredLifetime;
  835. pCurr->LeaseLifetime = 0xFFFFFFFF;
  836. pCurr->Flags = 0;
  837. pCurr->Address.iSockaddrLength = sizeof(SOCKADDR_IN6);
  838. pCurr->Address.lpSockaddr = (LPSOCKADDR)pAddr;
  839. pCurr->PrefixOrigin = ADE->PrefixConf;
  840. pCurr->SuffixOrigin = ADE->InterfaceIdConf;
  841. pCurr->DadState = ADE->DADState;
  842. // Only use DDNS on auto-configured addresses
  843. // (either auto-configured by the system or from an RA)
  844. // but NOT anonymous addresses.
  845. // Also do not use DDNS on link-local addresses
  846. // or the loopback address.
  847. if ((ADE->DADState == DAD_STATE_PREFERRED) &&
  848. (pCurr->SuffixOrigin != IpSuffixOriginRandom) &&
  849. !IN6_IS_ADDR_LOOPBACK(&ADE->This.Address) &&
  850. !IN6_IS_ADDR_LINKLOCAL(&ADE->This.Address)) {
  851. pCurr->Flags |= IP_ADAPTER_ADDRESS_DNS_ELIGIBLE;
  852. }
  853. return dwErr;
  854. }
  855. /*******************************************************************************
  856. * AddIPv6AnycastAddressInfo
  857. *
  858. * This routine adds an IP_ADAPTER_ANYCAST_ADDRESS entry for an IPv6 address
  859. * to a list of entries.
  860. *
  861. * ENTRY IF - IPv6 interface information
  862. * ADE - IPv6 address entry
  863. * ppNext - Previous anycast entry's "next" pointer to update
  864. *
  865. * EXIT Entry added and args updated
  866. *
  867. * RETURNS Error status
  868. *
  869. ******************************************************************************/
  870. DWORD AddIPv6AnycastAddressInfo(IPV6_INFO_INTERFACE *IF, IPV6_INFO_ADDRESS *ADE, PIP_ADAPTER_ANYCAST_ADDRESS **ppNext)
  871. {
  872. DWORD dwErr = NO_ERROR;
  873. PIP_ADAPTER_ANYCAST_ADDRESS pCurr;
  874. SOCKADDR_IN6 *pAddr;
  875. ASSERT(ADE->Type == ADE_ANYCAST);
  876. pCurr = MALLOC(sizeof(IP_ADAPTER_ANYCAST_ADDRESS));
  877. if (!pCurr) {
  878. return ERROR_NOT_ENOUGH_MEMORY;
  879. }
  880. pAddr = MALLOC(sizeof(SOCKADDR_IN6));
  881. if (!pAddr) {
  882. FREE(pCurr);
  883. return ERROR_NOT_ENOUGH_MEMORY;
  884. }
  885. memset(pAddr, 0, sizeof(SOCKADDR_IN6));
  886. pAddr->sin6_family = AF_INET6;
  887. pAddr->sin6_scope_id = ADE->ScopeId;
  888. memcpy(&pAddr->sin6_addr, &ADE->This.Address, sizeof(ADE->This.Address));
  889. // Add address to linked list
  890. **ppNext = pCurr;
  891. *ppNext = &pCurr->Next;
  892. pCurr->Next = NULL;
  893. pCurr->Length = sizeof(IP_ADAPTER_ANYCAST_ADDRESS);
  894. pCurr->Flags = 0;
  895. pCurr->Address.iSockaddrLength = sizeof(SOCKADDR_IN6);
  896. pCurr->Address.lpSockaddr = (LPSOCKADDR)pAddr;
  897. return dwErr;
  898. }
  899. /*******************************************************************************
  900. * AddIPv6MulticastAddressInfo
  901. *
  902. * This routine adds an IP_ADAPTER_MULTICAST_ADDRESS entry for an IPv6 address
  903. * to a list of entries.
  904. *
  905. * ENTRY IF - IPv6 interface information
  906. * ADE - IPv6 address entry
  907. * ppNext - Previous multicast entry's "next" pointer to update
  908. *
  909. * EXIT Entry added and args updated
  910. *
  911. * RETURNS Error status
  912. *
  913. ******************************************************************************/
  914. DWORD AddIPv6MulticastAddressInfo(IPV6_INFO_INTERFACE *IF, IPV6_INFO_ADDRESS *ADE, PIP_ADAPTER_MULTICAST_ADDRESS **ppNext)
  915. {
  916. DWORD dwErr = NO_ERROR;
  917. PIP_ADAPTER_MULTICAST_ADDRESS pCurr;
  918. SOCKADDR_IN6 *pAddr;
  919. ASSERT(ADE->Type == ADE_MULTICAST);
  920. pCurr = MALLOC(sizeof(IP_ADAPTER_MULTICAST_ADDRESS));
  921. if (!pCurr) {
  922. return ERROR_NOT_ENOUGH_MEMORY;
  923. }
  924. pAddr = MALLOC(sizeof(SOCKADDR_IN6));
  925. if (!pAddr) {
  926. FREE(pCurr);
  927. return ERROR_NOT_ENOUGH_MEMORY;
  928. }
  929. memset(pAddr, 0, sizeof(SOCKADDR_IN6));
  930. pAddr->sin6_family = AF_INET6;
  931. pAddr->sin6_scope_id = ADE->ScopeId;
  932. memcpy(&pAddr->sin6_addr, &ADE->This.Address, sizeof(ADE->This.Address));
  933. // Add address to linked list
  934. **ppNext = pCurr;
  935. *ppNext = &pCurr->Next;
  936. pCurr->Next = NULL;
  937. pCurr->Length = sizeof(IP_ADAPTER_MULTICAST_ADDRESS);
  938. pCurr->Flags = 0;
  939. pCurr->Address.iSockaddrLength = sizeof(SOCKADDR_IN6);
  940. pCurr->Address.lpSockaddr = (LPSOCKADDR)pAddr;
  941. return dwErr;
  942. }
  943. /*******************************************************************************
  944. * AddIPv6AddressInfo
  945. *
  946. * This routine adds an IP_ADAPTER_UNICAST_ADDRESS entry for an IPv6 address
  947. * to a list of entries.
  948. *
  949. * ENTRY IF - IPv6 interface information
  950. * ADE - IPv6 address entry
  951. * arg1 - Previous unicast entry's "next" pointer to update
  952. * arg2 - Previous anycast entry's "next" pointer to update
  953. * arg3 - Previous multicast entry's "next" pointer to update
  954. * Flags - Flags specified by application
  955. * Family - Address family constraint (for DNS server addresses)
  956. *
  957. * EXIT Entry added and args updated
  958. *
  959. * RETURNS Error status
  960. *
  961. ******************************************************************************/
  962. DWORD AddIPv6AddressInfo(IPV6_INFO_INTERFACE *IF, IPV6_INFO_ADDRESS *ADE, PVOID arg1, PVOID arg2, PVOID arg3, DWORD Flags, DWORD Family)
  963. {
  964. switch (ADE->Type) {
  965. case ADE_UNICAST:
  966. if (Flags & GAA_FLAG_SKIP_UNICAST) {
  967. return NO_ERROR;
  968. }
  969. return AddIPv6UnicastAddressInfo(IF, ADE,
  970. (PIP_ADAPTER_UNICAST_ADDRESS**)arg1);
  971. case ADE_ANYCAST:
  972. if (Flags & GAA_FLAG_SKIP_ANYCAST) {
  973. return NO_ERROR;
  974. }
  975. return AddIPv6AnycastAddressInfo(IF, ADE,
  976. (PIP_ADAPTER_ANYCAST_ADDRESS**)arg2);
  977. case ADE_MULTICAST:
  978. if (Flags & GAA_FLAG_SKIP_MULTICAST) {
  979. return NO_ERROR;
  980. }
  981. return AddIPv6MulticastAddressInfo(IF, ADE,
  982. (PIP_ADAPTER_MULTICAST_ADDRESS**)arg3);
  983. default:
  984. ASSERT(0);
  985. }
  986. return NO_ERROR;
  987. }
  988. /*******************************************************************************
  989. * ForEachIPv6Address
  990. *
  991. * This routine walks a set of IPv6 addresses and invokes a given function
  992. * on each one.
  993. *
  994. * ENTRY IF - IPv6 interface information
  995. * func - Function to invoke on each address
  996. * arg1 - Argument to pass to func
  997. * arg2 - Argument to pass to func
  998. * arg3 - Argument to pass to func
  999. * Flags - Flags to pass to func
  1000. * Family - Address family constraint (for DNS server addresses)
  1001. *
  1002. * EXIT Nothing
  1003. *
  1004. * RETURNS Error status
  1005. *
  1006. ******************************************************************************/
  1007. DWORD ForEachIPv6Address(IPV6_INFO_INTERFACE *IF, DWORD (*func)(IPV6_INFO_INTERFACE *,IPV6_INFO_ADDRESS *, PVOID, PVOID, PVOID, DWORD, DWORD), PVOID arg1, PVOID arg2, PVOID arg3, DWORD Flags, DWORD Family)
  1008. {
  1009. IPV6_QUERY_ADDRESS Query;
  1010. IPV6_INFO_ADDRESS ADE;
  1011. u_int BytesReturned, BytesIn;
  1012. DWORD dwErr;
  1013. Query.IF = IF->This;
  1014. Query.Address = in6addr_any;
  1015. for (;;) {
  1016. BytesIn = sizeof Query;
  1017. BytesReturned = sizeof ADE;
  1018. dwErr = WsControl( IPPROTO_IPV6,
  1019. IOCTL_IPV6_QUERY_ADDRESS,
  1020. &Query, &BytesIn,
  1021. &ADE, &BytesReturned);
  1022. if (dwErr != NO_ERROR) {
  1023. return dwErr;
  1024. }
  1025. if (!IN6_ADDR_EQUAL(&Query.Address, &in6addr_any)) {
  1026. dwErr = (*func)(IF, &ADE, arg1, arg2, arg3, Flags, Family);
  1027. if (dwErr != NO_ERROR) {
  1028. return dwErr;
  1029. }
  1030. }
  1031. if (IN6_ADDR_EQUAL(&ADE.Next.Address, &in6addr_any))
  1032. break;
  1033. Query = ADE.Next;
  1034. }
  1035. return NO_ERROR;
  1036. }
  1037. /*******************************************************************************
  1038. * MapIpv4AddressToName
  1039. *
  1040. * This routine finds the name and description of the adapter which
  1041. * has a given IPv4 address on it.
  1042. *
  1043. * ENTRY pAdapterInfo - Buffer obtained from GetAdaptersInfo
  1044. * Ipv4Address - IPv4 address to search for
  1045. * pDescription - Where to place a pointer to the description text
  1046. *
  1047. * EXIT pDescription updated, if found
  1048. *
  1049. * RETURNS Adapter name, or NULL if not found
  1050. *
  1051. ******************************************************************************/
  1052. LPSTR
  1053. MapIpv4AddressToName(IP_ADAPTER_INFO *pAdapterInfo, DWORD Ipv4Address, PCHAR *pDescription)
  1054. {
  1055. IP_ADAPTER_INFO *pAdapter;
  1056. IP_ADDR_STRING *pAddr;
  1057. for (pAdapter = pAdapterInfo;
  1058. pAdapter != NULL;
  1059. pAdapter = pAdapter->Next) {
  1060. for (pAddr = &pAdapter->IpAddressList; pAddr; pAddr=pAddr->Next) {
  1061. if (inet_addr(pAddr->IpAddress.String) == Ipv4Address) {
  1062. *pDescription = pAdapter->Description;
  1063. return pAdapter->AdapterName;
  1064. }
  1065. }
  1066. }
  1067. return NULL;
  1068. }
  1069. #define GUID_FORMAT_A "{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}"
  1070. /*******************************************************************************
  1071. * ConvertGuidToStringA
  1072. *
  1073. * This routine converts a GUID to a character string.
  1074. *
  1075. * ENTRY pGuid - Contains the GUID to translate.
  1076. * pszBuffer - Space for storing the string.
  1077. * Must be >= 39 * sizeof(CHAR).
  1078. *
  1079. * EXIT pszBuffer updated
  1080. *
  1081. * RETURNS Whatever sprintf returns
  1082. *
  1083. ******************************************************************************/
  1084. DWORD
  1085. ConvertGuidToStringA(GUID *pGuid, PCHAR pszBuffer)
  1086. {
  1087. return sprintf(pszBuffer,
  1088. GUID_FORMAT_A,
  1089. pGuid->Data1,
  1090. pGuid->Data2,
  1091. pGuid->Data3,
  1092. pGuid->Data4[0],
  1093. pGuid->Data4[1],
  1094. pGuid->Data4[2],
  1095. pGuid->Data4[3],
  1096. pGuid->Data4[4],
  1097. pGuid->Data4[5],
  1098. pGuid->Data4[6],
  1099. pGuid->Data4[7]);
  1100. }
  1101. /*******************************************************************************
  1102. * ConvertStringToGuidA
  1103. *
  1104. * This routine converts a character string to a GUID.
  1105. *
  1106. * ENTRY pszGuid - Contains the string to translate
  1107. * pGuid - Space for storing the GUID
  1108. *
  1109. * EXIT pGuid updated
  1110. *
  1111. * RETURNS Error status
  1112. *
  1113. ******************************************************************************/
  1114. DWORD
  1115. ConvertStringToGuidA(PCHAR pszGuid, GUID *pGuid)
  1116. {
  1117. UNICODE_STRING Temp;
  1118. WCHAR wszGuid[40+1];
  1119. MultiByteToWideChar(CP_ACP, 0, pszGuid, -1, wszGuid, 40);
  1120. RtlInitUnicodeString(&Temp, wszGuid);
  1121. if(RtlGUIDFromString(&Temp, pGuid) != STATUS_SUCCESS)
  1122. {
  1123. return ERROR_INVALID_PARAMETER;
  1124. }
  1125. return NO_ERROR;
  1126. }
  1127. /*******************************************************************************
  1128. * MapGuidToAdapterName
  1129. *
  1130. * This routine gets an adapter name and description, given a GUID.
  1131. *
  1132. * ENTRY pAdapterInfo - Buffer obtained from GetAdaptersInfo
  1133. * Guid - GUID of the adapter
  1134. * pwszDescription - Buffer in which to place description text.
  1135. * Must be at least MAX_ADAPTER_DESCRIPTION_LENGTH
  1136. * WCHAR's long.
  1137. *
  1138. * EXIT pwszDescription buffer filled in, if found
  1139. *
  1140. * RETURNS Adapter name, or NULL if not found
  1141. *
  1142. ******************************************************************************/
  1143. LPSTR
  1144. MapGuidToAdapterName(IP_ADAPTER_INFO *pAdapterInfo, GUID *Guid, PWCHAR pwszDescription)
  1145. {
  1146. IP_ADAPTER_INFO *pAdapter;
  1147. CHAR szGuid[40];
  1148. ConvertGuidToStringA(Guid, szGuid);
  1149. for (pAdapter = pAdapterInfo;
  1150. pAdapter != NULL;
  1151. pAdapter = pAdapter->Next) {
  1152. if (!strcmp(szGuid, pAdapter->AdapterName)) {
  1153. MultiByteToWideChar(CP_ACP, 0, pAdapter->Description, -1,
  1154. pwszDescription,
  1155. MAX_ADAPTER_DESCRIPTION_LENGTH);
  1156. return pAdapter->AdapterName;
  1157. }
  1158. }
  1159. pwszDescription[0] = L'\0';
  1160. return NULL;
  1161. }
  1162. /*******************************************************************************
  1163. * AddDnsServerAddressInfo
  1164. *
  1165. * This routine adds an IP_ADAPTER_DNS_SERVER_ADDRESS entry for an address
  1166. * to a list of entries.
  1167. *
  1168. * ENTRY IF - interface information
  1169. * Addr - Address in sockaddr format
  1170. * AddrLen- Size of sockaddr
  1171. * pFirst - First DNS server entry
  1172. * ppNext - Previous DNS server entry's "next" pointer to update
  1173. *
  1174. * EXIT Entry added and args updated
  1175. *
  1176. * RETURNS Error status
  1177. *
  1178. ******************************************************************************/
  1179. DWORD AddDnsServerAddressInfo(PIP_ADAPTER_DNS_SERVER_ADDRESS **ppNext, LPSOCKADDR Addr, ULONG AddrLen)
  1180. {
  1181. DWORD dwErr = NO_ERROR;
  1182. PIP_ADAPTER_DNS_SERVER_ADDRESS pCurr;
  1183. LPSOCKADDR pAddr;
  1184. pCurr = MALLOC(sizeof(IP_ADAPTER_DNS_SERVER_ADDRESS));
  1185. if (!pCurr) {
  1186. return ERROR_NOT_ENOUGH_MEMORY;
  1187. }
  1188. pAddr = MALLOC(AddrLen);
  1189. if (!pAddr) {
  1190. FREE(pCurr);
  1191. return ERROR_NOT_ENOUGH_MEMORY;
  1192. }
  1193. memcpy(pAddr, Addr, AddrLen);
  1194. // Add address to linked list
  1195. **ppNext = pCurr;
  1196. *ppNext = &pCurr->Next;
  1197. pCurr->Next = NULL;
  1198. pCurr->Length = sizeof(IP_ADAPTER_DNS_SERVER_ADDRESS);
  1199. pCurr->Address.iSockaddrLength = AddrLen;
  1200. pCurr->Address.lpSockaddr = (LPSOCKADDR)pAddr;
  1201. return dwErr;
  1202. }
  1203. /*******************************************************************************
  1204. * GetAdapterDnsServers
  1205. *
  1206. * This routine reads a list of DNS server addresses from a registry key.
  1207. *
  1208. * ENTRY TcpipKey - Registry key to look under
  1209. * pCurr - Interface entry to add servers to
  1210. *
  1211. * EXIT Entry updated
  1212. *
  1213. * RETURNS Error status
  1214. *
  1215. ******************************************************************************/
  1216. DWORD
  1217. GetAdapterDnsServers(HKEY TcpipKey, PIP_ADAPTER_ADDRESSES pCurr)
  1218. {
  1219. DWORD Size, Type, dwErr, i;
  1220. CHAR Servers[800], *Str;
  1221. PIP_ADAPTER_DNS_SERVER_ADDRESS pD, *ppDNext;
  1222. ADDRINFO hints, *ai;
  1223. static LONG Initialized = FALSE;
  1224. if (InterlockedExchange(&Initialized, TRUE) == FALSE) {
  1225. WSADATA WsaData;
  1226. dwErr = WSAStartup(MAKEWORD(2, 0), &WsaData);
  1227. if (NO_ERROR != dwErr) {
  1228. return dwErr;
  1229. }
  1230. }
  1231. //
  1232. // Read DNS Server addresses.
  1233. //
  1234. Size = sizeof(Servers);
  1235. ZeroMemory(Servers, Size);
  1236. dwErr = RegQueryValueExA(TcpipKey, (LPSTR)"NameServer", NULL, &Type,
  1237. (LPBYTE)Servers, &Size);
  1238. if (NO_ERROR != dwErr) {
  1239. if (ERROR_FILE_NOT_FOUND != dwErr) {
  1240. return dwErr;
  1241. }
  1242. Size = 0;
  1243. Type = REG_SZ;
  1244. }
  1245. if (REG_SZ != Type) {
  1246. return ERROR_INVALID_DATA;
  1247. }
  1248. if ((0 == Size) || (0 == strlen(Servers))) {
  1249. Size = sizeof(Servers);
  1250. dwErr = RegQueryValueExA(TcpipKey, (LPSTR)"DhcpNameServer", NULL,
  1251. &Type, (LPBYTE)Servers, &Size);
  1252. if (NO_ERROR != dwErr) {
  1253. if (ERROR_FILE_NOT_FOUND != dwErr) {
  1254. return dwErr;
  1255. }
  1256. Size = 0;
  1257. Type = REG_SZ;
  1258. }
  1259. }
  1260. //
  1261. // If there are any DNS Servers, convert them to sockaddrs
  1262. //
  1263. ZeroMemory(&hints, sizeof(hints));
  1264. hints.ai_flags = AI_NUMERICHOST;
  1265. ppDNext = &pCurr->FirstDnsServerAddress;
  1266. while (*ppDNext) {
  1267. ppDNext = &(*ppDNext)->Next;
  1268. }
  1269. if ((0 != Size) && strlen(Servers)) {
  1270. for (i = 0; i < Size; i ++) {
  1271. if (Servers[i] == ' ' || Servers[i] == ','
  1272. || Servers[i] == ';') {
  1273. Servers[i] = '\0';
  1274. }
  1275. }
  1276. Servers[Size] = '\0';
  1277. for (Str = (LPSTR)Servers;
  1278. *Str != '\0';
  1279. Str += strlen(Str) + 1)
  1280. {
  1281. if (getaddrinfo(Str, NULL, &hints, &ai) == NO_ERROR) {
  1282. AddDnsServerAddressInfo(&ppDNext, ai->ai_addr, ai->ai_addrlen);
  1283. }
  1284. }
  1285. }
  1286. return NO_ERROR;
  1287. }
  1288. /*******************************************************************************
  1289. * GetAdapterDnsInfo
  1290. *
  1291. * This routine reads DNS configuration information for an interface.
  1292. *
  1293. * ENTRY dwFamily - Address family constraint
  1294. * name - Adapter name
  1295. * pCurr - Interface entry to update
  1296. * AppFlags - Flags controlling what fields to skip, if any
  1297. *
  1298. * EXIT Entry updated
  1299. *
  1300. * RETURNS Error status
  1301. *
  1302. ******************************************************************************/
  1303. DWORD
  1304. GetAdapterDnsInfo(DWORD dwFamily, char *name, PIP_ADAPTER_ADDRESSES pCurr, DWORD AppFlags)
  1305. {
  1306. WCHAR Buffer[MAX_DOMAIN_NAME_LEN+1];
  1307. DWORD dwErr = NO_ERROR, Size, Type, Value;
  1308. DWORD DnsSuffixSize = sizeof(Buffer);
  1309. HKEY TcpipKey = NULL;
  1310. PIP_ADAPTER_DNS_SERVER_ADDRESS DnsServerAddr;
  1311. LPSOCKADDR_IN6 Sockaddr;
  1312. Buffer[0] = L'\0';
  1313. pCurr->DnsSuffix = NULL;
  1314. pCurr->Flags = IP_ADAPTER_DDNS_ENABLED;
  1315. if (name == NULL) {
  1316. //
  1317. // If we couldn't find an adapter name, just use the default settings.
  1318. //
  1319. goto Done;
  1320. }
  1321. do {
  1322. if (!OpenAdapterKey(KEY_TCP, name, KEY_READ, &TcpipKey)) {
  1323. dwErr = ERROR_CAN_NOT_COMPLETE;
  1324. break;
  1325. }
  1326. //
  1327. // Get DnsSuffix for the interface
  1328. //
  1329. Size = DnsSuffixSize;
  1330. dwErr = RegQueryValueExW(TcpipKey, (LPWSTR)L"Domain", NULL, &Type,
  1331. (LPBYTE)Buffer, &Size );
  1332. if (NO_ERROR != dwErr) {
  1333. if (ERROR_FILE_NOT_FOUND != dwErr) {
  1334. break;
  1335. }
  1336. Size = 0;
  1337. Type = REG_SZ;
  1338. }
  1339. if (REG_SZ != Type) {
  1340. dwErr = ERROR_INVALID_DATA;
  1341. break;
  1342. }
  1343. if ((0 == Size) || (0 == wcslen(Buffer))) {
  1344. Size = DnsSuffixSize;
  1345. dwErr = RegQueryValueExW(TcpipKey, (LPWSTR)L"DhcpDomain", NULL,
  1346. &Type, (LPBYTE)Buffer, &Size );
  1347. if (NO_ERROR != dwErr) {
  1348. if (ERROR_FILE_NOT_FOUND != dwErr) {
  1349. break;
  1350. }
  1351. Size = 0;
  1352. Buffer[0] = L'\0';
  1353. }
  1354. }
  1355. if (MyReadRegistryDword(TcpipKey, "RegistrationEnabled",
  1356. &Value) && (Value == 0)) {
  1357. pCurr->Flags &= ~IP_ADAPTER_DDNS_ENABLED;
  1358. }
  1359. if (MyReadRegistryDword(TcpipKey,
  1360. "RegisterAdapterName", &Value)
  1361. && Value) {
  1362. pCurr->Flags |= IP_ADAPTER_REGISTER_ADAPTER_SUFFIX;
  1363. }
  1364. //
  1365. // Now attempt to read the DnsServers list
  1366. //
  1367. if (!(AppFlags & GAA_FLAG_SKIP_DNS_SERVER)) {
  1368. if ((dwFamily != AF_INET) && bIp6DriverInstalled) {
  1369. //
  1370. // First look for IPv6 servers.
  1371. //
  1372. HKEY Tcpip6Key = NULL;
  1373. if (OpenAdapterKey(KEY_TCP6, name, KEY_READ, &Tcpip6Key)) {
  1374. GetAdapterDnsServers(Tcpip6Key, pCurr);
  1375. RegCloseKey(Tcpip6Key);
  1376. }
  1377. if (pCurr->FirstDnsServerAddress == NULL) {
  1378. //
  1379. // None are configured, so use the default list of
  1380. // well-known addresses.
  1381. //
  1382. SOCKADDR_IN6 Addr;
  1383. PIP_ADAPTER_DNS_SERVER_ADDRESS *ppDNext;
  1384. BYTE i;
  1385. ZeroMemory(&Addr, sizeof(Addr));
  1386. Addr.sin6_family = AF_INET6;
  1387. Addr.sin6_addr.s6_words[0] = 0xC0FE;
  1388. Addr.sin6_addr.s6_words[3] = 0xFFFF;
  1389. ppDNext = &pCurr->FirstDnsServerAddress;
  1390. while (*ppDNext) {
  1391. ppDNext = &(*ppDNext)->Next;
  1392. }
  1393. for (i=1; i<=3; i++) {
  1394. Addr.sin6_addr.s6_bytes[15] = i;
  1395. AddDnsServerAddressInfo(&ppDNext, (LPSOCKADDR)&Addr, sizeof(Addr));
  1396. }
  1397. }
  1398. // Now we need to go through any non-global IPv6 DNS server
  1399. // addresses and fill in the scope id.
  1400. for (DnsServerAddr = pCurr->FirstDnsServerAddress;
  1401. DnsServerAddr;
  1402. DnsServerAddr = DnsServerAddr->Next) {
  1403. if (DnsServerAddr->Address.lpSockaddr->sa_family != AF_INET6)
  1404. continue;
  1405. Sockaddr = (LPSOCKADDR_IN6)DnsServerAddr->Address.lpSockaddr;
  1406. if (IN6_IS_ADDR_LINKLOCAL(&Sockaddr->sin6_addr))
  1407. Sockaddr->sin6_scope_id = pCurr->ZoneIndices[ADE_LINK_LOCAL];
  1408. else if (IN6_IS_ADDR_SITELOCAL(&Sockaddr->sin6_addr))
  1409. Sockaddr->sin6_scope_id = pCurr->ZoneIndices[ADE_SITE_LOCAL];
  1410. }
  1411. }
  1412. if (dwFamily != AF_INET6) {
  1413. //
  1414. // Finally, add IPv4 servers.
  1415. //
  1416. GetAdapterDnsServers(TcpipKey, pCurr);
  1417. }
  1418. }
  1419. } while (FALSE);
  1420. if (TcpipKey) {
  1421. RegCloseKey(TcpipKey);
  1422. }
  1423. Done:
  1424. pCurr->DnsSuffix = MALLOC((wcslen(Buffer)+1) * sizeof(WCHAR));
  1425. if (pCurr->DnsSuffix) {
  1426. wcscpy(pCurr->DnsSuffix, Buffer);
  1427. }
  1428. return dwErr;
  1429. }
  1430. /*******************************************************************************
  1431. * NewIpAdapter
  1432. *
  1433. * This routine allocates an IP_ADAPTER_ADDRESSES entry and appends it to
  1434. * a list of such entries.
  1435. *
  1436. * ENTRY ppCurr - Location in which to return new entry
  1437. * ppNext - Previous entry's "next" pointer to update
  1438. * name - Adapter name
  1439. * Ipv4IfIndex - IPv4 Interface index
  1440. * Ipv6IfIndex - IPv6 Interface index
  1441. * AppFlags - Flags controlling what fields to skip, if any
  1442. * IfType - IANA ifType value
  1443. * Mtu - Maximum transmission unit
  1444. * PhysAddr - MAC address
  1445. * PhysAddrLen - Byte count of PhysAddr
  1446. * Description - Adapter description
  1447. * FriendlyName - User-friendly interface name
  1448. * Family - Address family constraint for DNS servers
  1449. *
  1450. * EXIT ppCurr and ppNext updated
  1451. *
  1452. * RETURNS Error status
  1453. *
  1454. ******************************************************************************/
  1455. DWORD NewIpAdapter(PIP_ADAPTER_ADDRESSES *ppCurr, PIP_ADAPTER_ADDRESSES **ppNext, char *AdapterName, char *NameForDnsInfo, UINT Ipv4IfIndex, UINT Ipv6IfIndex, DWORD AppFlags, DWORD IfType, SIZE_T Mtu, BYTE *PhysAddr, DWORD PhysAddrLen, PWCHAR Description, PWCHAR FriendlyName, DWORD *ZoneIndices, DWORD Family)
  1456. {
  1457. DWORD i;
  1458. *ppCurr = MALLOC(sizeof(IP_ADAPTER_ADDRESSES));
  1459. if (!*ppCurr) {
  1460. return ERROR_NOT_ENOUGH_MEMORY;
  1461. }
  1462. ZeroMemory(*ppCurr, sizeof(IP_ADAPTER_ADDRESSES));
  1463. (*ppCurr)->AdapterName = MALLOC(strlen(AdapterName)+1);
  1464. if (!(*ppCurr)->AdapterName) {
  1465. goto Fail;
  1466. }
  1467. (*ppCurr)->Description = MALLOC((wcslen(Description)+1) * sizeof(WCHAR));
  1468. if (!(*ppCurr)->Description) {
  1469. goto Fail;
  1470. }
  1471. (*ppCurr)->FriendlyName = MALLOC((wcslen(FriendlyName)+1) * sizeof(WCHAR));
  1472. if (!(*ppCurr)->FriendlyName) {
  1473. goto Fail;
  1474. }
  1475. (*ppCurr)->Next = NULL;
  1476. (*ppCurr)->Length = sizeof(IP_ADAPTER_ADDRESSES);
  1477. strcpy((*ppCurr)->AdapterName, AdapterName);
  1478. (*ppCurr)->IfIndex = Ipv4IfIndex;
  1479. (*ppCurr)->Ipv6IfIndex = Ipv6IfIndex;
  1480. (*ppCurr)->FirstUnicastAddress = NULL;
  1481. (*ppCurr)->FirstAnycastAddress = NULL;
  1482. (*ppCurr)->FirstMulticastAddress = NULL;
  1483. (*ppCurr)->FirstDnsServerAddress = NULL;
  1484. (*ppCurr)->OperStatus = IfOperStatusUp;
  1485. CopyMemory((*ppCurr)->ZoneIndices, ZoneIndices, ADE_GLOBAL * sizeof(DWORD));
  1486. (*ppCurr)->ZoneIndices[ADE_GLOBAL] = 0;
  1487. (*ppCurr)->ZoneIndices[ADE_LARGEST_SCOPE] = 0;
  1488. //(*ppCurr)->Mtu = Mtu; "dword should be enough for MTU"
  1489. (*ppCurr)->Mtu = (DWORD)Mtu;
  1490. (*ppCurr)->IfType = IfType;
  1491. (*ppCurr)->PhysicalAddressLength = PhysAddrLen;
  1492. memcpy((*ppCurr)->PhysicalAddress, PhysAddr, PhysAddrLen);
  1493. wcscpy((*ppCurr)->Description, Description);
  1494. wcscpy((*ppCurr)->FriendlyName, FriendlyName);
  1495. GetAdapterDnsInfo(Family,
  1496. (NameForDnsInfo != NULL)? NameForDnsInfo : AdapterName,
  1497. *ppCurr, AppFlags);
  1498. if ((*ppCurr)->DnsSuffix == NULL) {
  1499. goto Fail;
  1500. }
  1501. **ppNext = *ppCurr;
  1502. *ppNext = &(*ppCurr)->Next;
  1503. return NO_ERROR;
  1504. Fail:
  1505. if ((*ppCurr)->AdapterName) {
  1506. FREE((*ppCurr)->AdapterName);
  1507. }
  1508. if ((*ppCurr)->FriendlyName) {
  1509. FREE((*ppCurr)->FriendlyName);
  1510. }
  1511. if ((*ppCurr)->Description) {
  1512. FREE((*ppCurr)->Description);
  1513. }
  1514. FREE(*ppCurr);
  1515. return ERROR_NOT_ENOUGH_MEMORY;
  1516. }
  1517. /*******************************************************************************
  1518. * FindOrCreateIpAdapter
  1519. *
  1520. * This routine finds an existing IP_ADAPTER_ADDRESSES entry (if any), or
  1521. * creates a new one and appends it to a list of such entries.
  1522. *
  1523. * ENTRY pFirst - Pointer to start of list to search
  1524. * ppCurr - Location in which to return new entry
  1525. * ppNext - Previous entry's "next" pointer to update
  1526. * name - Adapter name
  1527. * Ipv4IfIndex - IPv4 Interface index
  1528. * Ipv6IfIndex - IPv6 Interface index
  1529. * AppFlags - Flags controlling what fields to skip, if any
  1530. * IfType - IANA ifType value
  1531. * Mtu - Maximum transmission unit
  1532. * PhysAddr - MAC address
  1533. * PhysAddrLen - Byte count of PhysAddr
  1534. * Description - Adapter description
  1535. * FriendlyName - User-friendly interface name
  1536. * Family - Address family constraint (for DNS servers)
  1537. *
  1538. * EXIT ppCurr and ppNext updated
  1539. *
  1540. * RETURNS Error status
  1541. *
  1542. ******************************************************************************/
  1543. DWORD FindOrCreateIpAdapter(PIP_ADAPTER_ADDRESSES pFirst, PIP_ADAPTER_ADDRESSES *ppCurr, PIP_ADAPTER_ADDRESSES **ppNext, char *AdapterName, char *NameForDnsInfo, UINT Ipv4IfIndex, UINT Ipv6IfIndex, DWORD AppFlags, DWORD IfType, SIZE_T Mtu, BYTE *PhysAddr, DWORD PhysAddrLen, PWCHAR Description, PWCHAR FriendlyName, DWORD *ZoneIndices, DWORD Family)
  1544. {
  1545. PIP_ADAPTER_ADDRESSES pIf;
  1546. DWORD dwErr;
  1547. // Look for an existing entry for the GUID.
  1548. for (pIf = pFirst; pIf; pIf = pIf->Next) {
  1549. if (!strcmp(AdapterName, pIf->AdapterName)) {
  1550. if (Ipv4IfIndex != 0) {
  1551. ASSERT(pIf->IfIndex == 0);
  1552. pIf->IfIndex = Ipv4IfIndex;
  1553. }
  1554. if (Ipv6IfIndex != 0) {
  1555. ASSERT(pIf->Ipv6IfIndex == 0);
  1556. pIf->Ipv6IfIndex = Ipv6IfIndex;
  1557. CopyMemory(pIf->ZoneIndices, ZoneIndices,
  1558. ADE_GLOBAL * sizeof(DWORD));
  1559. }
  1560. *ppCurr = pIf;
  1561. return NO_ERROR;
  1562. }
  1563. }
  1564. return NewIpAdapter(ppCurr, ppNext, AdapterName, NameForDnsInfo,
  1565. Ipv4IfIndex, Ipv6IfIndex, AppFlags, IfType, Mtu,
  1566. PhysAddr, PhysAddrLen, Description, FriendlyName,
  1567. ZoneIndices, Family);
  1568. }
  1569. __inline int IN6_IS_ADDR_6TO4(const struct in6_addr *a)
  1570. {
  1571. return ((a->s6_bytes[0] == 0x20) && (a->s6_bytes[1] == 0x02));
  1572. }
  1573. __inline int IN6_IS_ADDR_ISATAP(const struct in6_addr *a)
  1574. {
  1575. return (((a->s6_words[4] & 0xfffd) == 0) && (a->s6_words[5] == 0xfe5e));
  1576. }
  1577. //
  1578. // This array is used to convert from an internal IPv6 interface type value,
  1579. // as defined in ntddip6.h, to an IANA ifType value as defined in ipifcons.h.
  1580. //
  1581. DWORD
  1582. IPv6ToMibIfType[] = {
  1583. IF_TYPE_SOFTWARE_LOOPBACK,
  1584. IF_TYPE_ETHERNET_CSMACD,
  1585. IF_TYPE_FDDI,
  1586. IF_TYPE_TUNNEL,
  1587. IF_TYPE_TUNNEL,
  1588. IF_TYPE_TUNNEL,
  1589. IF_TYPE_TUNNEL,
  1590. IF_TYPE_TUNNEL
  1591. };
  1592. #define NUM_IPV6_IFTYPES (sizeof(IPv6ToMibIfType)/sizeof(DWORD))
  1593. /*******************************************************************************
  1594. * AddIPv6Prefix
  1595. *
  1596. * This routine adds an IP_ADAPTER_PREFIX entry for an IPv6 prefix
  1597. * to a list of entries.
  1598. *
  1599. * ENTRY Addr - IPv6 prefix (network byte order)
  1600. * MaskLen - IPv6 prefix length
  1601. * arg1 - Initial prefix entry, for duplicate avoidance
  1602. * arg2 - Previous prefix entry's "next" pointer to update
  1603. *
  1604. * EXIT Entry added and arg2 updated
  1605. *
  1606. * RETURNS Error status
  1607. *
  1608. ******************************************************************************/
  1609. DWORD AddIPv6Prefix(IN6_ADDR *Addr, DWORD MaskLen, PVOID arg1, PVOID arg2)
  1610. {
  1611. PIP_ADAPTER_PREFIX pFirst = *(PIP_ADAPTER_PREFIX*)arg1;
  1612. PIP_ADAPTER_PREFIX **ppNext = (PIP_ADAPTER_PREFIX**)arg2;
  1613. PIP_ADAPTER_PREFIX pCurr;
  1614. LPSOCKADDR_IN6 pAddr;
  1615. // Check if already in the list
  1616. for (pCurr = pFirst; pCurr; pCurr = pCurr->Next) {
  1617. if ((pCurr->PrefixLength == MaskLen) &&
  1618. (pCurr->Address.lpSockaddr->sa_family == AF_INET6) &&
  1619. IN6_ADDR_EQUAL(&((LPSOCKADDR_IN6)pCurr->Address.lpSockaddr)->sin6_addr, Addr)) {
  1620. return NO_ERROR;
  1621. }
  1622. }
  1623. pCurr = MALLOC(sizeof(IP_ADAPTER_PREFIX));
  1624. if (!pCurr) {
  1625. return ERROR_NOT_ENOUGH_MEMORY;
  1626. }
  1627. pAddr = MALLOC(sizeof(SOCKADDR_IN6));
  1628. if (!pAddr) {
  1629. FREE(pCurr);
  1630. return ERROR_NOT_ENOUGH_MEMORY;
  1631. }
  1632. memset(pAddr, 0, sizeof(SOCKADDR_IN6));
  1633. pAddr->sin6_family = AF_INET6;
  1634. pAddr->sin6_addr = *Addr;
  1635. // Add address to linked list
  1636. **ppNext = pCurr;
  1637. *ppNext = &pCurr->Next;
  1638. pCurr->Length = sizeof(IP_ADAPTER_PREFIX);
  1639. pCurr->Flags = 0;
  1640. pCurr->Next = NULL;
  1641. pCurr->Address.lpSockaddr = (LPSOCKADDR)pAddr;
  1642. pCurr->Address.iSockaddrLength = sizeof(SOCKADDR_IN6);
  1643. pCurr->PrefixLength = MaskLen;
  1644. return NO_ERROR;
  1645. }
  1646. /*******************************************************************************
  1647. * AddIPv6AutoAddressInfo
  1648. *
  1649. * This routine adds an IP_ADAPTER_UNICAST_ADDRESS entry for an IPv6 address
  1650. * on an "automatic tunnel" interface to a list of entries.
  1651. *
  1652. * ENTRY IF - IPv6 interface information
  1653. * ADE - IPv6 address entry
  1654. * arg1 - Previous entry's "next" pointer to update
  1655. * arg2 - Adapter info structure
  1656. * arg3 - "First" entry pointer to update
  1657. * Flags - flags specified by application
  1658. * Family - Address family constraint (for DNS)
  1659. *
  1660. * EXIT Entry added and arg1 updated
  1661. *
  1662. * RETURNS Error status
  1663. *
  1664. ******************************************************************************/
  1665. DWORD AddIPv6AutoAddressInfo(IPV6_INFO_INTERFACE *IF, IPV6_INFO_ADDRESS *ADE, PVOID arg1, PVOID arg2, PVOID arg3, DWORD Flags, DWORD Family)
  1666. {
  1667. PIP_ADAPTER_ADDRESSES **ppNext = (PIP_ADAPTER_ADDRESSES**)arg1;
  1668. IP_ADAPTER_INFO *pAdapterInfo = (IP_ADAPTER_INFO *)arg2;
  1669. PIP_ADAPTER_ADDRESSES pCurr, *ppFirst = (PIP_ADAPTER_ADDRESSES*)arg3;
  1670. PIP_ADAPTER_UNICAST_ADDRESS *pNextUnicastAddr;
  1671. PIP_ADAPTER_ANYCAST_ADDRESS *pNextAnycastAddr;
  1672. PIP_ADAPTER_MULTICAST_ADDRESS *pNextMulticastAddr;
  1673. PIP_ADAPTER_PREFIX *pNextPrefix;
  1674. CHAR szGuid[80];
  1675. char *NameForDnsInfo, *pszDescription;
  1676. DWORD Ipv4Address, dwErr, dwIfType;
  1677. WCHAR wszFriendlyName[MAX_FRIENDLY_NAME_LENGTH+1], *pwszDescription;
  1678. ULONG PrefixLength = 64;
  1679. IN6_ADDR Prefix;
  1680. if (ADE->Type != ADE_UNICAST) {
  1681. return NO_ERROR;
  1682. }
  1683. ConvertGuidToStringA(&IF->This.Guid, szGuid);
  1684. //
  1685. // We need the GUID ("NameForDnsInfo") of an interface which we
  1686. // can use to find additional relevant configuration information.
  1687. // For IPv6 pseudo-interfaces, we'll extract the IPv4 address, and
  1688. // find the GUID of the interface it's on, and use that, which assumes
  1689. // that configuration information (e.g. the DNS server to use) will
  1690. // still apply.
  1691. //
  1692. if (IF->Type == IPV6_IF_TYPE_TUNNEL_6TO4) {
  1693. if (IN6_IS_ADDR_6TO4(&ADE->This.Address)) {
  1694. // Extract IPv4 address from middle of IPv6 address
  1695. memcpy(&Ipv4Address, &ADE->This.Address.s6_bytes[2], sizeof(Ipv4Address));
  1696. } else {
  1697. return NO_ERROR;
  1698. }
  1699. pwszDescription = L"6to4 Tunneling Pseudo-Interface";
  1700. } else {
  1701. if (IN6_IS_ADDR_V4COMPAT(&ADE->This.Address) ||
  1702. IN6_IS_ADDR_ISATAP(&ADE->This.Address)) {
  1703. // Extract IPv4 address from last 4 bytes of IPv6 address
  1704. memcpy(&Ipv4Address, &ADE->This.Address.s6_bytes[12], sizeof(Ipv4Address));
  1705. } else {
  1706. return NO_ERROR;
  1707. }
  1708. pwszDescription = L"Automatic Tunneling Pseudo-Interface";
  1709. if (IN6_IS_ADDR_V4COMPAT(&ADE->This.Address)) {
  1710. PrefixLength = 96;
  1711. }
  1712. }
  1713. // Look for an existing interface with same physical address and index.
  1714. for (pCurr = *ppFirst; pCurr; pCurr = pCurr->Next) {
  1715. if ((pCurr->Ipv6IfIndex == ADE->This.IF.Index) &&
  1716. (*(DWORD*)pCurr->PhysicalAddress == Ipv4Address)) {
  1717. break;
  1718. }
  1719. }
  1720. if (pCurr == NULL) {
  1721. // Add an interface
  1722. NameForDnsInfo = MapIpv4AddressToName(pAdapterInfo, Ipv4Address,
  1723. &pszDescription);
  1724. if (NameForDnsInfo == NULL) {
  1725. return NO_ERROR;
  1726. }
  1727. wcscpy(wszFriendlyName, pwszDescription);
  1728. dwIfType = (IF->Type < NUM_IPV6_IFTYPES)? IPv6ToMibIfType[IF->Type]
  1729. : MIB_IF_TYPE_OTHER;
  1730. dwErr = NewIpAdapter(&pCurr, ppNext, szGuid, NameForDnsInfo,
  1731. 0, ADE->This.IF.Index, Flags, dwIfType,
  1732. IF->LinkMTU, (BYTE*)&Ipv4Address,
  1733. sizeof(Ipv4Address), pwszDescription,
  1734. wszFriendlyName, IF->ZoneIndices, Family);
  1735. if (dwErr != NO_ERROR) {
  1736. return dwErr;
  1737. }
  1738. // 6to4 and automatic tunneling interfaces don't support multicast
  1739. // today.
  1740. pCurr->Flags |= IP_ADAPTER_NO_MULTICAST;
  1741. if (*ppFirst == NULL) {
  1742. *ppFirst = pCurr;
  1743. }
  1744. }
  1745. // Add the address to the interface
  1746. pNextUnicastAddr = &pCurr->FirstUnicastAddress;
  1747. while (*pNextUnicastAddr) {
  1748. pNextUnicastAddr = &(*pNextUnicastAddr)->Next;
  1749. }
  1750. pNextAnycastAddr = &pCurr->FirstAnycastAddress;
  1751. while (*pNextAnycastAddr) {
  1752. pNextAnycastAddr = &(*pNextAnycastAddr)->Next;
  1753. }
  1754. pNextMulticastAddr = &pCurr->FirstMulticastAddress;
  1755. while (*pNextMulticastAddr) {
  1756. pNextMulticastAddr = &(*pNextMulticastAddr)->Next;
  1757. }
  1758. dwErr = AddIPv6AddressInfo(IF, ADE, &pNextUnicastAddr, &pNextAnycastAddr,
  1759. &pNextMulticastAddr, Flags, Family);
  1760. if (dwErr != NO_ERROR) {
  1761. return dwErr;
  1762. }
  1763. // Add the prefix to the interface
  1764. if (Flags & GAA_FLAG_INCLUDE_PREFIX) {
  1765. ZeroMemory(&Prefix, sizeof(Prefix));
  1766. CopyMemory(&Prefix, &ADE->This.Address, PrefixLength / 8);
  1767. pNextPrefix = &pCurr->FirstPrefix;
  1768. while (*pNextPrefix) {
  1769. pNextPrefix = &(*pNextPrefix)->Next;
  1770. }
  1771. dwErr = AddIPv6Prefix(&Prefix, PrefixLength, &pCurr->FirstPrefix,
  1772. &pNextPrefix);
  1773. }
  1774. return dwErr;
  1775. }
  1776. /*******************************************************************************
  1777. * GetString
  1778. *
  1779. * This routine reads a string value from the registry.
  1780. *
  1781. * ENTRY hKey - Handle to registry key
  1782. * lpName - Name of value to read
  1783. * pwszBuff - Buffer in which to place value read
  1784. * ulBytes - Size of buffer
  1785. *
  1786. * EXIT pwszBuff filled in
  1787. *
  1788. * RETURNS TRUE on success, FALSE on failure
  1789. *
  1790. ******************************************************************************/
  1791. BOOL
  1792. GetString(HKEY hKey, LPCWSTR lpName, PWCHAR pwszBuff, SIZE_T ulBytes)
  1793. {
  1794. DWORD dwErr, dwType;
  1795. ULONG ulSize, ulValue;
  1796. WCHAR buff[NI_MAXHOST];
  1797. ulSize = sizeof(ulValue);
  1798. dwErr = RegQueryValueExW(hKey, lpName, NULL, &dwType, (PBYTE)pwszBuff,
  1799. (LPDWORD)&ulBytes);
  1800. if (dwErr != ERROR_SUCCESS) {
  1801. return FALSE;
  1802. }
  1803. if (dwType != REG_SZ) {
  1804. return FALSE;
  1805. }
  1806. return TRUE;
  1807. }
  1808. BOOL MapAdapterNameToFriendlyName(GUID *Guid, char *name, PWCHAR pwszFriendlyName, ULONG ulNumChars)
  1809. {
  1810. DWORD dwErr, dwTemp;
  1811. dwTemp = ulNumChars;
  1812. //
  1813. // The following call can be time-consuming the first time it is called.
  1814. // If the caller doesn't need the friendly name, it should use the
  1815. // GAA_FLAG_SKIP_FRIENDLY_NAME flag, in which case we won't get called.
  1816. //
  1817. dwErr = HrLanConnectionNameFromGuidOrPath(Guid, NULL, pwszFriendlyName,
  1818. &dwTemp);
  1819. if (dwErr == NO_ERROR) {
  1820. return TRUE;
  1821. }
  1822. dwTemp = ulNumChars;
  1823. dwErr = NhGetInterfaceNameFromDeviceGuid(Guid, pwszFriendlyName, &dwTemp,
  1824. TRUE, FALSE );
  1825. if (dwErr == NO_ERROR) {
  1826. return TRUE;
  1827. }
  1828. MultiByteToWideChar(CP_ACP, 0, name, -1, pwszFriendlyName, ulNumChars);
  1829. return FALSE;
  1830. }
  1831. #define KEY_TCPIP6_IF L"System\\CurrentControlSet\\Services\\Tcpip6\\Parameters\\Interfaces"
  1832. VOID MapIpv6AdapterNameToFriendlyName(GUID *Guid, char *name, PWCHAR pwszFriendlyName, ULONG ulBytes)
  1833. {
  1834. DWORD dwErr;
  1835. HKEY hInterfaces = NULL, hIf = NULL;
  1836. CHAR szGuid[40];
  1837. if (MapAdapterNameToFriendlyName(Guid, name, pwszFriendlyName,
  1838. ulBytes/sizeof(WCHAR))) {
  1839. return;
  1840. }
  1841. dwErr = RegOpenKeyExW(HKEY_LOCAL_MACHINE, KEY_TCPIP6_IF, 0, GENERIC_READ,
  1842. &hInterfaces);
  1843. if (dwErr != NO_ERROR) {
  1844. goto Fail;
  1845. }
  1846. dwErr = RegOpenKeyEx(hInterfaces, name, 0, GENERIC_READ, &hIf);
  1847. if (dwErr != NO_ERROR) {
  1848. goto Fail;
  1849. }
  1850. if (GetString(hIf, L"FriendlyName", pwszFriendlyName, ulBytes)) {
  1851. goto Cleanup;
  1852. }
  1853. Fail:
  1854. ConvertGuidToStringA(Guid, szGuid);
  1855. MultiByteToWideChar(CP_ACP, 0, szGuid, -1,
  1856. pwszFriendlyName, ulBytes / sizeof(WCHAR));
  1857. Cleanup:
  1858. if (hInterfaces) {
  1859. RegCloseKey(hInterfaces);
  1860. }
  1861. if (hIf) {
  1862. RegCloseKey(hIf);
  1863. }
  1864. }
  1865. IN6_ADDR Ipv6LinkLocalPrefix = { 0xfe, 0x80 };
  1866. /*******************************************************************************
  1867. * ForEachIPv6Prefix
  1868. *
  1869. * This routine walks the IPv6 routing table and invokes a given function
  1870. * on each prefix on a given interface.
  1871. *
  1872. * ENTRY Ipv6IfIndex - IPv6 interface index
  1873. * func - Function to invoke on each address
  1874. * arg1 - Argument to pass to func
  1875. * arg2 - Argument to pass to func
  1876. *
  1877. * EXIT Nothing
  1878. *
  1879. * RETURNS Error status
  1880. *
  1881. ******************************************************************************/
  1882. DWORD ForEachIPv6Prefix(ULONG Ipv6IfIndex, DWORD (*func)(IN6_ADDR *, DWORD, PVOID, PVOID), PVOID arg1, PVOID arg2)
  1883. {
  1884. IPV6_QUERY_ROUTE_TABLE Query, NextQuery;
  1885. IPV6_INFO_ROUTE_TABLE RTE;
  1886. DWORD BytesIn, BytesReturned, dwCount = 0;
  1887. ULONG MaskLen, dwErr = NO_ERROR;
  1888. BOOL SawLinkLocal = FALSE;
  1889. ZeroMemory(&NextQuery, sizeof(NextQuery));
  1890. for (;;) {
  1891. Query = NextQuery;
  1892. BytesIn = sizeof Query;
  1893. BytesReturned = sizeof RTE;
  1894. dwErr = WsControl(IPPROTO_IPV6,
  1895. IOCTL_IPV6_QUERY_ROUTE_TABLE,
  1896. &Query, &BytesIn,
  1897. &RTE, &BytesReturned);
  1898. if (dwErr != NO_ERROR) {
  1899. return dwErr;
  1900. }
  1901. NextQuery = RTE.Next;
  1902. RTE.This = Query;
  1903. // Skip if it's not an onlink prefix for this interface.
  1904. if ((RTE.This.Neighbor.IF.Index == Ipv6IfIndex) &&
  1905. !IN6_IS_ADDR_MULTICAST(&RTE.This.Prefix)) {
  1906. if (IN6_IS_ADDR_LINKLOCAL(&RTE.This.Prefix)) {
  1907. // This interface has link-local addresses
  1908. // (the 6to4 interface, for example, does not).
  1909. SawLinkLocal = TRUE;
  1910. }
  1911. if ((RTE.Type != RTE_TYPE_SYSTEM) &&
  1912. IN6_IS_ADDR_UNSPECIFIED(&RTE.This.Neighbor.Address)) {
  1913. dwErr = func(&RTE.This.Prefix, RTE.This.PrefixLength,
  1914. arg1, arg2);
  1915. if (dwErr != NO_ERROR) {
  1916. return dwErr;
  1917. }
  1918. }
  1919. }
  1920. if (NextQuery.Neighbor.IF.Index == 0) {
  1921. break;
  1922. }
  1923. }
  1924. if (SawLinkLocal) {
  1925. dwErr = func(&Ipv6LinkLocalPrefix, 64, arg1, arg2);
  1926. }
  1927. return dwErr;
  1928. }
  1929. //
  1930. // This array is used to convert from an internal IPv6 media status value,
  1931. // as defined in ntddip6.h, to a MIB ifOperStatus value as defined in
  1932. // iptypes.h.
  1933. //
  1934. DWORD
  1935. IPv6ToMibOperStatus[] = {
  1936. IfOperStatusDown, // IPV6_IF_MEDIA_STATUS_DISCONNECTED
  1937. IfOperStatusUp, // IPV6_IF_MEDIA_STATUS_RECONNECTED
  1938. IfOperStatusUp, // IPV6_IF_MEDIA_STATUS_CONNECTED
  1939. };
  1940. #define NUM_IPV6_MEDIA_STATUSES (sizeof(IPv6ToMibOperStatus)/sizeof(DWORD))
  1941. #define IPV6_LOOPBACK_NAME L"Loopback Pseudo-Interface"
  1942. #define IPV6_TEREDO_NAME L"Teredo Tunneling Pseudo-Interface"
  1943. /*******************************************************************************
  1944. * AddIPv6InterfaceInfo
  1945. *
  1946. * This routine adds an IP_ADAPTER_ADDRESSES entry for an IPv6 interface
  1947. * to a list of such entries.
  1948. *
  1949. * ENTRY IF - IPv6 interface information
  1950. * arg1 - Previous entry's "next" pointer to update
  1951. * arg2 - Pointer to start of interface list
  1952. * pAdapterInfo - Additional adapter information
  1953. * Flags - Flags specified by application
  1954. * Family - Address family constraint (for DNS servers)
  1955. *
  1956. * EXIT Entry added and arg1 updated
  1957. *
  1958. * RETURNS Error status
  1959. *
  1960. ******************************************************************************/
  1961. DWORD AddIPv6InterfaceInfo(IPV6_INFO_INTERFACE *IF, PVOID arg1, PVOID arg2, IP_ADAPTER_INFO *pAdapterInfo, DWORD Flags, DWORD Family)
  1962. {
  1963. DWORD dwErr = NO_ERROR;
  1964. PIP_ADAPTER_ADDRESSES **ppNext = (PIP_ADAPTER_ADDRESSES**)arg1;
  1965. PIP_ADAPTER_ADDRESSES pFirst = *(PIP_ADAPTER_ADDRESSES*)arg2;
  1966. PIP_ADAPTER_ADDRESSES pCurr;
  1967. PIP_ADAPTER_UNICAST_ADDRESS *pNextUnicastAddr;
  1968. PIP_ADAPTER_ANYCAST_ADDRESS *pNextAnycastAddr;
  1969. PIP_ADAPTER_MULTICAST_ADDRESS *pNextMulticastAddr;
  1970. PIP_ADAPTER_PREFIX *pNextPrefix;
  1971. char *NameForDnsInfo = NULL, *pszDescription;
  1972. u_char *LinkLayerAddress;
  1973. DWORD Ipv4Address, dwIfType;
  1974. WCHAR wszDescription[MAX_ADAPTER_DESCRIPTION_LENGTH + 4];
  1975. WCHAR wszFriendlyName[MAX_FRIENDLY_NAME_LENGTH + 1];
  1976. CHAR AdapterName[MAX_ADAPTER_NAME_LENGTH + 1];
  1977. LinkLayerAddress = (u_char *)(IF + 1);
  1978. ConvertGuidToStringA(&IF->This.Guid, AdapterName);
  1979. //
  1980. // Get a description and adapter name.
  1981. //
  1982. switch (IF->Type) {
  1983. case IPV6_IF_TYPE_TUNNEL_6TO4:
  1984. wcscpy(wszDescription, L"6to4 Pseudo-Interface");
  1985. NameForDnsInfo = AdapterName;
  1986. pCurr = NULL;
  1987. dwErr = ForEachIPv6Address(IF, AddIPv6AutoAddressInfo,
  1988. ppNext, pAdapterInfo, (PVOID)&pCurr, Flags,
  1989. Family);
  1990. if (dwErr != NO_ERROR) {
  1991. return dwErr;
  1992. }
  1993. //
  1994. // Ensure that there exists an entry for the 6to4 interface.
  1995. //
  1996. if (pCurr == NULL) {
  1997. dwErr = NewIpAdapter(&pCurr, ppNext, AdapterName,
  1998. NameForDnsInfo, 0, IF->This.Index, Flags,
  1999. IF_TYPE_TUNNEL, IF->LinkMTU,
  2000. LinkLayerAddress, IF->LinkLayerAddressLength,
  2001. wszDescription, wszDescription,
  2002. IF->ZoneIndices, Family);
  2003. }
  2004. return dwErr;
  2005. case IPV6_IF_TYPE_TUNNEL_AUTO:
  2006. wcscpy(wszDescription, L"Automatic Tunneling Pseudo-Interface");
  2007. NameForDnsInfo = AdapterName;
  2008. pCurr = NULL;
  2009. dwErr = ForEachIPv6Address(IF, AddIPv6AutoAddressInfo,
  2010. ppNext, pAdapterInfo, (PVOID)&pCurr, Flags,
  2011. Family);
  2012. if (dwErr != NO_ERROR) {
  2013. return dwErr;
  2014. }
  2015. //
  2016. // Ensure that there exists an entry for the ISATAP interface.
  2017. //
  2018. if (pCurr == NULL) {
  2019. dwErr = NewIpAdapter(&pCurr, ppNext, AdapterName,
  2020. NameForDnsInfo, 0, IF->This.Index, Flags,
  2021. IF_TYPE_TUNNEL, IF->LinkMTU,
  2022. LinkLayerAddress, IF->LinkLayerAddressLength,
  2023. wszDescription, wszDescription,
  2024. IF->ZoneIndices, Family);
  2025. }
  2026. return dwErr;
  2027. case IPV6_IF_TYPE_TUNNEL_6OVER4:
  2028. wcscpy(wszDescription, L"6over4 Pseudo-Interface");
  2029. memcpy(&Ipv4Address, LinkLayerAddress, sizeof(Ipv4Address));
  2030. NameForDnsInfo = MapIpv4AddressToName(pAdapterInfo, Ipv4Address, &pszDescription);
  2031. if (NameForDnsInfo == NULL) {
  2032. //
  2033. // IPv4 address does not exist, so just use the interface GUID.
  2034. //
  2035. NameForDnsInfo = AdapterName;
  2036. }
  2037. break;
  2038. case IPV6_IF_TYPE_TUNNEL_V6V4:
  2039. wcscpy(wszDescription, L"Configured Tunnel Interface");
  2040. memcpy(&Ipv4Address, LinkLayerAddress, sizeof(Ipv4Address));
  2041. NameForDnsInfo = MapIpv4AddressToName(pAdapterInfo, Ipv4Address, &pszDescription);
  2042. if (NameForDnsInfo == NULL) {
  2043. //
  2044. // IPv4 address does not exist, so just use the interface GUID.
  2045. //
  2046. NameForDnsInfo = AdapterName;
  2047. }
  2048. break;
  2049. case IPV6_IF_TYPE_TUNNEL_TEREDO:
  2050. wcscpy(wszDescription, IPV6_TEREDO_NAME);
  2051. NameForDnsInfo = AdapterName;
  2052. break;
  2053. case IPV6_IF_TYPE_LOOPBACK:
  2054. wcscpy(wszDescription, IPV6_LOOPBACK_NAME);
  2055. NameForDnsInfo = AdapterName;
  2056. break;
  2057. default:
  2058. NameForDnsInfo = MapGuidToAdapterName(pAdapterInfo,
  2059. &IF->This.Guid,
  2060. wszDescription);
  2061. if (NameForDnsInfo != NULL) {
  2062. strcpy(AdapterName, NameForDnsInfo);
  2063. }
  2064. }
  2065. if (Flags & GAA_FLAG_SKIP_FRIENDLY_NAME) {
  2066. wszFriendlyName[0] = L'\0';
  2067. } else if (IF->Type == IPV6_IF_TYPE_TUNNEL_TEREDO) {
  2068. //
  2069. // The Teredo interface does not have a friendly name.
  2070. //
  2071. wcscpy(wszFriendlyName, IPV6_TEREDO_NAME);
  2072. } else if (IF->Type == IPV6_IF_TYPE_LOOPBACK) {
  2073. //
  2074. // The IPv6 loopback interface will not have a friendly name,
  2075. // so use the same string as the description we set above.
  2076. //
  2077. wcscpy(wszFriendlyName, IPV6_LOOPBACK_NAME);
  2078. } else {
  2079. MapIpv6AdapterNameToFriendlyName(&IF->This.Guid, AdapterName,
  2080. wszFriendlyName,
  2081. sizeof(wszFriendlyName));
  2082. }
  2083. dwIfType = (IF->Type < NUM_IPV6_IFTYPES)? IPv6ToMibIfType[IF->Type]
  2084. : MIB_IF_TYPE_OTHER;
  2085. dwErr = FindOrCreateIpAdapter(pFirst, &pCurr, ppNext, AdapterName,
  2086. NameForDnsInfo, 0, IF->This.Index, Flags,
  2087. dwIfType, IF->LinkMTU, LinkLayerAddress,
  2088. IF->LinkLayerAddressLength, wszDescription,
  2089. wszFriendlyName, IF->ZoneIndices, Family);
  2090. if (dwErr != NO_ERROR) {
  2091. return dwErr;
  2092. }
  2093. if (IF->OtherStatefulConfig != 0) {
  2094. pCurr->Flags |= IP_ADAPTER_IPV6_OTHER_STATEFUL_CONFIG;
  2095. }
  2096. pCurr->OperStatus = (IF->MediaStatus < NUM_IPV6_MEDIA_STATUSES)
  2097. ? IPv6ToMibOperStatus[IF->MediaStatus]
  2098. : IfOperStatusUnknown;
  2099. // Add addresses
  2100. pNextUnicastAddr = &pCurr->FirstUnicastAddress;
  2101. while (*pNextUnicastAddr) {
  2102. pNextUnicastAddr = &(*pNextUnicastAddr)->Next;
  2103. }
  2104. pNextAnycastAddr = &pCurr->FirstAnycastAddress;
  2105. while (*pNextAnycastAddr) {
  2106. pNextAnycastAddr = &(*pNextAnycastAddr)->Next;
  2107. }
  2108. pNextMulticastAddr = &pCurr->FirstMulticastAddress;
  2109. while (*pNextMulticastAddr) {
  2110. pNextMulticastAddr = &(*pNextMulticastAddr)->Next;
  2111. }
  2112. dwErr = ForEachIPv6Address(IF, AddIPv6AddressInfo, &pNextUnicastAddr,
  2113. &pNextAnycastAddr, &pNextMulticastAddr, Flags,
  2114. Family);
  2115. if (dwErr != NO_ERROR) {
  2116. return dwErr;
  2117. }
  2118. // Add prefixes
  2119. if (Flags & GAA_FLAG_INCLUDE_PREFIX) {
  2120. pNextPrefix = &pCurr->FirstPrefix;
  2121. while (*pNextPrefix) {
  2122. pNextPrefix = &(*pNextPrefix)->Next;
  2123. }
  2124. dwErr = ForEachIPv6Prefix(IF->This.Index, AddIPv6Prefix,
  2125. &pCurr->FirstPrefix, &pNextPrefix);
  2126. }
  2127. return dwErr;
  2128. }
  2129. #define MAX_LINK_LEVEL_ADDRESS_LENGTH 64
  2130. /*******************************************************************************
  2131. * ForEachIPv6Interface
  2132. *
  2133. * This routine walks a set of IPv6 interfaces and invokes a given function
  2134. * on each one.
  2135. *
  2136. * ENTRY func - Function to invoke on each interface
  2137. * arg1 - Argument to pass to func
  2138. * arg2 - Argument to pass to func
  2139. * pAdapterInfo - List of adapter information
  2140. * Flags - Flags to pass to func
  2141. * Family - Address family constraint (for DNS servers)
  2142. *
  2143. * EXIT Nothing
  2144. *
  2145. * RETURNS Error status
  2146. *
  2147. ******************************************************************************/
  2148. DWORD ForEachIPv6Interface(DWORD (*func)(IPV6_INFO_INTERFACE *, PVOID, PVOID, IP_ADAPTER_INFO *, DWORD, DWORD), PVOID arg1, PVOID arg2, IP_ADAPTER_INFO *pAdapterInfo, DWORD Flags, DWORD Family)
  2149. {
  2150. IPV6_QUERY_INTERFACE Query;
  2151. IPV6_INFO_INTERFACE *IF;
  2152. u_int InfoSize, BytesReturned, BytesIn;
  2153. DWORD dwErr;
  2154. InfoSize = sizeof *IF + 2 * MAX_LINK_LEVEL_ADDRESS_LENGTH;
  2155. IF = (IPV6_INFO_INTERFACE *) MALLOC(InfoSize);
  2156. if (IF == NULL) {
  2157. return ERROR_NOT_ENOUGH_MEMORY;
  2158. }
  2159. Query.Index = (u_int) -1;
  2160. for (;;) {
  2161. BytesIn = sizeof Query;
  2162. BytesReturned = InfoSize;
  2163. dwErr = WsControl( IPPROTO_IPV6,
  2164. IOCTL_IPV6_QUERY_INTERFACE,
  2165. &Query, &BytesIn,
  2166. IF, &BytesReturned);
  2167. if (dwErr != NO_ERROR) {
  2168. if (dwErr == ERROR_FILE_NOT_FOUND) {
  2169. // IPv6 is not installed
  2170. dwErr = NO_ERROR;
  2171. }
  2172. break;
  2173. }
  2174. if (Query.Index != (u_int) -1) {
  2175. if ((BytesReturned < sizeof *IF) ||
  2176. (IF->Length < sizeof *IF) ||
  2177. (BytesReturned != IF->Length +
  2178. ((IF->LocalLinkLayerAddress != 0) ?
  2179. IF->LinkLayerAddressLength : 0) +
  2180. ((IF->RemoteLinkLayerAddress != 0) ?
  2181. IF->LinkLayerAddressLength : 0))) {
  2182. dwErr = ERROR_INVALID_PARAMETER;
  2183. break;
  2184. }
  2185. dwErr = (*func)(IF, arg1, arg2, pAdapterInfo, Flags, Family);
  2186. if (dwErr != NO_ERROR) {
  2187. break;
  2188. }
  2189. }
  2190. if (IF->Next.Index == (u_int) -1)
  2191. break;
  2192. Query = IF->Next;
  2193. }
  2194. FREE(IF);
  2195. return dwErr;
  2196. }
  2197. //
  2198. // IPv4 equivalents of some standard IN6_* macros
  2199. //
  2200. #define IN_IS_ADDR_LOOPBACK(x) (*(x) == INADDR_LOOPBACK)
  2201. #define IN_IS_ADDR_LINKLOCAL(x) ((*(x) & 0x0000ffff) == 0x0000fea9)
  2202. /*******************************************************************************
  2203. * AddIPv4MulticastAddressInfo
  2204. *
  2205. * This routine adds an IP_ADAPTER_MULTICAST_ADDRESS entry for an IPv4 address
  2206. * to a list of entries.
  2207. *
  2208. * ENTRY IF - interface information
  2209. * Addr - IPv4 address
  2210. * pFirst - First multicast entry
  2211. * ppNext - Previous multicast entry's "next" pointer to update
  2212. *
  2213. * EXIT Entry added and args updated
  2214. *
  2215. * RETURNS Error status
  2216. *
  2217. ******************************************************************************/
  2218. DWORD AddIPv4MulticastAddressInfo(IP_ADAPTER_INFO *IF, DWORD Addr, PIP_ADAPTER_MULTICAST_ADDRESS *pFirst, PIP_ADAPTER_MULTICAST_ADDRESS **ppNext)
  2219. {
  2220. DWORD dwErr = NO_ERROR;
  2221. PIP_ADAPTER_MULTICAST_ADDRESS pCurr;
  2222. SOCKADDR_IN *pAddr;
  2223. for (pCurr=*pFirst; pCurr; pCurr=pCurr->Next) {
  2224. pAddr = (SOCKADDR_IN *)pCurr->Address.lpSockaddr;
  2225. if (pAddr->sin_family == AF_INET
  2226. && pAddr->sin_addr.s_addr == Addr) {
  2227. return NO_ERROR;
  2228. }
  2229. }
  2230. pCurr = MALLOC(sizeof(IP_ADAPTER_MULTICAST_ADDRESS));
  2231. if (!pCurr) {
  2232. return ERROR_NOT_ENOUGH_MEMORY;
  2233. }
  2234. pAddr = MALLOC(sizeof(SOCKADDR_IN));
  2235. if (!pAddr) {
  2236. FREE(pCurr);
  2237. return ERROR_NOT_ENOUGH_MEMORY;
  2238. }
  2239. memset(pAddr, 0, sizeof(SOCKADDR_IN));
  2240. pAddr->sin_family = AF_INET;
  2241. pAddr->sin_addr.s_addr = Addr;
  2242. // Add address to linked list
  2243. **ppNext = pCurr;
  2244. *ppNext = &pCurr->Next;
  2245. pCurr->Next = NULL;
  2246. pCurr->Length = sizeof(IP_ADAPTER_MULTICAST_ADDRESS);
  2247. pCurr->Flags = 0;
  2248. pCurr->Address.iSockaddrLength = sizeof(SOCKADDR_IN);
  2249. pCurr->Address.lpSockaddr = (LPSOCKADDR)pAddr;
  2250. return dwErr;
  2251. }
  2252. /*******************************************************************************
  2253. * AddIPv4UnicastAddressInfo
  2254. *
  2255. * This routine adds an IP_ADAPTER_UNICAST_ADDRESS entry for an IPv4 address
  2256. * to a list of entries.
  2257. *
  2258. * ENTRY IF - IPv4 interface information
  2259. * ADE - IPv4 address entry
  2260. * arg1 - Previous unicast entry's "next" pointer to update
  2261. * arg2 - Initial multicast entry, for duplicate avoidance
  2262. * arg3 - Previous multicast entry's "next" pointer to update
  2263. * AppFlags - Flags specified by application
  2264. *
  2265. * EXIT Entry added and arg1 updated
  2266. *
  2267. * RETURNS Error status
  2268. *
  2269. ******************************************************************************/
  2270. DWORD AddIPv4UnicastAddressInfo(IP_ADAPTER_INFO *IF, MIB_IPADDRROW *ADE, PVOID arg1, PVOID arg2, PVOID arg3, PVOID arg4, DWORD AppFlags)
  2271. {
  2272. PIP_ADAPTER_UNICAST_ADDRESS **ppNext = (PIP_ADAPTER_UNICAST_ADDRESS**)arg1;
  2273. PIP_ADAPTER_UNICAST_ADDRESS pCurr;
  2274. SOCKADDR_IN *pAddr;
  2275. DWORD Address, *pIfFlags = (DWORD *)arg4;
  2276. time_t Curtime;
  2277. DWORD dwStatus = NO_ERROR, i;
  2278. Address = ADE->dwAddr;
  2279. if (!Address) {
  2280. // Do nothing if address is 0.0.0.0
  2281. return NO_ERROR;
  2282. }
  2283. if ((Address & 0x000000FF) == 0) {
  2284. //
  2285. // An address in 0/8 isn't a real IP address, it's a fake one that
  2286. // the IPv4 stack sticks on a receive-only adapter.
  2287. //
  2288. (*pIfFlags) |= IP_ADAPTER_RECEIVE_ONLY;
  2289. return NO_ERROR;
  2290. }
  2291. if (!(AppFlags & GAA_FLAG_SKIP_UNICAST)) {
  2292. pCurr = MALLOC(sizeof(IP_ADAPTER_UNICAST_ADDRESS));
  2293. if (!pCurr) {
  2294. return ERROR_NOT_ENOUGH_MEMORY;
  2295. }
  2296. pAddr = MALLOC(sizeof(SOCKADDR_IN));
  2297. if (!pAddr) {
  2298. FREE(pCurr);
  2299. return ERROR_NOT_ENOUGH_MEMORY;
  2300. }
  2301. memset(pAddr, 0, sizeof(SOCKADDR_IN));
  2302. pAddr->sin_family = AF_INET;
  2303. memcpy(&pAddr->sin_addr, &Address, sizeof(Address));
  2304. // Add address to linked list
  2305. **ppNext = pCurr;
  2306. *ppNext = &pCurr->Next;
  2307. time(&Curtime);
  2308. pCurr->Next = NULL;
  2309. pCurr->Length = sizeof(IP_ADAPTER_UNICAST_ADDRESS);
  2310. pCurr->LeaseLifetime = (ULONG)(IF->LeaseExpires - Curtime);
  2311. pCurr->ValidLifetime = pCurr->PreferredLifetime = pCurr->LeaseLifetime;
  2312. pCurr->Flags = 0;
  2313. pCurr->Address.iSockaddrLength = sizeof(SOCKADDR_IN);
  2314. pCurr->Address.lpSockaddr = (LPSOCKADDR)pAddr;
  2315. pCurr->PrefixOrigin = IpPrefixOriginManual;
  2316. pCurr->SuffixOrigin = IpSuffixOriginManual;
  2317. if (IF->DhcpEnabled) {
  2318. if (IN_IS_ADDR_LINKLOCAL(&Address)) {
  2319. pCurr->PrefixOrigin = IpPrefixOriginWellKnown;
  2320. pCurr->SuffixOrigin = IpSuffixOriginRandom;
  2321. } else {
  2322. pCurr->PrefixOrigin = IpPrefixOriginDhcp;
  2323. pCurr->SuffixOrigin = IpSuffixOriginDhcp;
  2324. }
  2325. }
  2326. pCurr->DadState = IpDadStatePreferred;
  2327. if ((pCurr->DadState == IpDadStatePreferred) &&
  2328. (pCurr->SuffixOrigin != IpSuffixOriginRandom) &&
  2329. !IN_IS_ADDR_LOOPBACK(&Address) &&
  2330. !IN_IS_ADDR_LINKLOCAL(&Address)) {
  2331. pCurr->Flags |= IP_ADAPTER_ADDRESS_DNS_ELIGIBLE;
  2332. }
  2333. if (ADE->wType & MIB_IPADDR_TRANSIENT) {
  2334. pCurr->Flags |= IP_ADAPTER_ADDRESS_TRANSIENT;
  2335. }
  2336. }
  2337. // Now add any new multicast addresses
  2338. if (!(AppFlags & GAA_FLAG_SKIP_MULTICAST)) {
  2339. DWORD *pIgmpList = NULL;
  2340. DWORD dwTotal, dwOutBufLen = 0;
  2341. dwStatus = GetIgmpList(Address, pIgmpList, &dwOutBufLen);
  2342. if (dwStatus == ERROR_INSUFFICIENT_BUFFER) {
  2343. pIgmpList = MALLOC(dwOutBufLen);
  2344. if (!pIgmpList) {
  2345. return ERROR_NOT_ENOUGH_MEMORY;
  2346. }
  2347. dwStatus = GetIgmpList(Address, pIgmpList, &dwOutBufLen);
  2348. }
  2349. if (dwStatus != NO_ERROR) {
  2350. if (pIgmpList) {
  2351. FREE(pIgmpList);
  2352. }
  2353. return dwStatus;
  2354. }
  2355. dwTotal = dwOutBufLen/sizeof(Address);
  2356. for (i=0; (i<dwTotal) && (dwStatus == NO_ERROR); i++) {
  2357. dwStatus = AddIPv4MulticastAddressInfo(IF, pIgmpList[i],
  2358. (PIP_ADAPTER_MULTICAST_ADDRESS *)arg2,
  2359. (PIP_ADAPTER_MULTICAST_ADDRESS **)arg3);
  2360. }
  2361. if (pIgmpList) {
  2362. FREE(pIgmpList);
  2363. }
  2364. }
  2365. return dwStatus;
  2366. }
  2367. /*******************************************************************************
  2368. * ForEachIPv4Address
  2369. *
  2370. * This routine walks a set of IPv4 addresses and invokes a given function
  2371. * on each one.
  2372. *
  2373. * ENTRY IF - IPv4 interface information
  2374. * func - Function to invoke on each address
  2375. * arg1 - Argument to pass to func
  2376. * arg2 - Argument to pass to func
  2377. * arg3 - Argument to pass to func
  2378. * Flags - Flags to pass to func
  2379. * pIpAddrTable - IPv4 address table with per-address flags
  2380. *
  2381. * EXIT Nothing
  2382. *
  2383. * RETURNS Error status
  2384. *
  2385. ******************************************************************************/
  2386. DWORD ForEachIPv4Address(IP_ADAPTER_INFO *IF, DWORD (*func)(IP_ADAPTER_INFO *,PMIB_IPADDRROW, PVOID, PVOID, PVOID, PVOID, DWORD), PVOID arg1, PVOID arg2, PVOID arg3, PVOID arg4, DWORD Flags, PMIB_IPADDRTABLE pIpAddrTable)
  2387. {
  2388. DWORD dwErr, i;
  2389. PMIB_IPADDRROW ADE;
  2390. for (i=0; i<pIpAddrTable->dwNumEntries; i++) {
  2391. ADE = &pIpAddrTable->table[i];
  2392. if (ADE->dwIndex != IF->Index) {
  2393. continue;
  2394. }
  2395. dwErr = (*func)(IF, ADE, arg1, arg2, arg3, arg4, Flags);
  2396. if (dwErr != NO_ERROR) {
  2397. return dwErr;
  2398. }
  2399. }
  2400. return NO_ERROR;
  2401. }
  2402. DWORD
  2403. MaskToMaskLen(
  2404. DWORD dwMask
  2405. )
  2406. {
  2407. register int i;
  2408. for (i=0; i<32 && !(dwMask & (1<<i)); i++);
  2409. return 32-i;
  2410. }
  2411. /*******************************************************************************
  2412. * AddIPv4Prefix
  2413. *
  2414. * This routine adds an IP_ADAPTER_PREFIX entry for an IPv4 prefix
  2415. * to a list of entries.
  2416. *
  2417. * ENTRY IF - IPv4 interface information
  2418. * Addr - IPv4 prefix (network byte order)
  2419. * MaskLen - IPv4 prefix length
  2420. * arg1 - Initial prefix entry, for duplicate avoidance
  2421. * arg2 - Previous prefix entry's "next" pointer to update
  2422. *
  2423. * EXIT Entry added and arg2 updated
  2424. *
  2425. * RETURNS Error status
  2426. *
  2427. ******************************************************************************/
  2428. DWORD AddIPv4Prefix(DWORD Addr, DWORD MaskLen, PVOID arg1, PVOID arg2)
  2429. {
  2430. PIP_ADAPTER_PREFIX pFirst = *(PIP_ADAPTER_PREFIX*)arg1;
  2431. PIP_ADAPTER_PREFIX **ppNext = (PIP_ADAPTER_PREFIX**)arg2;
  2432. PIP_ADAPTER_PREFIX pCurr;
  2433. LPSOCKADDR_IN pAddr;
  2434. // Check if already in the list
  2435. for (pCurr = pFirst; pCurr; pCurr = pCurr->Next) {
  2436. if ((pCurr->PrefixLength == MaskLen) &&
  2437. (pCurr->Address.lpSockaddr->sa_family == AF_INET) &&
  2438. (((LPSOCKADDR_IN)pCurr->Address.lpSockaddr)->sin_addr.s_addr == Addr)) {
  2439. return NO_ERROR;
  2440. }
  2441. }
  2442. pCurr = MALLOC(sizeof(IP_ADAPTER_PREFIX));
  2443. if (!pCurr) {
  2444. return ERROR_NOT_ENOUGH_MEMORY;
  2445. }
  2446. pAddr = MALLOC(sizeof(SOCKADDR_IN));
  2447. if (!pAddr) {
  2448. FREE(pCurr);
  2449. return ERROR_NOT_ENOUGH_MEMORY;
  2450. }
  2451. memset(pAddr, 0, sizeof(SOCKADDR_IN));
  2452. pAddr->sin_family = AF_INET;
  2453. pAddr->sin_addr.s_addr = Addr;
  2454. // Add address to linked list
  2455. **ppNext = pCurr;
  2456. *ppNext = &pCurr->Next;
  2457. pCurr->Length = sizeof(IP_ADAPTER_PREFIX);
  2458. pCurr->Flags = 0;
  2459. pCurr->Next = NULL;
  2460. pCurr->Address.lpSockaddr = (LPSOCKADDR)pAddr;
  2461. pCurr->Address.iSockaddrLength = sizeof(SOCKADDR_IN);
  2462. pCurr->PrefixLength = MaskLen;
  2463. return NO_ERROR;
  2464. }
  2465. /*******************************************************************************
  2466. * ForEachIPv4Prefix
  2467. *
  2468. * This routine walks a set of IPv4 prefixes and invokes a given function
  2469. * on each one.
  2470. *
  2471. * ENTRY IF - IPv4 interface information
  2472. * func - Function to invoke on each address
  2473. * arg1 - Argument to pass to func
  2474. * arg2 - Argument to pass to func
  2475. *
  2476. * EXIT Nothing
  2477. *
  2478. * RETURNS Error status
  2479. *
  2480. ******************************************************************************/
  2481. DWORD ForEachIPv4Prefix(IP_ADAPTER_INFO *IF, DWORD (*func)(DWORD, DWORD, PVOID, PVOID), PVOID arg1, PVOID arg2)
  2482. {
  2483. PIP_ADDR_STRING Prefix;
  2484. DWORD Addr, Mask, MaskLen, dwErr;
  2485. for (Prefix = &IF->IpAddressList; Prefix; Prefix = Prefix->Next) {
  2486. if (Prefix->IpAddress.String[0] == '\0') {
  2487. continue;
  2488. }
  2489. Mask = inet_addr(Prefix->IpMask.String);
  2490. Addr = inet_addr(Prefix->IpAddress.String) & Mask;
  2491. MaskLen = MaskToMaskLen(ntohl(Mask));
  2492. dwErr = func(Addr, MaskLen, arg1, arg2);
  2493. if (dwErr != NO_ERROR) {
  2494. return dwErr;
  2495. }
  2496. }
  2497. return NO_ERROR;
  2498. }
  2499. //
  2500. // This array is used to convert from an internal IPv4 oper status value,
  2501. // as defined in ipifcons.h, to a MIB ifOperStatus value as defined in
  2502. // iptypes.h.
  2503. //
  2504. DWORD
  2505. IPv4ToMibOperStatus[] = {
  2506. IfOperStatusDown, // IF_OPER_STATUS_NON_OPERATIONAL
  2507. IfOperStatusDown, // IF_OPER_STATUS_UNREACHABLE
  2508. IfOperStatusDormant, // IF_OPER_STATUS_DISCONNECTED
  2509. IfOperStatusDormant, // IF_OPER_STATUS_CONNECTING
  2510. IfOperStatusUp, // IF_OPER_STATUS_CONNECTED
  2511. IfOperStatusUp, // IF_OPER_STATUS_OPERATIONAL
  2512. };
  2513. #define NUM_IPV4_OPER_STATUSES (sizeof(IPv4ToMibOperStatus)/sizeof(DWORD))
  2514. /*******************************************************************************
  2515. * AddIPv4InterfaceInfo
  2516. *
  2517. * This routine adds an IP_ADAPTER_ADDRESSES entry for an IPv4 interface
  2518. * to a list of such entries.
  2519. *
  2520. * ENTRY IF - IPv4 interface information
  2521. * arg1 - Previous entry's "next" pointer to update
  2522. * arg2 - Pointer to start of interface list
  2523. * Flags - Flags controlling what fields to skip, if any
  2524. * Family - Address family constraint (for DNS server addresses)
  2525. * pAddrTable - IPv4 address table
  2526. *
  2527. * EXIT Entry added and arg updated
  2528. *
  2529. * RETURNS Error status
  2530. *
  2531. ******************************************************************************/
  2532. DWORD AddIPv4InterfaceInfo(IP_ADAPTER_INFO *IF, PVOID arg1, PVOID arg2, DWORD Flags, DWORD Family, PMIB_IPADDRTABLE pAddrTable)
  2533. {
  2534. DWORD dwErr = NO_ERROR, i;
  2535. PIP_ADAPTER_ADDRESSES **ppNext = (PIP_ADAPTER_ADDRESSES**)arg1;
  2536. PIP_ADAPTER_ADDRESSES pFirst = *(PIP_ADAPTER_ADDRESSES*)arg2;
  2537. PIP_ADAPTER_ADDRESSES pCurr;
  2538. PIP_ADAPTER_UNICAST_ADDRESS *pNextUAddr;
  2539. PIP_ADAPTER_MULTICAST_ADDRESS *pNextMAddr;
  2540. PIP_ADAPTER_PREFIX *pNextPrefix;
  2541. WCHAR wszDescription[MAX_ADAPTER_DESCRIPTION_LENGTH + 4];
  2542. WCHAR wszFriendlyName[MAX_FRIENDLY_NAME_LENGTH + 1];
  2543. MIB_IFROW IfEntry;
  2544. GUID Guid;
  2545. DWORD ZoneIndices[ADE_NUM_SCOPES];
  2546. MultiByteToWideChar(CP_ACP, 0, IF->Description, -1,
  2547. wszDescription, MAX_ADAPTER_DESCRIPTION_LENGTH);
  2548. //
  2549. // Get information which isn't in IP_ADAPTER_INFO.
  2550. //
  2551. dwErr = GetIfEntryFromStack(&IfEntry, IF->Index, FALSE);
  2552. if (dwErr != NO_ERROR) {
  2553. return dwErr;
  2554. }
  2555. if (ConvertStringToGuidA(IF->AdapterName, &Guid) != NO_ERROR) {
  2556. ZeroMemory(&Guid, sizeof(Guid));
  2557. }
  2558. //
  2559. // Fill in some dummy zone indices.
  2560. //
  2561. ZoneIndices[0] = ZoneIndices[1] = ZoneIndices[2] = ZoneIndices[3] = IF->Index;
  2562. for (i=ADE_ADMIN_LOCAL; i<ADE_NUM_SCOPES; i++) {
  2563. ZoneIndices[i] = 1;
  2564. }
  2565. if (Flags & GAA_FLAG_SKIP_FRIENDLY_NAME) {
  2566. wszFriendlyName[0] = L'\0';
  2567. } else {
  2568. MapAdapterNameToFriendlyName(&Guid, IF->AdapterName, wszFriendlyName,
  2569. MAX_FRIENDLY_NAME_LENGTH);
  2570. }
  2571. dwErr = FindOrCreateIpAdapter(pFirst, &pCurr, ppNext, IF->AdapterName,
  2572. IF->AdapterName, IF->Index, 0, Flags,
  2573. IF->Type, IfEntry.dwMtu, IF->Address,
  2574. IF->AddressLength, wszDescription, wszFriendlyName,
  2575. ZoneIndices, Family);
  2576. if (dwErr != NO_ERROR) {
  2577. return dwErr;
  2578. }
  2579. pCurr->OperStatus = (IfEntry.dwOperStatus < NUM_IPV4_OPER_STATUSES)
  2580. ? IPv4ToMibOperStatus[IfEntry.dwOperStatus]
  2581. : IfOperStatusUnknown;
  2582. if (IF->DhcpEnabled) {
  2583. pCurr->Flags |= IP_ADAPTER_DHCP_ENABLED;
  2584. }
  2585. // Add addresses
  2586. pNextUAddr = &pCurr->FirstUnicastAddress;
  2587. pNextMAddr = &pCurr->FirstMulticastAddress;
  2588. dwErr = ForEachIPv4Address(IF, AddIPv4UnicastAddressInfo, &pNextUAddr,
  2589. pNextMAddr, &pNextMAddr, &pCurr->Flags,
  2590. Flags, pAddrTable);
  2591. if (dwErr != NO_ERROR) {
  2592. return dwErr;
  2593. }
  2594. // Add prefixes
  2595. if (Flags & GAA_FLAG_INCLUDE_PREFIX) {
  2596. pNextPrefix = &pCurr->FirstPrefix;
  2597. dwErr = ForEachIPv4Prefix(IF, AddIPv4Prefix, &pCurr->FirstPrefix,
  2598. &pNextPrefix);
  2599. }
  2600. return dwErr;
  2601. }
  2602. IP_ADAPTER_INFO IPv4LoopbackInterfaceInfo = {
  2603. NULL, // Next
  2604. 1, // ComboIndex
  2605. "MS TCP Loopback interface", // AdapterName
  2606. "MS TCP Loopback interface", // Description
  2607. 0, // Address Length
  2608. {0}, // Address
  2609. 1, // Index
  2610. MIB_IF_TYPE_LOOPBACK, // Type
  2611. FALSE, // DhcpEnabled
  2612. NULL, // CurrentIpAddress,
  2613. {NULL}, // IpAddressList,
  2614. {NULL}, // GatewayList,
  2615. {NULL}, // DhcpServer,
  2616. FALSE, // HaveWins
  2617. {NULL}, // PrimaryWinsServer,
  2618. {NULL}, // SecondaryWinsServer,
  2619. 0, // LeaseObtained
  2620. 0 // LeaseExpires
  2621. };
  2622. /*******************************************************************************
  2623. * ForEachIPv4Interface
  2624. *
  2625. * This routine walks a set of IPv4 interfaces and invokes a given function
  2626. * on each one.
  2627. *
  2628. * ENTRY func - Function to invoke on each interface
  2629. * arg1 - Argument to pass to func
  2630. * arg2 - Argument to pass to func
  2631. * pAdapterInfo - List of IPv4 interfaces
  2632. * Flags - Flags to pass to func
  2633. * Family - Address family constraint (for DNS server addresses)
  2634. *
  2635. * EXIT Nothing
  2636. *
  2637. * RETURNS Error status
  2638. *
  2639. ******************************************************************************/
  2640. DWORD ForEachIPv4Interface(DWORD (*func)(IP_ADAPTER_INFO *, PVOID, PVOID, DWORD, DWORD, PMIB_IPADDRTABLE), PVOID arg1, PVOID arg2, IP_ADAPTER_INFO *pAdapterInfo, DWORD Flags, DWORD Family, PMIB_IPADDRTABLE pIpAddrTable)
  2641. {
  2642. PIP_ADAPTER_INFO IF;
  2643. DWORD dwErr;
  2644. //
  2645. // The IPv4 loopback interface is missing from the pAdapterInfo list,
  2646. // so we special case it here.
  2647. //
  2648. dwErr = (*func)(&IPv4LoopbackInterfaceInfo, arg1, arg2, Flags, Family,
  2649. pIpAddrTable);
  2650. if (dwErr != NO_ERROR) {
  2651. return dwErr;
  2652. }
  2653. for (IF=pAdapterInfo; IF; IF=IF->Next) {
  2654. dwErr = (*func)(IF, arg1, arg2, Flags, Family, pIpAddrTable);
  2655. if (dwErr != NO_ERROR) {
  2656. return dwErr;
  2657. }
  2658. }
  2659. return NO_ERROR;
  2660. }
  2661. DWORD GetAdapterAddresses(ULONG Family, DWORD Flags, PIP_ADAPTER_ADDRESSES *pAddresses)
  2662. {
  2663. IP_ADAPTER_INFO *pAdapterInfo = NULL;
  2664. PIP_ADAPTER_ADDRESSES adapterList, *pCurr;
  2665. DWORD dwErr = NO_ERROR;
  2666. PMIB_IPADDRTABLE pIpAddrTable = NULL;
  2667. TRACE_PRINT(("Entered GetAdapterAddresses\n"));
  2668. pAdapterInfo = GetAdapterInfo();
  2669. *pAddresses = adapterList = NULL;
  2670. pCurr = &adapterList;
  2671. //
  2672. // If we want to return IPv6 DNS servers, find out now whether the
  2673. // IPv6 stack is installed.
  2674. //
  2675. if ((Family != AF_INET) && !(Flags & GAA_FLAG_SKIP_DNS_SERVER)) {
  2676. IPV6_GLOBAL_PARAMETERS Params;
  2677. u_int BytesReturned = sizeof(Params);
  2678. DWORD InputBufferLength = 0;
  2679. dwErr = WsControl(IPPROTO_IPV6,
  2680. IOCTL_IPV6_QUERY_GLOBAL_PARAMETERS,
  2681. NULL, &InputBufferLength,
  2682. &Params, &BytesReturned);
  2683. bIp6DriverInstalled = (dwErr == NO_ERROR);
  2684. dwErr = NO_ERROR;
  2685. }
  2686. if ((Family == AF_UNSPEC) || (Family == AF_INET)) {
  2687. DWORD dwSize = 0;
  2688. //
  2689. // GetAdapterInfo alone isn't sufficient since it doesn't get
  2690. // per-address flags whereas GetIpAddrTable does.
  2691. // GetIpAddrTable doesn't get per-interface info however,
  2692. // so this is why we have to do both. We use pAdapterInfo
  2693. // for per-interface info and pIpAddrTable for
  2694. // per-address info.
  2695. //
  2696. dwErr = GetIpAddrTable(NULL, &dwSize, TRUE);
  2697. if (dwErr == ERROR_INSUFFICIENT_BUFFER) {
  2698. pIpAddrTable = MALLOC(dwSize);
  2699. if (!pIpAddrTable) {
  2700. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  2701. goto Cleanup;
  2702. }
  2703. dwErr = GetIpAddrTable(pIpAddrTable, &dwSize, TRUE);
  2704. }
  2705. if (dwErr != NO_ERROR) {
  2706. goto Cleanup;
  2707. }
  2708. dwErr = ForEachIPv4Interface(AddIPv4InterfaceInfo, &pCurr, &adapterList,
  2709. pAdapterInfo, Flags, Family, pIpAddrTable);
  2710. if (dwErr != NO_ERROR) {
  2711. goto Cleanup;
  2712. }
  2713. }
  2714. if ((Family == AF_UNSPEC) || (Family == AF_INET6)) {
  2715. dwErr = ForEachIPv6Interface(AddIPv6InterfaceInfo, &pCurr, &adapterList,
  2716. pAdapterInfo, Flags, Family);
  2717. if (dwErr != NO_ERROR) {
  2718. goto Cleanup;
  2719. }
  2720. }
  2721. *pAddresses = adapterList;
  2722. Cleanup:
  2723. if (pIpAddrTable) {
  2724. FREE(pIpAddrTable);
  2725. }
  2726. if (pAdapterInfo) {
  2727. KillAdapterInfo(pAdapterInfo);
  2728. }
  2729. TRACE_PRINT(("Exit GetAdapterAddresses %p\n", adapterList));
  2730. return dwErr;
  2731. }
  2732. /*******************************************************************************
  2733. *
  2734. * InternalGetPerAdapterInfo
  2735. *
  2736. * Gets per-adapter special information.
  2737. *
  2738. * ENTRY IfIndex
  2739. *
  2740. * EXIT nothing
  2741. *
  2742. * RETURNS pointer to the IP_PER_ADAPTER_INFO structure
  2743. *
  2744. * ASSUMES
  2745. *
  2746. ******************************************************************************/
  2747. PIP_PER_ADAPTER_INFO InternalGetPerAdapterInfo(ULONG IfIndex)
  2748. {
  2749. PIP_ADAPTER_INFO adapterList;
  2750. PIP_ADAPTER_INFO adapter;
  2751. PIP_PER_ADAPTER_INFO perAdapterInfo = NULL;
  2752. HKEY key;
  2753. BOOL ok;
  2754. TRACE_PRINT(("Entered GetPerAdapterList\n"));
  2755. if ((adapterList = GetAdapterInfo()) != NULL) {
  2756. //
  2757. // scan the adapter list and find one that matches IfIndex
  2758. //
  2759. for (adapter = adapterList; adapter; adapter = adapter->Next) {
  2760. TRACE_PRINT(("GetPerAdapterInfo: '%s'\n", adapter->AdapterName));
  2761. if (adapter->Index == IfIndex &&
  2762. adapter->AdapterName[0] &&
  2763. OpenAdapterKey(KEY_TCP, adapter->AdapterName, KEY_READ, &key)) {
  2764. //
  2765. // found the right adapter so let's fill up the perAdapterInfo
  2766. //
  2767. perAdapterInfo = NEW(IP_PER_ADAPTER_INFO);
  2768. if (perAdapterInfo == NULL) {
  2769. DEBUG_PRINT(("GetPerAdapterInfo: no memory for perAdapterInfo\n"));
  2770. KillAdapterInfo(adapterList);
  2771. RegCloseKey(key);
  2772. return NULL;
  2773. }
  2774. ZeroMemory(perAdapterInfo, sizeof(IP_PER_ADAPTER_INFO));
  2775. if (!MyReadRegistryDword(key,
  2776. TEXT("IPAutoconfigurationEnabled"),
  2777. &perAdapterInfo->AutoconfigEnabled)) {
  2778. //
  2779. // autoconfig is enabled if no regval exists for this
  2780. // adapter
  2781. //
  2782. perAdapterInfo->AutoconfigEnabled = TRUE;
  2783. TRACE_PRINT(("IPAutoconfigurationEnabled not read\n"));
  2784. }
  2785. TRACE_PRINT(("IPAutoconfigurationEnableda = %d\n",
  2786. perAdapterInfo->AutoconfigEnabled));
  2787. if (perAdapterInfo->AutoconfigEnabled) {
  2788. MyReadRegistryDword(key,
  2789. TEXT("AddressType"),
  2790. &perAdapterInfo->AutoconfigActive);
  2791. TRACE_PRINT(("AddressType !%s\n",
  2792. perAdapterInfo->AutoconfigActive));
  2793. }
  2794. //
  2795. // DNS Server list: first NameServer and then DhcpNameServer
  2796. //
  2797. ok = ReadRegistryIpAddrString(key,
  2798. TEXT("NameServer"),
  2799. &perAdapterInfo->DnsServerList);
  2800. if (ok) {
  2801. TRACE_PRINT(("GetPerAdapterInfo: DhcpNameServer %s\n",
  2802. perAdapterInfo->DnsServerList));
  2803. }
  2804. if (!ok) {
  2805. ok = ReadRegistryIpAddrString(key,
  2806. TEXT("DhcpNameServer"),
  2807. &perAdapterInfo->DnsServerList);
  2808. if (ok) {
  2809. TRACE_PRINT(("GetPerAdapterInfo: DhcpNameServer %s\n",
  2810. perAdapterInfo->DnsServerList));
  2811. }
  2812. }
  2813. //
  2814. // we are done so let's exit the loop
  2815. //
  2816. RegCloseKey(key);
  2817. break;
  2818. } else {
  2819. DEBUG_PRINT(("Cannot OpenAdapterKey KEY_TCP '%s', gle=%d\n",
  2820. adapter->AdapterName,
  2821. GetLastError()));
  2822. }
  2823. }
  2824. KillAdapterInfo(adapterList);
  2825. } else {
  2826. DEBUG_PRINT(("GetPerAdapterInfo: GetAdapterInfo returns NULL\n"));
  2827. }
  2828. TRACE_PRINT(("Exit GetPerAdapterInfo %p\n", perAdapterInfo));
  2829. return perAdapterInfo;
  2830. }
  2831. /*******************************************************************************
  2832. *
  2833. * OpenAdapterKey
  2834. *
  2835. * Opens one of the 3 per-adapter registry keys:
  2836. * Tcpip\\Parameters"\<adapter>
  2837. * or NetBT\Adapters\<Adapter>
  2838. * or Tcpip6\Paramters\<adapter>
  2839. *
  2840. * ENTRY KeyType - KEY_TCP or KEY_NBT or KEY_TCP6
  2841. * Name - pointer to adapter name to use
  2842. * Key - pointer to returned key
  2843. *
  2844. * EXIT Key updated
  2845. *
  2846. * RETURNS TRUE if success
  2847. *
  2848. * ASSUMES
  2849. * HISTORY: MohsinA, 16-May-97. Fixing for PNP.
  2850. *
  2851. ******************************************************************************/
  2852. static
  2853. BOOL OpenAdapterKey(DWORD KeyType, const LPSTR Name, REGSAM Access, PHKEY Key)
  2854. {
  2855. LONG err;
  2856. CHAR keyName[MAX_ADAPTER_NAME_LENGTH + sizeof(TCPIP_PARAMS_INTER_KEY)];
  2857. switch (KeyType) {
  2858. case KEY_TCP:
  2859. //
  2860. // open the handle to this adapter's TCPIP parameter key
  2861. //
  2862. strcpy(keyName, TCPIP_PARAMS_INTER_KEY );
  2863. strcat(keyName, Name);
  2864. break;
  2865. case KEY_TCP6:
  2866. //
  2867. // open the handle to this adapter's TCPIP6 parameter key
  2868. //
  2869. strcpy(keyName, TCPIP6_PARAMS_INTER_KEY );
  2870. strcat(keyName, Name);
  2871. break;
  2872. case KEY_NBT:
  2873. //
  2874. // open the handle to the NetBT\Adapters\<Adapter> handle
  2875. //
  2876. strcpy(keyName, NETBT_ADAPTER_KEY );
  2877. strcat(keyName, Name);
  2878. break;
  2879. default:
  2880. return FALSE;
  2881. }
  2882. TRACE_PRINT(("OpenAdapterKey: %s\n", keyName ));
  2883. err = RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName, 0, Access, Key );
  2884. if( err != ERROR_SUCCESS ){
  2885. DEBUG_PRINT(("OpenAdapterKey: RegOpenKey %s, err=%d\n",
  2886. keyName, GetLastError() ));
  2887. }else{
  2888. TRACE_PRINT(("Exit OpenAdapterKey: %s ok\n", keyName ));
  2889. }
  2890. return (err == ERROR_SUCCESS);
  2891. }
  2892. BOOL WriteRegistryDword(HKEY hKey, LPSTR szParameter, DWORD *pdwValue )
  2893. {
  2894. DWORD dwResult;
  2895. TRACE_PRINT(("WriteRegistryDword: %s %d\n", szParameter, *pdwValue ));
  2896. dwResult = RegSetValueEx(
  2897. hKey,
  2898. szParameter,
  2899. 0,
  2900. REG_DWORD,
  2901. (CONST BYTE *) pdwValue,
  2902. sizeof( *pdwValue )
  2903. );
  2904. return ( ERROR_SUCCESS == dwResult );
  2905. }
  2906. BOOL WriteRegistryMultiString(HKEY hKey,
  2907. LPSTR szParameter,
  2908. LPSTR szValue
  2909. )
  2910. {
  2911. DWORD dwResult;
  2912. LPSTR psz;
  2913. for (psz = szValue; *psz; psz += lstrlen(szValue) + 1) { }
  2914. dwResult = RegSetValueEx(
  2915. hKey,
  2916. szParameter,
  2917. 0,
  2918. REG_MULTI_SZ,
  2919. (CONST BYTE *) szValue,
  2920. (DWORD)(psz - szValue) + 1
  2921. );
  2922. return ( ERROR_SUCCESS == dwResult );
  2923. }
  2924. /*******************************************************************************
  2925. *
  2926. * MyReadRegistryDword
  2927. *
  2928. * Reads a registry value that is stored as a DWORD
  2929. *
  2930. * ENTRY Key - open registry key where value resides
  2931. * ParameterName - name of value to read from registry
  2932. * Value - pointer to returned value
  2933. *
  2934. * EXIT *Value = value read
  2935. *
  2936. * RETURNS TRUE if success
  2937. *
  2938. * ASSUMES
  2939. *
  2940. ******************************************************************************/
  2941. BOOL MyReadRegistryDword(HKEY Key, LPSTR ParameterName, LPDWORD Value)
  2942. {
  2943. LONG err;
  2944. DWORD valueLength;
  2945. DWORD valueType;
  2946. valueLength = sizeof(*Value);
  2947. err = RegQueryValueEx(Key,
  2948. ParameterName,
  2949. NULL, // reserved
  2950. &valueType,
  2951. (LPBYTE)Value,
  2952. &valueLength
  2953. );
  2954. if ((err == ERROR_SUCCESS) && (valueType == REG_DWORD) && (valueLength == sizeof(DWORD))) {
  2955. DEBUG_PRINT(("MyReadRegistryDword(%s): val = %d, type = %d, len = %d\n",
  2956. ParameterName,
  2957. *Value,
  2958. valueType,
  2959. valueLength
  2960. ));
  2961. } else {
  2962. DEBUG_PRINT(("MyReadRegistryDword(%p,%s): err = %d\n",
  2963. Key, ParameterName, err));
  2964. err = !ERROR_SUCCESS;
  2965. }
  2966. return (err == ERROR_SUCCESS);
  2967. }
  2968. // ========================================================================
  2969. // Was DWORD IPInterfaceContext, now CHAR NTEContextList[][].
  2970. // Reads in a REG_MULTI_SZ and converts it into a list of numbers.
  2971. // MohsinA, 21-May-97.
  2972. // ========================================================================
  2973. // max length of REG_MULTI_SZ.
  2974. #define MAX_VALUE 5002
  2975. BOOL
  2976. ReadRegistryList(HKEY Key, LPSTR ParameterName,
  2977. DWORD NumList[], int *MaxList
  2978. )
  2979. {
  2980. LONG err;
  2981. DWORD valueType;
  2982. BYTE Value[MAX_VALUE];
  2983. DWORD valueLength = MAX_VALUE;
  2984. int i = 0, k = 0;
  2985. err = RegQueryValueEx(Key,
  2986. ParameterName,
  2987. NULL,
  2988. &valueType,
  2989. &Value[0],
  2990. &valueLength
  2991. );
  2992. if( ( err == ERROR_SUCCESS) &&
  2993. ( valueType == REG_MULTI_SZ ) &&
  2994. ((valueLength+2) < MAX_VALUE)
  2995. ){
  2996. TRACE_PRINT(("ReadRegistryList %s ok\n", ParameterName ));
  2997. Value[MAX_VALUE-1] = '\0';
  2998. Value[MAX_VALUE-2] = '\0';
  2999. while( (i < MAX_VALUE) && Value[i] && (k < (*MaxList)) ){
  3000. NumList[k] = strtoul( &Value[i], NULL, 0 );
  3001. TRACE_PRINT((" NumList[%d] = '%s' => %d\n",
  3002. k, &Value[i], NumList[k] ));
  3003. k++;
  3004. i += strlen( &Value[i] ) + 1;
  3005. }
  3006. assert( (i < MAX_VALUE) && !Value[i] && (k < MaxList) );
  3007. *MaxList = k;
  3008. }
  3009. else
  3010. {
  3011. *MaxList = 0;
  3012. DEBUG_PRINT(("ReadRegistryList %s failed\n", ParameterName ));
  3013. err = !ERROR_SUCCESS;
  3014. }
  3015. return (err == ERROR_SUCCESS);
  3016. }
  3017. BOOL
  3018. IsIncluded( DWORD Context, DWORD contextlist[], int len_contextlist )
  3019. {
  3020. int i;
  3021. for( i = 0; i < len_contextlist; i++ )
  3022. {
  3023. if( Context == contextlist[i] ){
  3024. return TRUE;
  3025. }
  3026. }
  3027. return FALSE;
  3028. }
  3029. /*******************************************************************************
  3030. *
  3031. * ReadRegistryString
  3032. *
  3033. * Reads a registry value that is stored as a string
  3034. *
  3035. * ENTRY Key - open registry key
  3036. * ParameterName - name of value to read from registry
  3037. * String - pointer to returned string
  3038. * Length - IN: length of String buffer. OUT: length of returned string
  3039. *
  3040. * EXIT String contains string read
  3041. *
  3042. * RETURNS TRUE if success
  3043. *
  3044. * ASSUMES
  3045. *
  3046. ******************************************************************************/
  3047. BOOL ReadRegistryString(HKEY Key, LPSTR ParameterName, LPSTR String, LPDWORD Length)
  3048. {
  3049. LONG err;
  3050. DWORD valueType;
  3051. *String = '\0';
  3052. err = RegQueryValueEx(Key,
  3053. ParameterName,
  3054. NULL, // reserved
  3055. &valueType,
  3056. (LPBYTE)String,
  3057. Length
  3058. );
  3059. if (err == ERROR_SUCCESS) {
  3060. ASSERT(valueType == REG_SZ || valueType == REG_MULTI_SZ);
  3061. DEBUG_PRINT(("ReadRegistryString(%s): val = \"%s\", type = %d, len = %d\n",
  3062. ParameterName,
  3063. String,
  3064. valueType,
  3065. *Length
  3066. ));
  3067. } else {
  3068. DEBUG_PRINT(("ReadRegistryString(%s): err = %d\n", ParameterName, err));
  3069. }
  3070. return ((err == ERROR_SUCCESS) && (*Length > sizeof('\0')));
  3071. }
  3072. /*******************************************************************************
  3073. *
  3074. * ReadRegistryOemString
  3075. *
  3076. * Reads a registry value as a wide character string
  3077. *
  3078. * ENTRY Key - open registry key
  3079. * ParameterName - name of value to read from registry
  3080. * String - pointer to returned string
  3081. * Length - IN: length of String buffer. OUT: length of returned string
  3082. *
  3083. * EXIT String contains string read
  3084. *
  3085. * RETURNS TRUE if success
  3086. *
  3087. * ASSUMES
  3088. *
  3089. ******************************************************************************/
  3090. BOOL ReadRegistryOemString(HKEY Key, LPWSTR ParameterName, LPSTR String, LPDWORD Length)
  3091. {
  3092. LONG err;
  3093. DWORD valueType;
  3094. DWORD valueLength;
  3095. //
  3096. // first, get the length of the string
  3097. //
  3098. *String = '\0';
  3099. err = RegQueryValueExW(Key,
  3100. ParameterName,
  3101. NULL, // reserved
  3102. &valueType,
  3103. NULL,
  3104. &valueLength
  3105. );
  3106. if ((err == ERROR_SUCCESS) && (valueType == REG_SZ)) {
  3107. if ((valueLength <= *Length) && (valueLength > sizeof(L'\0'))) {
  3108. UNICODE_STRING unicodeString;
  3109. OEM_STRING oemString;
  3110. LPWSTR str = (LPWSTR)GrabMemory(valueLength);
  3111. if (!str) {
  3112. return FALSE;
  3113. }
  3114. //
  3115. // read the UNICODE string into allocated memory
  3116. //
  3117. err = RegQueryValueExW(Key,
  3118. ParameterName,
  3119. NULL,
  3120. &valueType,
  3121. (LPBYTE)str,
  3122. &valueLength
  3123. );
  3124. if (err == ERROR_SUCCESS) {
  3125. NTSTATUS Status;
  3126. //
  3127. // convert the UNICODE string to OEM character set
  3128. //
  3129. RtlInitUnicodeString(&unicodeString, str);
  3130. Status = RtlUnicodeStringToOemString(&oemString, &unicodeString, TRUE);
  3131. if (NT_SUCCESS(Status)) {
  3132. strcpy(String, oemString.Buffer);
  3133. RtlFreeOemString(&oemString);
  3134. } else {
  3135. err = !ERROR_SUCCESS;
  3136. }
  3137. DEBUG_PRINT(("ReadRegistryOemString(%ws): val = \"%s\", len = %d\n",
  3138. ParameterName,
  3139. String,
  3140. valueLength
  3141. ));
  3142. } else {
  3143. DEBUG_PRINT(("ReadRegistryOemString(%ws): err = %d, type = %d, len = %d\n",
  3144. ParameterName,
  3145. err,
  3146. valueType,
  3147. valueLength
  3148. ));
  3149. }
  3150. ReleaseMemory(str);
  3151. } else {
  3152. DEBUG_PRINT(("ReadRegistryOemString(%ws): err = %d, type = %d, len = %d\n",
  3153. ParameterName,
  3154. err,
  3155. valueType,
  3156. valueLength
  3157. ));
  3158. err = !ERROR_SUCCESS;
  3159. }
  3160. } else {
  3161. DEBUG_PRINT(("ReadRegistryOemString(%ws): err = %d, type = %d, len = %d\n",
  3162. ParameterName,
  3163. err,
  3164. valueType,
  3165. valueLength
  3166. ));
  3167. err = !ERROR_SUCCESS;
  3168. }
  3169. return (err == ERROR_SUCCESS);
  3170. }
  3171. /*******************************************************************************
  3172. *
  3173. * ReadRegistryIpAddrString
  3174. *
  3175. * Reads zero or more IP addresses from a space-delimited string in a registry
  3176. * parameter and converts them to a list of IP_ADDR_STRINGs
  3177. *
  3178. * ENTRY Key - registry key
  3179. * ParameterName - name of value entry under Key to read from
  3180. * IpAddr - pointer to IP_ADDR_STRING to update
  3181. *
  3182. * EXIT IpAddr updated if success
  3183. *
  3184. * RETURNS TRUE if success
  3185. *
  3186. * ASSUMES
  3187. *
  3188. ******************************************************************************/
  3189. BOOL ReadRegistryIpAddrString(HKEY Key, LPSTR ParameterName, PIP_ADDR_STRING IpAddr)
  3190. {
  3191. LONG err;
  3192. DWORD valueLength;
  3193. DWORD valueType;
  3194. LPBYTE valueBuffer;
  3195. err = RegQueryValueEx(Key,
  3196. ParameterName,
  3197. NULL, // reserved
  3198. &valueType,
  3199. NULL,
  3200. &valueLength
  3201. );
  3202. if ((err == ERROR_SUCCESS)) {
  3203. if((valueLength > 1) && (valueType == REG_SZ)
  3204. || (valueLength > 2) && (valueType == REG_MULTI_SZ) ) {
  3205. valueBuffer = GrabMemory(valueLength);
  3206. if (!valueBuffer) {
  3207. return FALSE;
  3208. }
  3209. err = RegQueryValueEx(Key,
  3210. ParameterName,
  3211. NULL, // reserved
  3212. &valueType,
  3213. valueBuffer,
  3214. &valueLength
  3215. );
  3216. if ((err == ERROR_SUCCESS) && (valueLength > 1)) {
  3217. UINT stringCount;
  3218. LPSTR stringPointer = valueBuffer;
  3219. LPSTR *stringAddress;
  3220. UINT i;
  3221. DEBUG_PRINT(("ReadRegistryIpAddrString(%s): \"%s\", len = %d\n",
  3222. ParameterName,
  3223. valueBuffer,
  3224. valueLength
  3225. ));
  3226. stringAddress = GrabMemory(valueLength / 2 * sizeof(LPSTR));
  3227. if (stringAddress) {
  3228. if( REG_SZ == valueType ) {
  3229. stringPointer += strspn(stringPointer, STRING_ARRAY_DELIMITERS);
  3230. stringAddress[0] = stringPointer;
  3231. stringCount = 1;
  3232. while (stringPointer = strpbrk(stringPointer, STRING_ARRAY_DELIMITERS)) {
  3233. *stringPointer++ = '\0';
  3234. stringPointer += strspn(stringPointer, STRING_ARRAY_DELIMITERS);
  3235. stringAddress[stringCount] = stringPointer;
  3236. if (*stringPointer) {
  3237. ++stringCount;
  3238. }
  3239. }
  3240. for (i = 0; i < stringCount; ++i) {
  3241. AddIpAddressString(IpAddr, stringAddress[i], "");
  3242. }
  3243. } else if( REG_MULTI_SZ == valueType ) {
  3244. stringCount = 0;
  3245. while(strlen(stringPointer)) {
  3246. AddIpAddressString(IpAddr, stringPointer, "");
  3247. stringPointer += 1+strlen(stringPointer);
  3248. stringCount ++;
  3249. }
  3250. if( 0 == stringCount ) err = ERROR_PATH_NOT_FOUND;
  3251. } else {
  3252. err = ERROR_PATH_NOT_FOUND;
  3253. }
  3254. ReleaseMemory(stringAddress);
  3255. } else {
  3256. err = ERROR_NOT_ENOUGH_MEMORY;
  3257. }
  3258. } else {
  3259. DEBUG_PRINT(("ReadRegistryIpAddrString(%s): err = %d, len = %d\n",
  3260. ParameterName,
  3261. err,
  3262. valueLength
  3263. ));
  3264. err = ERROR_PATH_NOT_FOUND;
  3265. }
  3266. ReleaseMemory(valueBuffer);
  3267. } else {
  3268. DEBUG_PRINT(("ReadRegistryIpAddrString(%s): err = %d, type = %d, len = %d\n",
  3269. ParameterName,
  3270. err,
  3271. valueType,
  3272. valueLength
  3273. ));
  3274. err = ERROR_PATH_NOT_FOUND;
  3275. }
  3276. }
  3277. return (err == ERROR_SUCCESS);
  3278. }
  3279. /*******************************************************************************
  3280. *
  3281. * GetBoundAdapterList
  3282. *
  3283. * Gets a list of names of all adapters bound to a protocol (TCP/IP). Returns
  3284. * a pointer to an array of pointers to strings - basically an argv list. The
  3285. * memory for the strings is concatenated to the array and the array is NULL
  3286. * terminated. If Elnkii1 and IbmTok2 are bound to TCP/IP then this function
  3287. * will return:
  3288. *
  3289. * ---> addr of string1 \
  3290. * addr of string2 \
  3291. * NULL > allocated as one block
  3292. * &string1: "Elnkii1" /
  3293. * &string2: "IbmTok2" /
  3294. *
  3295. * ENTRY BindingsSectionKey
  3296. * - Open registry handle to a linkage key (e.g. Tcpip\Linkage)
  3297. *
  3298. * EXIT
  3299. *
  3300. * RETURNS pointer to argv[] style array, or NULL
  3301. *
  3302. * ASSUMES
  3303. *
  3304. ******************************************************************************/
  3305. LPSTR* GetBoundAdapterList(HKEY BindingsSectionKey)
  3306. {
  3307. LONG err;
  3308. DWORD valueType;
  3309. PBYTE valueBuffer;
  3310. DWORD valueLength;
  3311. LPSTR* resultBuffer;
  3312. LPSTR* nextResult;
  3313. int len;
  3314. DWORD resultLength;
  3315. LPSTR nextValue;
  3316. LPSTR variableData;
  3317. DWORD numberOfBindings;
  3318. //
  3319. // get required size of value buffer
  3320. //
  3321. valueLength = 0;
  3322. err = RegQueryValueEx(BindingsSectionKey,
  3323. TEXT("Bind"),
  3324. NULL, // reserved
  3325. &valueType,
  3326. NULL,
  3327. &valueLength
  3328. );
  3329. if (err != ERROR_SUCCESS) {
  3330. return NULL;
  3331. }
  3332. if (valueType != REG_MULTI_SZ) {
  3333. return NULL;
  3334. }
  3335. if (!valueLength) {
  3336. return NULL;
  3337. }
  3338. valueBuffer = (PBYTE)GrabMemory(valueLength);
  3339. if (!valueBuffer) {
  3340. return NULL;
  3341. }
  3342. err = RegQueryValueEx(BindingsSectionKey,
  3343. TEXT("Bind"),
  3344. NULL, // reserved
  3345. &valueType,
  3346. valueBuffer,
  3347. &valueLength
  3348. );
  3349. if (err != ERROR_SUCCESS) {
  3350. DEBUG_PRINT(("GetBoundAdapterList: RegQueryValueEx 'Bind' failed\n"));
  3351. ReleaseMemory(valueBuffer);
  3352. return NULL;
  3353. }
  3354. resultLength = sizeof(LPSTR); // the NULL at the end of the list
  3355. numberOfBindings = 0;
  3356. nextValue = (LPSTR)valueBuffer;
  3357. while (len = strlen(nextValue)) {
  3358. resultLength += sizeof(LPSTR) + len + 1;
  3359. if (!_strnicmp(nextValue, DEVICE_PREFIX, sizeof(DEVICE_PREFIX) - 1)) {
  3360. resultLength -= sizeof(DEVICE_PREFIX) - 1;
  3361. }
  3362. nextValue += len + 1;
  3363. ++numberOfBindings;
  3364. }
  3365. resultBuffer = (LPSTR*)GrabMemory(resultLength);
  3366. if (!resultBuffer) {
  3367. return NULL;
  3368. }
  3369. nextValue = (LPSTR)valueBuffer;
  3370. nextResult = resultBuffer;
  3371. variableData = (LPSTR)(((LPSTR*)resultBuffer) + numberOfBindings + 1);
  3372. while (numberOfBindings--) {
  3373. LPSTR adapterName;
  3374. adapterName = nextValue;
  3375. if (!_strnicmp(adapterName, DEVICE_PREFIX, sizeof(DEVICE_PREFIX) - 1)) {
  3376. adapterName += sizeof(DEVICE_PREFIX) - 1;
  3377. }
  3378. *nextResult++ = variableData;
  3379. strcpy(variableData, adapterName);
  3380. TRACE_PRINT(("GetBoundAdapterList: adapterName=%s\n", adapterName ));
  3381. while (*variableData) {
  3382. ++variableData;
  3383. }
  3384. ++variableData;
  3385. while (*nextValue) {
  3386. ++nextValue;
  3387. }
  3388. ++nextValue;
  3389. }
  3390. *nextResult = NULL;
  3391. ReleaseMemory(valueBuffer);
  3392. return resultBuffer;
  3393. }
  3394. /*******************************************************************************
  3395. *
  3396. * MapNodeType
  3397. *
  3398. * Converts node type to descriptive string
  3399. *
  3400. * ENTRY
  3401. *
  3402. * EXIT
  3403. *
  3404. * RETURNS pointer to string
  3405. *
  3406. * ASSUMES
  3407. *
  3408. ******************************************************************************/
  3409. LPSTR MapNodeType(UINT Parm)
  3410. {
  3411. DWORD dwParm = LAST_NODE_TYPE + 1;
  3412. //
  3413. // 1, 2, 4, 8 => log2(n) + 1 [1, 2, 3, 4]
  3414. //
  3415. switch (Parm) {
  3416. case 0:
  3417. //
  3418. // according to JStew value of 0 will be treated as BNode (default)
  3419. //
  3420. case BNODE:
  3421. dwParm = 1;
  3422. break;
  3423. case PNODE:
  3424. dwParm = 2;
  3425. break;
  3426. case MNODE:
  3427. dwParm = 3;
  3428. break;
  3429. case HNODE:
  3430. dwParm = 4;
  3431. break;
  3432. }
  3433. if ((dwParm >= FIRST_NODE_TYPE) && (dwParm <= LAST_NODE_TYPE)) {
  3434. return NodeTypes[dwParm].String;
  3435. }
  3436. //
  3437. // if no node type is defined then we default to Hybrid
  3438. //
  3439. return NodeTypes[LAST_NODE_TYPE].String;
  3440. }
  3441. /*******************************************************************************
  3442. *
  3443. * MapNodeTypeEx
  3444. *
  3445. * Converts node type to descriptive string
  3446. *
  3447. * ENTRY
  3448. *
  3449. * EXIT
  3450. *
  3451. * RETURNS pointer to string
  3452. *
  3453. * ASSUMES
  3454. *
  3455. ******************************************************************************/
  3456. LPSTR MapNodeTypeEx(UINT Parm)
  3457. {
  3458. DWORD dwParm = LAST_NODE_TYPE + 1;
  3459. LPSTR Buf;
  3460. Buf = GrabMemory(10);
  3461. if (!Buf) {
  3462. return NULL;
  3463. }
  3464. //
  3465. // 1, 2, 4, 8 => log2(n) + 1 [1, 2, 3, 4]
  3466. //
  3467. switch (Parm) {
  3468. case 0:
  3469. //
  3470. // according to JStew value of 0 will be treated as BNode (default)
  3471. //
  3472. case BNODE:
  3473. dwParm = 1;
  3474. break;
  3475. case PNODE:
  3476. dwParm = 2;
  3477. break;
  3478. case MNODE:
  3479. dwParm = 3;
  3480. break;
  3481. case HNODE:
  3482. dwParm = 4;
  3483. break;
  3484. }
  3485. if ((dwParm >= FIRST_NODE_TYPE) && (dwParm <= LAST_NODE_TYPE)) {
  3486. strcpy(Buf, NodeTypesEx[dwParm]);
  3487. return Buf;
  3488. }
  3489. //
  3490. // if no node type is defined then we default to Hybrid
  3491. //
  3492. strcpy(Buf, NodeTypesEx[LAST_NODE_TYPE]);
  3493. return Buf;
  3494. }
  3495. /*******************************************************************************
  3496. *
  3497. * MapAdapterType
  3498. *
  3499. * Returns a string describing the type of adapter, based on the type retrieved
  3500. * from TCP/IP
  3501. *
  3502. * ENTRY type - type of adapter
  3503. *
  3504. * EXIT nothing
  3505. *
  3506. * RETURNS pointer to mapped type or pointer to NUL string
  3507. *
  3508. * ASSUMES
  3509. *
  3510. ******************************************************************************/
  3511. LPSTR MapAdapterType(UINT type)
  3512. {
  3513. switch (type) {
  3514. case IF_TYPE_OTHER:
  3515. return ADAPTER_TYPE(MI_IF_OTHER); // ?
  3516. case IF_TYPE_ETHERNET_CSMACD:
  3517. return ADAPTER_TYPE(MI_IF_ETHERNET);
  3518. case IF_TYPE_ISO88025_TOKENRING:
  3519. return ADAPTER_TYPE(MI_IF_TOKEN_RING);
  3520. case IF_TYPE_FDDI:
  3521. return ADAPTER_TYPE(MI_IF_FDDI);
  3522. case IF_TYPE_PPP:
  3523. return ADAPTER_TYPE(MI_IF_PPP);
  3524. case IF_TYPE_SOFTWARE_LOOPBACK:
  3525. return ADAPTER_TYPE(MI_IF_LOOPBACK);
  3526. case IF_TYPE_SLIP:
  3527. return ADAPTER_TYPE(MI_IF_SLIP);
  3528. }
  3529. return "";
  3530. }
  3531. /*******************************************************************************
  3532. *
  3533. * MapAdapterTypeEx
  3534. *
  3535. * Returns a string describing the type of adapter, based on the type retrieved
  3536. * from TCP/IP
  3537. *
  3538. * ENTRY type - type of adapter
  3539. *
  3540. * EXIT nothing
  3541. *
  3542. * RETURNS pointer to mapped type or pointer to NUL string
  3543. *
  3544. * ASSUMES
  3545. *
  3546. ******************************************************************************/
  3547. LPSTR MapAdapterTypeEx(UINT type)
  3548. {
  3549. LPSTR Buf;
  3550. Buf = GrabMemory(12);
  3551. if (!Buf) {
  3552. return NULL;
  3553. }
  3554. switch (type) {
  3555. case IF_TYPE_OTHER:
  3556. strcpy(Buf, ADAPTER_TYPE_EX(MI_IF_OTHER)); // ?
  3557. return Buf;
  3558. case IF_TYPE_ETHERNET_CSMACD:
  3559. strcpy(Buf, ADAPTER_TYPE_EX(MI_IF_ETHERNET));
  3560. return Buf;
  3561. case IF_TYPE_ISO88025_TOKENRING:
  3562. strcpy(Buf, ADAPTER_TYPE_EX(MI_IF_TOKEN_RING));
  3563. return Buf;
  3564. case IF_TYPE_FDDI:
  3565. strcpy(Buf, ADAPTER_TYPE_EX(MI_IF_FDDI));
  3566. return Buf;
  3567. case IF_TYPE_PPP:
  3568. strcpy(Buf, ADAPTER_TYPE_EX(MI_IF_PPP));
  3569. return Buf;
  3570. case IF_TYPE_SOFTWARE_LOOPBACK:
  3571. strcpy(Buf, ADAPTER_TYPE_EX(MI_IF_LOOPBACK));
  3572. return Buf;
  3573. case IF_TYPE_SLIP:
  3574. strcpy(Buf, ADAPTER_TYPE_EX(MI_IF_SLIP));
  3575. return Buf;
  3576. }
  3577. strcpy(Buf, "");
  3578. return Buf;
  3579. }
  3580. /*******************************************************************************
  3581. *
  3582. * MapAdapterAddress
  3583. *
  3584. * Converts the binary adapter address retrieved from TCP/IP into an ASCII
  3585. * string. Allows for various conversions based on adapter type. The only
  3586. * mapping we do currently is basic 6-byte MAC address (e.g. 02-60-8C-4C-97-0E)
  3587. *
  3588. * ENTRY pAdapterInfo - pointer to IP_ADAPTER_INFO containing address info
  3589. * Buffer - pointer to buffer where address will be put
  3590. *
  3591. * EXIT Buffer - contains converted address
  3592. *
  3593. * RETURNS pointer to Buffer
  3594. *
  3595. * ASSUMES
  3596. *
  3597. ******************************************************************************/
  3598. LPSTR MapAdapterAddress(PIP_ADAPTER_INFO pAdapterInfo, LPSTR Buffer)
  3599. {
  3600. LPSTR format;
  3601. int separator;
  3602. int len;
  3603. int i;
  3604. LPSTR pbuf = Buffer;
  3605. UINT mask;
  3606. len = min((int)pAdapterInfo->AddressLength, sizeof(pAdapterInfo->Address));
  3607. switch (pAdapterInfo->Type) {
  3608. case IF_TYPE_ETHERNET_CSMACD:
  3609. case IF_TYPE_ISO88025_TOKENRING:
  3610. case IF_TYPE_FDDI:
  3611. format = "%02X";
  3612. mask = 0xff;
  3613. separator = TRUE;
  3614. break;
  3615. default:
  3616. format = "%02x";
  3617. mask = 0xff;
  3618. separator = TRUE;
  3619. break;
  3620. }
  3621. for (i = 0; i < len; ++i) {
  3622. pbuf += sprintf(pbuf, format, pAdapterInfo->Address[i] & mask);
  3623. if (separator && (i != len - 1)) {
  3624. pbuf += sprintf(pbuf, "-");
  3625. }
  3626. }
  3627. return Buffer;
  3628. }
  3629. /*******************************************************************************
  3630. *
  3631. * MapTime
  3632. *
  3633. * Converts IP lease time to more human-sensible string
  3634. *
  3635. * ENTRY AdapterInfo - pointer to IP_ADAPTER_INFO owning time variable
  3636. * TimeVal - DWORD (time_t) time value (number of milliseconds since
  3637. * virtual year dot)
  3638. *
  3639. * EXIT static buffer updated
  3640. *
  3641. * RETURNS pointer to string
  3642. *
  3643. * ASSUMES 1. The caller realizes this function returns a pointer to a static
  3644. * buffer, hence calling this function a second time, but before
  3645. * the results from the previous call have been used, will destroy
  3646. * the previous results
  3647. *
  3648. ******************************************************************************/
  3649. LPSTR MapTime(PIP_ADAPTER_INFO AdapterInfo, DWORD_PTR TimeVal)
  3650. {
  3651. struct tm* pTime;
  3652. static char timeBuf[128];
  3653. static char oemTimeBuf[256];
  3654. if (pTime = localtime(&TimeVal)) {
  3655. SYSTEMTIME systemTime;
  3656. char* pTimeBuf = timeBuf;
  3657. int n;
  3658. systemTime.wYear = pTime->tm_year + 1900;
  3659. systemTime.wMonth = pTime->tm_mon + 1;
  3660. systemTime.wDayOfWeek = (WORD)pTime->tm_wday;
  3661. systemTime.wDay = (WORD)pTime->tm_mday;
  3662. systemTime.wHour = (WORD)pTime->tm_hour;
  3663. systemTime.wMinute = (WORD)pTime->tm_min;
  3664. systemTime.wSecond = (WORD)pTime->tm_sec;
  3665. systemTime.wMilliseconds = 0;
  3666. n = GetDateFormat(0, DATE_LONGDATE, &systemTime, NULL, timeBuf, sizeof(timeBuf));
  3667. timeBuf[n - 1] = ' ';
  3668. GetTimeFormat(0, 0, &systemTime, NULL, &timeBuf[n], sizeof(timeBuf) - n);
  3669. //
  3670. // we have to convert the returned ANSI string to the OEM charset
  3671. //
  3672. //
  3673. if (CharToOem(timeBuf, oemTimeBuf)) {
  3674. return oemTimeBuf;
  3675. }
  3676. return timeBuf;
  3677. }
  3678. return "";
  3679. }
  3680. /*******************************************************************************
  3681. *
  3682. * MapTimeEx
  3683. *
  3684. * Converts IP lease time to more human-sensible string
  3685. *
  3686. * ENTRY AdapterInfo - pointer to IP_ADAPTER_INFO owning time variable
  3687. * TimeVal - DWORD (time_t) time value (number of milliseconds since
  3688. * virtual year dot)
  3689. *
  3690. * EXIT buffer allocated
  3691. *
  3692. * RETURNS pointer to string
  3693. *
  3694. * ASSUMES 1. The caller realizes this function returns a pointer to a static
  3695. * buffer, hence calling this function a second time, but before
  3696. * the results from the previous call have been used, will destroy
  3697. * the previous results
  3698. *
  3699. ******************************************************************************/
  3700. LPSTR MapTimeEx(PIP_ADAPTER_INFO AdapterInfo, DWORD_PTR TimeVal)
  3701. {
  3702. LPSTR rettime, rettimeBuf;
  3703. rettimeBuf = GrabMemory(128);
  3704. if (!rettimeBuf) {
  3705. return NULL;
  3706. }
  3707. rettime = MapTime(AdapterInfo, TimeVal);
  3708. if (strcmp(rettime, "") == 0) {
  3709. rettimeBuf[0] = '\0';
  3710. }
  3711. else {
  3712. strcpy(rettimeBuf, rettime);
  3713. }
  3714. return rettimeBuf;
  3715. }
  3716. /*******************************************************************************
  3717. *
  3718. * MapScopeId
  3719. *
  3720. * Converts scope id value. Input is a string. If it is "*" then this denotes
  3721. * that the scope id is really a null string, so we return an empty string.
  3722. * Otherwise, the input string is returned
  3723. *
  3724. * ENTRY
  3725. *
  3726. * EXIT
  3727. *
  3728. * RETURNS pointer to string
  3729. *
  3730. * ASSUMES
  3731. *
  3732. ******************************************************************************/
  3733. LPSTR MapScopeId(PVOID Param)
  3734. {
  3735. return !strcmp((LPSTR)Param, "*") ? "" : (LPSTR)Param;
  3736. }
  3737. /*******************************************************************************
  3738. *
  3739. * Terminate
  3740. *
  3741. * Cleans up - closes the registry handles, ready for process exit
  3742. *
  3743. * ENTRY
  3744. *
  3745. * EXIT
  3746. *
  3747. * RETURNS
  3748. *
  3749. * ASSUMES
  3750. *
  3751. ******************************************************************************/
  3752. VOID Terminate()
  3753. {
  3754. //
  3755. // this function probably isn't even necessary - I'm sure the system will
  3756. // clean up these handles if we just fall out
  3757. //
  3758. if (NetbtParametersKey != INVALID_HANDLE_VALUE) {
  3759. RegCloseKey(NetbtParametersKey);
  3760. }
  3761. if (NetbtInterfacesKey != INVALID_HANDLE_VALUE) {
  3762. RegCloseKey(NetbtInterfacesKey);
  3763. }
  3764. if (TcpipParametersKey != INVALID_HANDLE_VALUE) {
  3765. RegCloseKey(TcpipParametersKey);
  3766. }
  3767. if (TcpipLinkageKey != INVALID_HANDLE_VALUE) {
  3768. RegCloseKey(TcpipLinkageKey);
  3769. }
  3770. }
  3771. /*******************************************************************************
  3772. *
  3773. * GrabMemory
  3774. *
  3775. * Allocates memory. Exits with a fatal error if LocalAlloc fails, since on NT
  3776. * I don't expect this ever to occur
  3777. *
  3778. * ENTRY size
  3779. * Number of bytes to allocate
  3780. *
  3781. * EXIT
  3782. *
  3783. * RETURNS pointer to allocated memory
  3784. *
  3785. * ASSUMES
  3786. *
  3787. ******************************************************************************/
  3788. LPVOID GrabMemory(DWORD size)
  3789. {
  3790. LPVOID p;
  3791. p = (LPVOID)LocalAlloc(LMEM_FIXED, size);
  3792. if (!p) {
  3793. return NULL;
  3794. }
  3795. return p;
  3796. }
  3797. /*******************************************************************************
  3798. *
  3799. * DisplayMessage
  3800. *
  3801. * Outputs a message retrieved from the string resource attached to the exe.
  3802. * Mainly for internationalizable reasons
  3803. *
  3804. * ENTRY
  3805. *
  3806. * EXIT
  3807. *
  3808. * RETURNS
  3809. *
  3810. * ASSUMES
  3811. *
  3812. ******************************************************************************/
  3813. VOID DisplayMessage(BOOL Tabbed, DWORD MessageId, ...)
  3814. {
  3815. va_list argptr;
  3816. char messageBuffer[2048];
  3817. int count;
  3818. va_start(argptr, MessageId);
  3819. count = FormatMessage(FORMAT_MESSAGE_FROM_HMODULE,
  3820. NULL, // use default hModule
  3821. MessageId,
  3822. 0, // use default Language
  3823. messageBuffer,
  3824. sizeof(messageBuffer),
  3825. &argptr
  3826. );
  3827. if (count == 0) {
  3828. DEBUG_PRINT(("DisplayMessage: GetLastError() returns %d\n", GetLastError()));
  3829. }
  3830. va_end(argptr);
  3831. if (Tabbed) {
  3832. putchar('\t');
  3833. }
  3834. printf(messageBuffer);
  3835. }
  3836. /*******************************************************************************
  3837. *
  3838. * KillFixedInfo
  3839. *
  3840. * ENTRY
  3841. *
  3842. * EXIT
  3843. *
  3844. * RETURNS
  3845. *
  3846. * ASSUMES
  3847. *
  3848. ******************************************************************************/
  3849. VOID KillFixedInfo(PFIXED_INFO Info)
  3850. {
  3851. PIP_ADDR_STRING p;
  3852. PIP_ADDR_STRING next;
  3853. for (p = Info->DnsServerList.Next; p != NULL; p = next) {
  3854. next = p->Next;
  3855. ReleaseMemory(p);
  3856. }
  3857. ReleaseMemory(Info);
  3858. }
  3859. /*******************************************************************************
  3860. *
  3861. * KillAdapterInfo
  3862. *
  3863. * ENTRY
  3864. *
  3865. * EXIT
  3866. *
  3867. * RETURNS
  3868. *
  3869. * ASSUMES
  3870. *
  3871. ******************************************************************************/
  3872. VOID KillAdapterInfo(PIP_ADAPTER_INFO Info)
  3873. {
  3874. PIP_ADDR_STRING p;
  3875. PIP_ADDR_STRING next;
  3876. PIP_ADAPTER_INFO CurrAdapter;
  3877. PIP_ADAPTER_INFO NextAdapter;
  3878. for (CurrAdapter=Info; CurrAdapter != NULL; CurrAdapter = NextAdapter) {
  3879. for (p = CurrAdapter->IpAddressList.Next; p != NULL; p = next) {
  3880. next = p->Next;
  3881. ReleaseMemory(p);
  3882. }
  3883. for (p = CurrAdapter->GatewayList.Next; p != NULL; p = next) {
  3884. next = p->Next;
  3885. ReleaseMemory(p);
  3886. }
  3887. for (p = CurrAdapter->SecondaryWinsServer.Next; p != NULL; p = next) {
  3888. next = p->Next;
  3889. ReleaseMemory(p);
  3890. }
  3891. NextAdapter = CurrAdapter->Next;
  3892. ReleaseMemory(CurrAdapter);
  3893. }
  3894. }
  3895. VOID KillAdapterAddresses(PIP_ADAPTER_ADDRESSES Info)
  3896. {
  3897. PIP_ADAPTER_UNICAST_ADDRESS pU;
  3898. PIP_ADAPTER_UNICAST_ADDRESS nextU;
  3899. PIP_ADAPTER_ANYCAST_ADDRESS pA;
  3900. PIP_ADAPTER_ANYCAST_ADDRESS nextA;
  3901. PIP_ADAPTER_MULTICAST_ADDRESS pM;
  3902. PIP_ADAPTER_MULTICAST_ADDRESS nextM;
  3903. PIP_ADAPTER_DNS_SERVER_ADDRESS pD;
  3904. PIP_ADAPTER_DNS_SERVER_ADDRESS nextD;
  3905. PIP_ADAPTER_PREFIX pP;
  3906. PIP_ADAPTER_PREFIX nextP;
  3907. PIP_ADAPTER_ADDRESSES CurrAdapter;
  3908. PIP_ADAPTER_ADDRESSES NextAdapter;
  3909. for (CurrAdapter=Info; CurrAdapter != NULL; CurrAdapter = NextAdapter) {
  3910. FREE(CurrAdapter->Description);
  3911. FREE(CurrAdapter->FriendlyName);
  3912. FREE(CurrAdapter->DnsSuffix);
  3913. FREE(CurrAdapter->AdapterName);
  3914. for (pU = CurrAdapter->FirstUnicastAddress; pU != NULL; pU = nextU) {
  3915. FREE(pU->Address.lpSockaddr);
  3916. nextU = pU->Next;
  3917. FREE(pU);
  3918. }
  3919. for (pA = CurrAdapter->FirstAnycastAddress; pA != NULL; pA = nextA) {
  3920. FREE(pA->Address.lpSockaddr);
  3921. nextA = pA->Next;
  3922. FREE(pA);
  3923. }
  3924. for (pM = CurrAdapter->FirstMulticastAddress; pM != NULL; pM = nextM) {
  3925. FREE(pM->Address.lpSockaddr);
  3926. nextM = pM->Next;
  3927. FREE(pM);
  3928. }
  3929. for (pD = CurrAdapter->FirstDnsServerAddress; pD != NULL; pD = nextD) {
  3930. FREE(pD->Address.lpSockaddr);
  3931. nextD = pD->Next;
  3932. FREE(pD);
  3933. }
  3934. for (pP = CurrAdapter->FirstPrefix; pP != NULL; pP = nextP) {
  3935. FREE(pP->Address.lpSockaddr);
  3936. nextP = pP->Next;
  3937. FREE(pP);
  3938. }
  3939. NextAdapter = CurrAdapter->Next;
  3940. FREE(CurrAdapter);
  3941. }
  3942. }
  3943. /*******************************************************************************
  3944. *
  3945. * KillPerAdapterInfo
  3946. *
  3947. * ENTRY
  3948. *
  3949. * EXIT
  3950. *
  3951. * RETURNS
  3952. *
  3953. * ASSUMES
  3954. *
  3955. ******************************************************************************/
  3956. VOID KillPerAdapterInfo(PIP_PER_ADAPTER_INFO Info)
  3957. {
  3958. PIP_ADDR_STRING p;
  3959. PIP_ADDR_STRING next;
  3960. for (p = Info->DnsServerList.Next; p != NULL; p = next) {
  3961. next = p->Next;
  3962. ReleaseMemory(p);
  3963. }
  3964. ReleaseMemory(Info);
  3965. }
  3966. /*******************************************************************************
  3967. *
  3968. * GetIPAddrStringLen
  3969. *
  3970. * ENTRY
  3971. *
  3972. * EXIT
  3973. *
  3974. * RETURNS
  3975. *
  3976. * ASSUMES
  3977. *
  3978. ******************************************************************************/
  3979. DWORD
  3980. GetIPAddrStringLen(PIP_ADDR_STRING pIPAddrString)
  3981. {
  3982. PIP_ADDR_STRING Curr=pIPAddrString->Next;
  3983. int len = 0;
  3984. while (Curr != NULL) {
  3985. Curr=Curr->Next;
  3986. len++;
  3987. }
  3988. return len;
  3989. }
  3990. /*******************************************************************************
  3991. *
  3992. * GetSizeofFixedInfo
  3993. *
  3994. * ENTRY
  3995. *
  3996. * EXIT
  3997. *
  3998. * RETURNS
  3999. *
  4000. * ASSUMES
  4001. *
  4002. ******************************************************************************/
  4003. DWORD
  4004. GetSizeofFixedInfo(PFIXED_INFO pFixedInfo)
  4005. {
  4006. return (sizeof(FIXED_INFO) + (GetIPAddrStringLen(&pFixedInfo->DnsServerList) * sizeof(IP_ADDR_STRING)));
  4007. }
  4008. /*******************************************************************************
  4009. *
  4010. * GetFixedInfoEx
  4011. *
  4012. * ENTRY
  4013. *
  4014. * EXIT
  4015. *
  4016. * RETURNS
  4017. *
  4018. * ASSUMES
  4019. *
  4020. ******************************************************************************/
  4021. DWORD
  4022. GetFixedInfoEx(PFIXED_INFO pFixedInfo, PULONG pOutBufLen)
  4023. {
  4024. PFIXED_INFO getinfo;
  4025. PIP_ADDR_STRING DnsServerList, CurrDnsServerList;
  4026. uint len;
  4027. if (pOutBufLen == NULL) {
  4028. return ERROR_INVALID_PARAMETER;
  4029. }
  4030. getinfo = GetFixedInfo();
  4031. try {
  4032. if (!pFixedInfo || (*pOutBufLen < GetSizeofFixedInfo(getinfo)) ) {
  4033. *pOutBufLen = GetSizeofFixedInfo(getinfo);
  4034. KillFixedInfo(getinfo);
  4035. return ERROR_BUFFER_OVERFLOW;
  4036. }
  4037. ZeroMemory(pFixedInfo, *pOutBufLen);
  4038. CopyMemory(pFixedInfo, getinfo, sizeof(FIXED_INFO));
  4039. DnsServerList = getinfo->DnsServerList.Next;
  4040. CurrDnsServerList = &pFixedInfo->DnsServerList;
  4041. CurrDnsServerList->Next = NULL;
  4042. len = sizeof(FIXED_INFO);
  4043. while (DnsServerList != NULL) {
  4044. CurrDnsServerList->Next = (PIP_ADDR_STRING)((ULONG_PTR)pFixedInfo + len);
  4045. CopyMemory(CurrDnsServerList->Next, DnsServerList, sizeof(IP_ADDR_STRING));
  4046. CurrDnsServerList = CurrDnsServerList->Next;
  4047. DnsServerList = DnsServerList->Next;
  4048. len = len + sizeof(IP_ADDR_STRING);
  4049. }
  4050. KillFixedInfo(getinfo);
  4051. return ERROR_SUCCESS;
  4052. }
  4053. except (EXCEPTION_EXECUTE_HANDLER) {
  4054. // printf("Exception %d \n", GetExceptionCode());
  4055. return ERROR_INVALID_PARAMETER;
  4056. }
  4057. }
  4058. /*******************************************************************************
  4059. *
  4060. * GetSizeofAdapterInfo
  4061. *
  4062. * ENTRY
  4063. *
  4064. * EXIT
  4065. *
  4066. * RETURNS
  4067. *
  4068. * ASSUMES
  4069. *
  4070. ******************************************************************************/
  4071. DWORD
  4072. GetSizeofAdapterInfo(PIP_ADAPTER_INFO pAdapterInfo)
  4073. {
  4074. DWORD size = 0;
  4075. while (pAdapterInfo != NULL) {
  4076. size += sizeof(IP_ADAPTER_INFO) +
  4077. (GetIPAddrStringLen(&pAdapterInfo->IpAddressList) *
  4078. sizeof(IP_ADDR_STRING)) +
  4079. (GetIPAddrStringLen(&pAdapterInfo->GatewayList) *
  4080. sizeof(IP_ADDR_STRING)) +
  4081. (GetIPAddrStringLen(&pAdapterInfo->SecondaryWinsServer) *
  4082. sizeof(IP_ADDR_STRING));
  4083. pAdapterInfo = pAdapterInfo->Next;
  4084. }
  4085. return size;
  4086. }
  4087. /*******************************************************************************
  4088. * GetSizeofAdapterAddresses
  4089. *
  4090. * This routine determines how much memory is used by data organized in a set
  4091. * of IP_ADAPTER_ADDRESSES information.
  4092. *
  4093. * ENTRY pAdapterInfo - information to get total size for
  4094. *
  4095. * EXIT
  4096. *
  4097. * RETURNS amount of memory used
  4098. *
  4099. ******************************************************************************/
  4100. DWORD GetSizeofAdapterAddresses(PIP_ADAPTER_ADDRESSES pAdapterInfo)
  4101. {
  4102. DWORD size = 0;
  4103. PIP_ADAPTER_UNICAST_ADDRESS pUAddress;
  4104. PIP_ADAPTER_ANYCAST_ADDRESS pAAddress;
  4105. PIP_ADAPTER_MULTICAST_ADDRESS pMAddress;
  4106. PIP_ADAPTER_DNS_SERVER_ADDRESS pDAddress;
  4107. PIP_ADAPTER_PREFIX pPrefix;
  4108. while (pAdapterInfo != NULL) {
  4109. size += sizeof(IP_ADAPTER_ADDRESSES);
  4110. size += (wcslen(pAdapterInfo->FriendlyName)+1) * sizeof(WCHAR);
  4111. size += (wcslen(pAdapterInfo->Description)+1) * sizeof(WCHAR);
  4112. size += (wcslen(pAdapterInfo->DnsSuffix)+1) * sizeof(WCHAR);
  4113. size += (strlen(pAdapterInfo->AdapterName)+1);
  4114. size = ALIGN_UP(size, PVOID);
  4115. for ( pUAddress = pAdapterInfo->FirstUnicastAddress;
  4116. pUAddress;
  4117. pUAddress = pUAddress->Next) {
  4118. size += sizeof(IP_ADAPTER_UNICAST_ADDRESS) + ALIGN_UP(pUAddress->Address.iSockaddrLength, PVOID);
  4119. }
  4120. for ( pAAddress = pAdapterInfo->FirstAnycastAddress;
  4121. pAAddress;
  4122. pAAddress = pAAddress->Next) {
  4123. size += sizeof(IP_ADAPTER_ANYCAST_ADDRESS) + ALIGN_UP(pAAddress->Address.iSockaddrLength, PVOID);
  4124. }
  4125. for ( pMAddress = pAdapterInfo->FirstMulticastAddress;
  4126. pMAddress;
  4127. pMAddress = pMAddress->Next) {
  4128. size += sizeof(IP_ADAPTER_MULTICAST_ADDRESS) + ALIGN_UP(pMAddress->Address.iSockaddrLength, PVOID);
  4129. }
  4130. for ( pDAddress = pAdapterInfo->FirstDnsServerAddress;
  4131. pDAddress;
  4132. pDAddress = pDAddress->Next) {
  4133. size += sizeof(IP_ADAPTER_DNS_SERVER_ADDRESS) + ALIGN_UP(pDAddress->Address.iSockaddrLength, PVOID);
  4134. }
  4135. for ( pPrefix = pAdapterInfo->FirstPrefix;
  4136. pPrefix;
  4137. pPrefix = pPrefix->Next) {
  4138. size += sizeof(IP_ADAPTER_PREFIX) + ALIGN_UP(pPrefix->Address.iSockaddrLength, PVOID);
  4139. }
  4140. pAdapterInfo = pAdapterInfo->Next;
  4141. }
  4142. return size;
  4143. }
  4144. /*******************************************************************************
  4145. *
  4146. * GetSizeofPerAdapterInfo
  4147. *
  4148. * ENTRY
  4149. *
  4150. * EXIT
  4151. *
  4152. * RETURNS
  4153. *
  4154. * ASSUMES
  4155. *
  4156. ******************************************************************************/
  4157. DWORD
  4158. GetSizeofPerAdapterInfo(PIP_PER_ADAPTER_INFO pPerAdapterInfo)
  4159. {
  4160. return (sizeof(IP_PER_ADAPTER_INFO) + (GetIPAddrStringLen(&pPerAdapterInfo->DnsServerList) * sizeof(IP_ADDR_STRING)));
  4161. }
  4162. /*******************************************************************************
  4163. *
  4164. * GetAdapterInfoEx
  4165. *
  4166. * ENTRY
  4167. *
  4168. * EXIT
  4169. *
  4170. * RETURNS
  4171. *
  4172. * ASSUMES
  4173. *
  4174. ******************************************************************************/
  4175. DWORD
  4176. GetAdapterInfoEx(PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen)
  4177. {
  4178. PIP_ADAPTER_INFO getinfo, orginfoptr, CurrAdapterInfo;
  4179. PIP_ADDR_STRING IpAddressList, CurrIpAddressList;
  4180. PIP_ADDR_STRING GatewayList, CurrGatewayList;
  4181. PIP_ADDR_STRING SecondaryWinsServer, CurrSecondaryWinsServer;
  4182. uint len;
  4183. if (pOutBufLen == NULL) {
  4184. return ERROR_INVALID_PARAMETER;
  4185. }
  4186. getinfo = GetAdapterInfo();
  4187. if (getinfo == NULL) {
  4188. return ERROR_NO_DATA;
  4189. }
  4190. orginfoptr = getinfo;
  4191. try {
  4192. if (!pAdapterInfo || (*pOutBufLen < GetSizeofAdapterInfo(getinfo)) ) {
  4193. *pOutBufLen = GetSizeofAdapterInfo(getinfo);
  4194. KillAdapterInfo(getinfo);
  4195. return ERROR_BUFFER_OVERFLOW;
  4196. }
  4197. ZeroMemory(pAdapterInfo, *pOutBufLen);
  4198. CurrAdapterInfo = pAdapterInfo;
  4199. while (getinfo != NULL) {
  4200. // pAdapterInfo->Next = (PIP_ADAPTER_INFO)((uint)pAdapterInfo + len);
  4201. // copy the adapter info structure
  4202. CopyMemory(CurrAdapterInfo, getinfo, sizeof(IP_ADAPTER_INFO));
  4203. // copy the IPAddressList & GatewayList
  4204. IpAddressList = getinfo->IpAddressList.Next;
  4205. CurrIpAddressList = &CurrAdapterInfo->IpAddressList;
  4206. CurrIpAddressList->Next = NULL;
  4207. len = sizeof(IP_ADAPTER_INFO);
  4208. while (IpAddressList != NULL) {
  4209. CurrIpAddressList->Next = (PIP_ADDR_STRING)((ULONG_PTR)CurrAdapterInfo + len);
  4210. CopyMemory(CurrIpAddressList->Next, IpAddressList, sizeof(IP_ADDR_STRING));
  4211. CurrIpAddressList = CurrIpAddressList->Next;
  4212. IpAddressList = IpAddressList->Next;
  4213. len = len + sizeof(IP_ADDR_STRING);
  4214. }
  4215. GatewayList = getinfo->GatewayList.Next;
  4216. CurrGatewayList = &CurrAdapterInfo->GatewayList;
  4217. CurrGatewayList->Next = NULL;
  4218. while (GatewayList != NULL) {
  4219. CurrGatewayList->Next = (PIP_ADDR_STRING) ((ULONG_PTR)CurrAdapterInfo + len);
  4220. CopyMemory(CurrGatewayList->Next, GatewayList, sizeof(IP_ADDR_STRING));
  4221. CurrGatewayList = CurrGatewayList->Next;
  4222. GatewayList = GatewayList->Next;
  4223. len = len + sizeof(IP_ADDR_STRING);
  4224. }
  4225. SecondaryWinsServer = getinfo->SecondaryWinsServer.Next;
  4226. CurrSecondaryWinsServer = &CurrAdapterInfo->SecondaryWinsServer;
  4227. CurrSecondaryWinsServer->Next = NULL;
  4228. while (SecondaryWinsServer != NULL) {
  4229. CurrSecondaryWinsServer->Next =
  4230. (PIP_ADDR_STRING) ((ULONG_PTR)CurrAdapterInfo + len);
  4231. CopyMemory(CurrSecondaryWinsServer->Next,
  4232. SecondaryWinsServer, sizeof(IP_ADDR_STRING));
  4233. CurrSecondaryWinsServer = CurrSecondaryWinsServer->Next;
  4234. SecondaryWinsServer = SecondaryWinsServer->Next;
  4235. len = len + sizeof(IP_ADDR_STRING);
  4236. }
  4237. pAdapterInfo = CurrAdapterInfo;
  4238. CurrAdapterInfo->Next = (PIP_ADAPTER_INFO)((ULONG_PTR)CurrAdapterInfo + len);
  4239. CurrAdapterInfo = CurrAdapterInfo->Next;
  4240. getinfo = getinfo->Next;
  4241. }
  4242. pAdapterInfo->Next = NULL;
  4243. KillAdapterInfo(orginfoptr);
  4244. return ERROR_SUCCESS;
  4245. } except (EXCEPTION_EXECUTE_HANDLER) {
  4246. // printf("Exception %d \n", GetExceptionCode());
  4247. KillAdapterInfo(orginfoptr);
  4248. return ERROR_INVALID_PARAMETER;
  4249. }
  4250. }
  4251. DWORD
  4252. GetAdapterAddressesEx(ULONG Family, DWORD Flags, PIP_ADAPTER_ADDRESSES pAdapterInfo, PULONG pOutBufLen)
  4253. {
  4254. PIP_ADAPTER_ADDRESSES getinfo, orginfoptr, CurrAdapterInfo;
  4255. PIP_ADAPTER_UNICAST_ADDRESS SrcUAddress, *pDestUAddress;
  4256. PIP_ADAPTER_ANYCAST_ADDRESS SrcAAddress, *pDestAAddress;
  4257. PIP_ADAPTER_MULTICAST_ADDRESS SrcMAddress, *pDestMAddress;
  4258. PIP_ADAPTER_DNS_SERVER_ADDRESS SrcDAddress, *pDestDAddress;
  4259. ULONG_PTR pDestBuffer;
  4260. uint len;
  4261. DWORD dwErr;
  4262. if (pOutBufLen == NULL) {
  4263. return ERROR_INVALID_PARAMETER;
  4264. }
  4265. dwErr = GetAdapterAddresses(Family, Flags, &getinfo);
  4266. if (dwErr != NO_ERROR) {
  4267. if (getinfo) {
  4268. KillAdapterAddresses(getinfo);
  4269. }
  4270. return dwErr;
  4271. }
  4272. if (getinfo == NULL) {
  4273. return ERROR_NO_DATA;
  4274. }
  4275. orginfoptr = getinfo;
  4276. try {
  4277. if (!pAdapterInfo || (*pOutBufLen < GetSizeofAdapterAddresses(getinfo)) ) {
  4278. *pOutBufLen = GetSizeofAdapterAddresses(getinfo);
  4279. KillAdapterAddresses(getinfo);
  4280. return ERROR_BUFFER_OVERFLOW;
  4281. }
  4282. ZeroMemory(pAdapterInfo, *pOutBufLen);
  4283. CurrAdapterInfo = pAdapterInfo;
  4284. while (getinfo != NULL) {
  4285. // pAdapterInfo->Next = (PIP_ADAPTER_ADDRESSES)((uint)pAdapterInfo + len);
  4286. // copy the adapter info structure
  4287. CopyMemory(CurrAdapterInfo, getinfo, sizeof(IP_ADAPTER_ADDRESSES));
  4288. pDestBuffer = (ULONG_PTR)CurrAdapterInfo + sizeof(IP_ADAPTER_ADDRESSES);
  4289. CurrAdapterInfo->FriendlyName = (PWCHAR)pDestBuffer;
  4290. wcscpy(CurrAdapterInfo->FriendlyName, getinfo->FriendlyName);
  4291. pDestBuffer += (wcslen(CurrAdapterInfo->FriendlyName)+1) * sizeof(WCHAR);
  4292. CurrAdapterInfo->Description = (PWCHAR)pDestBuffer;
  4293. wcscpy(CurrAdapterInfo->Description, getinfo->Description);
  4294. pDestBuffer += (wcslen(CurrAdapterInfo->Description)+1) * sizeof(WCHAR);
  4295. CurrAdapterInfo->DnsSuffix = (PWCHAR)pDestBuffer;
  4296. wcscpy(CurrAdapterInfo->DnsSuffix, getinfo->DnsSuffix);
  4297. pDestBuffer += (wcslen(CurrAdapterInfo->DnsSuffix)+1) * sizeof(WCHAR);
  4298. CurrAdapterInfo->AdapterName = (PCHAR)pDestBuffer;
  4299. strcpy(CurrAdapterInfo->AdapterName, getinfo->AdapterName);
  4300. pDestBuffer += (strlen(CurrAdapterInfo->AdapterName)+1);
  4301. pDestBuffer = ALIGN_UP_PTR(pDestBuffer, PVOID);
  4302. // copy the address lists
  4303. if (!(Flags & GAA_FLAG_SKIP_UNICAST)) {
  4304. SrcUAddress = getinfo->FirstUnicastAddress;
  4305. pDestUAddress = &CurrAdapterInfo->FirstUnicastAddress;
  4306. while (SrcUAddress != NULL) {
  4307. *pDestUAddress = (PIP_ADAPTER_UNICAST_ADDRESS)pDestBuffer;
  4308. // copy address structure
  4309. CopyMemory((PVOID)pDestBuffer, SrcUAddress,
  4310. sizeof(IP_ADAPTER_UNICAST_ADDRESS));
  4311. pDestBuffer += sizeof(IP_ADAPTER_UNICAST_ADDRESS);
  4312. (*pDestUAddress)->Address.lpSockaddr = (LPSOCKADDR)pDestBuffer;
  4313. // copy sockaddr
  4314. CopyMemory((PVOID)pDestBuffer, SrcUAddress->Address.lpSockaddr,
  4315. SrcUAddress->Address.iSockaddrLength);
  4316. pDestBuffer += SrcUAddress->Address.iSockaddrLength;
  4317. pDestBuffer = ALIGN_UP_PTR(pDestBuffer, PVOID);
  4318. pDestUAddress = &(*pDestUAddress)->Next;
  4319. SrcUAddress = SrcUAddress->Next;
  4320. }
  4321. }
  4322. if (!(Flags & GAA_FLAG_SKIP_ANYCAST)) {
  4323. SrcAAddress = getinfo->FirstAnycastAddress;
  4324. pDestAAddress = &CurrAdapterInfo->FirstAnycastAddress;
  4325. while (SrcAAddress != NULL) {
  4326. *pDestAAddress = (PIP_ADAPTER_ANYCAST_ADDRESS)pDestBuffer;
  4327. // copy address structure
  4328. CopyMemory((PVOID)pDestBuffer, SrcAAddress,
  4329. sizeof(IP_ADAPTER_ANYCAST_ADDRESS));
  4330. pDestBuffer += sizeof(IP_ADAPTER_ANYCAST_ADDRESS);
  4331. (*pDestAAddress)->Address.lpSockaddr = (LPSOCKADDR)pDestBuffer;
  4332. // copy sockaddr
  4333. CopyMemory((PVOID)pDestBuffer, SrcAAddress->Address.lpSockaddr,
  4334. SrcAAddress->Address.iSockaddrLength);
  4335. pDestBuffer += SrcAAddress->Address.iSockaddrLength;
  4336. pDestBuffer = ALIGN_UP_PTR(pDestBuffer, PVOID);
  4337. pDestAAddress = &(*pDestAAddress)->Next;
  4338. SrcAAddress = SrcAAddress->Next;
  4339. }
  4340. }
  4341. if (!(Flags & GAA_FLAG_SKIP_MULTICAST)) {
  4342. SrcMAddress = getinfo->FirstMulticastAddress;
  4343. pDestMAddress = &CurrAdapterInfo->FirstMulticastAddress;
  4344. while (SrcMAddress != NULL) {
  4345. *pDestMAddress = (PIP_ADAPTER_MULTICAST_ADDRESS)pDestBuffer;
  4346. // copy address structure
  4347. CopyMemory((PVOID)pDestBuffer, SrcMAddress,
  4348. sizeof(IP_ADAPTER_MULTICAST_ADDRESS));
  4349. pDestBuffer += sizeof(IP_ADAPTER_MULTICAST_ADDRESS);
  4350. (*pDestMAddress)->Address.lpSockaddr = (LPSOCKADDR)pDestBuffer;
  4351. // copy sockaddr
  4352. CopyMemory((PVOID)pDestBuffer, SrcMAddress->Address.lpSockaddr,
  4353. SrcMAddress->Address.iSockaddrLength);
  4354. pDestBuffer += SrcMAddress->Address.iSockaddrLength;
  4355. pDestBuffer = ALIGN_UP_PTR(pDestBuffer, PVOID);
  4356. pDestMAddress = &(*pDestMAddress)->Next;
  4357. SrcMAddress = SrcMAddress->Next;
  4358. }
  4359. }
  4360. if (!(Flags & GAA_FLAG_SKIP_DNS_SERVER)) {
  4361. SrcDAddress = getinfo->FirstDnsServerAddress;
  4362. pDestDAddress = &CurrAdapterInfo->FirstDnsServerAddress;
  4363. while (SrcDAddress != NULL) {
  4364. *pDestDAddress = (PIP_ADAPTER_DNS_SERVER_ADDRESS)pDestBuffer;
  4365. // copy address structure
  4366. CopyMemory((PVOID)pDestBuffer, SrcDAddress,
  4367. sizeof(IP_ADAPTER_DNS_SERVER_ADDRESS));
  4368. pDestBuffer += sizeof(IP_ADAPTER_DNS_SERVER_ADDRESS);
  4369. (*pDestDAddress)->Address.lpSockaddr = (LPSOCKADDR)pDestBuffer;
  4370. // copy sockaddr
  4371. CopyMemory((PVOID)pDestBuffer, SrcDAddress->Address.lpSockaddr,
  4372. SrcDAddress->Address.iSockaddrLength);
  4373. pDestBuffer += SrcDAddress->Address.iSockaddrLength;
  4374. pDestBuffer = ALIGN_UP_PTR(pDestBuffer, PVOID);
  4375. pDestDAddress = &(*pDestDAddress)->Next;
  4376. SrcDAddress = SrcDAddress->Next;
  4377. }
  4378. }
  4379. if (Flags & GAA_FLAG_INCLUDE_PREFIX) {
  4380. PIP_ADAPTER_PREFIX SrcPrefix, *pDestPrefix;
  4381. SrcPrefix = getinfo->FirstPrefix;
  4382. pDestPrefix = &CurrAdapterInfo->FirstPrefix;
  4383. while (SrcPrefix != NULL) {
  4384. *pDestPrefix = (PIP_ADAPTER_PREFIX)pDestBuffer;
  4385. // copy structure
  4386. CopyMemory((PVOID)pDestBuffer, SrcPrefix,
  4387. sizeof(IP_ADAPTER_PREFIX));
  4388. pDestBuffer += sizeof(IP_ADAPTER_PREFIX);
  4389. (*pDestPrefix)->Address.lpSockaddr = (LPSOCKADDR)pDestBuffer;
  4390. // copy sockaddr
  4391. CopyMemory((PVOID)pDestBuffer, SrcPrefix->Address.lpSockaddr,
  4392. SrcPrefix->Address.iSockaddrLength);
  4393. pDestBuffer += SrcPrefix->Address.iSockaddrLength;
  4394. pDestBuffer = ALIGN_UP_PTR(pDestBuffer, PVOID);
  4395. pDestPrefix = &(*pDestPrefix)->Next;
  4396. SrcPrefix = SrcPrefix->Next;
  4397. }
  4398. }
  4399. pAdapterInfo = CurrAdapterInfo;
  4400. CurrAdapterInfo->Next = (PIP_ADAPTER_ADDRESSES)pDestBuffer;
  4401. CurrAdapterInfo = CurrAdapterInfo->Next;
  4402. getinfo = getinfo->Next;
  4403. }
  4404. pAdapterInfo->Next = NULL;
  4405. KillAdapterAddresses(orginfoptr);
  4406. return ERROR_SUCCESS;
  4407. }
  4408. except (EXCEPTION_EXECUTE_HANDLER) {
  4409. // printf("Exception %d \n", GetExceptionCode());
  4410. KillAdapterAddresses(orginfoptr);
  4411. return ERROR_INVALID_PARAMETER;
  4412. }
  4413. }
  4414. /*******************************************************************************
  4415. *
  4416. * GetPerAdapterInfoEx
  4417. *
  4418. * ENTRY
  4419. *
  4420. * EXIT
  4421. *
  4422. * RETURNS
  4423. *
  4424. * ASSUMES
  4425. *
  4426. ******************************************************************************/
  4427. DWORD
  4428. GetPerAdapterInfoEx(ULONG IfIndex,
  4429. PIP_PER_ADAPTER_INFO pPerAdapterInfo,
  4430. PULONG pOutBufLen
  4431. )
  4432. {
  4433. PIP_PER_ADAPTER_INFO getinfo;
  4434. PIP_ADDR_STRING DnsServerList, CurrDnsServerList;
  4435. UINT len;
  4436. if (pOutBufLen == NULL) {
  4437. return ERROR_INVALID_PARAMETER;
  4438. }
  4439. getinfo = InternalGetPerAdapterInfo(IfIndex);
  4440. if (getinfo == NULL) {
  4441. return ERROR_NO_DATA;
  4442. }
  4443. try {
  4444. if (!pPerAdapterInfo ||
  4445. *pOutBufLen < GetSizeofPerAdapterInfo(getinfo)) {
  4446. *pOutBufLen = GetSizeofPerAdapterInfo(getinfo);
  4447. KillPerAdapterInfo(getinfo);
  4448. return ERROR_BUFFER_OVERFLOW;
  4449. }
  4450. ZeroMemory(pPerAdapterInfo, *pOutBufLen);
  4451. CopyMemory(pPerAdapterInfo, getinfo, sizeof(IP_PER_ADAPTER_INFO));
  4452. DnsServerList = getinfo->DnsServerList.Next;
  4453. CurrDnsServerList = &pPerAdapterInfo->DnsServerList;
  4454. CurrDnsServerList->Next = NULL;
  4455. len = sizeof(IP_PER_ADAPTER_INFO);
  4456. while (DnsServerList != NULL) {
  4457. CurrDnsServerList->Next = (PIP_ADDR_STRING)((ULONG_PTR)pPerAdapterInfo + len);
  4458. CopyMemory(CurrDnsServerList->Next, DnsServerList, sizeof(IP_ADDR_STRING));
  4459. CurrDnsServerList = CurrDnsServerList->Next;
  4460. DnsServerList = DnsServerList->Next;
  4461. len = len + sizeof(IP_ADDR_STRING);
  4462. }
  4463. KillPerAdapterInfo(getinfo);
  4464. return ERROR_SUCCESS;
  4465. }
  4466. except (EXCEPTION_EXECUTE_HANDLER) {
  4467. // printf("Exception %d \n", GetExceptionCode());
  4468. return ERROR_INVALID_PARAMETER;
  4469. }
  4470. }
  4471. /*******************************************************************************
  4472. *
  4473. * ReleaseAdapterIpAddress
  4474. *
  4475. * ENTRY
  4476. *
  4477. * EXIT
  4478. *
  4479. * RETURNS
  4480. *
  4481. * ASSUMES
  4482. *
  4483. ******************************************************************************/
  4484. BOOL
  4485. ReleaseAdapterIpAddress(PIP_ADAPTER_INFO adapterInfo)
  4486. {
  4487. WCHAR wAdapter[MAX_ALLOWED_ADAPTER_NAME_LENGTH + 1];
  4488. DWORD status;
  4489. //
  4490. // check adapter pointer and name
  4491. //
  4492. if (adapterInfo == NULL || strcmp(adapterInfo->AdapterName, "") == 0) {
  4493. return FALSE;
  4494. }
  4495. //
  4496. // don't bother releasing if the address is already released (0.0.0.0).
  4497. //
  4498. if (ZERO_IP_ADDRESS(adapterInfo->IpAddressList.IpAddress.String)) {
  4499. return FALSE;
  4500. }
  4501. //
  4502. // convert adapter name to unicode and call DhcpReleaseParameters
  4503. //
  4504. ConvertOemToUnicode(adapterInfo->AdapterName, wAdapter);
  4505. status = DhcpReleaseParameters(wAdapter);
  4506. TRACE_PRINT(("DhcpReleaseParameters(%ws) returns %d\n",
  4507. wAdapter, status));
  4508. return status == ERROR_SUCCESS;
  4509. }
  4510. /*******************************************************************************
  4511. *
  4512. * RenewAdapterIpAddress
  4513. *
  4514. * ENTRY
  4515. *
  4516. * EXIT
  4517. *
  4518. * RETURNS
  4519. *
  4520. * ASSUMES
  4521. *
  4522. ******************************************************************************/
  4523. BOOL
  4524. RenewAdapterIpAddress(PIP_ADAPTER_INFO adapterInfo)
  4525. {
  4526. WCHAR wAdapter[MAX_ALLOWED_ADAPTER_NAME_LENGTH + 1];
  4527. DWORD status;
  4528. //
  4529. // check adapter pointer and name
  4530. //
  4531. if (adapterInfo == NULL || strcmp(adapterInfo->AdapterName, "") == 0) {
  4532. return FALSE;
  4533. }
  4534. //
  4535. // convert adapter name to unicode and call DhcpAcquireParameters
  4536. //
  4537. ConvertOemToUnicode(adapterInfo->AdapterName, wAdapter);
  4538. status = DhcpAcquireParameters(wAdapter);
  4539. TRACE_PRINT(("DhcpAcquireParameters(%ws) returns %d\n",
  4540. wAdapter, status));
  4541. return status == ERROR_SUCCESS;
  4542. }
  4543. /*******************************************************************************
  4544. *
  4545. * SetAdapterIpAddress
  4546. *
  4547. * ENTRY
  4548. *
  4549. * EXIT
  4550. *
  4551. * RETURNS
  4552. *
  4553. * ASSUMES
  4554. *
  4555. ******************************************************************************/
  4556. DWORD APIENTRY
  4557. SetAdapterIpAddress(LPSTR AdapterName,
  4558. BOOL EnableDHCP,
  4559. ULONG IPAddress,
  4560. ULONG SubnetMask,
  4561. ULONG DefaultGateway
  4562. )
  4563. {
  4564. DWORD dwEnableDHCP;
  4565. DWORD dwDHCPEnabled;
  4566. IP_ADDR_STRING IpAddrString;
  4567. HKEY key;
  4568. WCHAR Name[MAX_ADAPTER_NAME_LENGTH + 1];
  4569. CHAR String[20];
  4570. DWORD status;
  4571. if (!OpenAdapterKey(KEY_TCP, AdapterName, KEY_ALL_ACCESS, &key)) {
  4572. return ERROR_CAN_NOT_COMPLETE;
  4573. }
  4574. //
  4575. // We cannot handle netcards with multiple addresses,
  4576. // so check for that case up front
  4577. //
  4578. ZeroMemory(&IpAddrString, sizeof(IpAddrString));
  4579. if (!ReadRegistryIpAddrString(key, "IPAddress", &IpAddrString)) {
  4580. return ERROR_CAN_NOT_COMPLETE;
  4581. }
  4582. if (IpAddrString.Next) {
  4583. PIP_ADDR_STRING p;
  4584. for (p = IpAddrString.Next; p != NULL; p = IpAddrString.Next) {
  4585. IpAddrString.Next = p->Next;
  4586. ReleaseMemory(p);
  4587. }
  4588. return ERROR_TOO_MANY_NAMES;
  4589. }
  4590. //
  4591. // If we're setting a static address, check to see if the adapter
  4592. // currently has a static or DHCP address.
  4593. //
  4594. if (!EnableDHCP) {
  4595. if (!MyReadRegistryDword(key, "EnableDHCP", &dwDHCPEnabled)) {
  4596. //
  4597. // If an error occurs assume that DHCP was NOT enabled.
  4598. //
  4599. dwDHCPEnabled = FALSE;
  4600. }
  4601. }
  4602. //
  4603. // Update the address, mask, and gateway in the registry
  4604. //
  4605. dwEnableDHCP = !!EnableDHCP;
  4606. WriteRegistryDword(key, "EnableDHCP", &dwEnableDHCP);
  4607. if (EnableDHCP) { IPAddress = SubnetMask = DefaultGateway = 0; }
  4608. ZeroMemory(String, sizeof(String));
  4609. lstrcpy(String, inet_ntoa(*(struct in_addr*)&IPAddress));
  4610. WriteRegistryMultiString(key, "IPAddress", String);
  4611. ZeroMemory(String, sizeof(String));
  4612. lstrcpy(String, inet_ntoa(*(struct in_addr*)&SubnetMask));
  4613. WriteRegistryMultiString(key, "SubnetMask", String);
  4614. ZeroMemory(String, sizeof(String));
  4615. if (DefaultGateway) {
  4616. lstrcpy(String, inet_ntoa(*(struct in_addr*)&DefaultGateway));
  4617. }
  4618. WriteRegistryMultiString(key, "DefaultGateway", String);
  4619. RegCloseKey(key);
  4620. //
  4621. // Notify DHCP of the change
  4622. //
  4623. mbstowcs(Name, AdapterName, MAX_ADAPTER_NAME_LENGTH);
  4624. if (EnableDHCP) {
  4625. status = DhcpNotifyConfigChange(NULL, Name, FALSE, 0, 0, 0,
  4626. DhcpEnable
  4627. );
  4628. }
  4629. else {
  4630. //
  4631. // If the netcard previously had a static address we need
  4632. // to remove it before setting the new address.
  4633. //
  4634. if (!dwDHCPEnabled) {
  4635. DhcpNotifyConfigChange(NULL, Name, TRUE, 0, 0, 0,
  4636. IgnoreFlag
  4637. );
  4638. }
  4639. status = DhcpNotifyConfigChange(NULL, Name, TRUE, 0,
  4640. IPAddress, SubnetMask,
  4641. DhcpDisable
  4642. );
  4643. }
  4644. return status;
  4645. }
  4646. /*******************************************************************************
  4647. *
  4648. * GetDnsServerList
  4649. *
  4650. * Gets DNS server List
  4651. *
  4652. * ENTRY
  4653. *
  4654. * EXIT
  4655. *
  4656. * RETURNS
  4657. *
  4658. * ASSUMES
  4659. *
  4660. ******************************************************************************/
  4661. BOOL
  4662. GetDnsServerList(PIP_ADDR_STRING IpAddr)
  4663. {
  4664. PIP_ADAPTER_INFO adapterList;
  4665. PIP_ADAPTER_INFO adapter;
  4666. PIP_PER_ADAPTER_INFO perAdapterInfo = NULL;
  4667. LONG err = ERROR_PATH_NOT_FOUND;
  4668. HKEY key;
  4669. BOOL ok;
  4670. TRACE_PRINT(("Entered GetDnsServerList\n"));
  4671. if ((adapterList = GetAdapterInfo()) != NULL) {
  4672. //
  4673. // scan the adapter list and try to insert DNS names to IpAddr
  4674. //
  4675. for (adapter = adapterList; adapter; adapter = adapter->Next) {
  4676. if (adapter->AdapterName[0] &&
  4677. OpenAdapterKey(KEY_TCP, adapter->AdapterName, KEY_READ, &key)) {
  4678. //
  4679. // DNS Server list: first NameServer and then DhcpNameServer
  4680. //
  4681. ok = ReadRegistryIpAddrString(key,
  4682. TEXT("NameServer"),
  4683. IpAddr);
  4684. if (!ok) {
  4685. ok = ReadRegistryIpAddrString(key,
  4686. TEXT("DhcpNameServer"),
  4687. IpAddr);
  4688. }
  4689. if (ok) {
  4690. err = ERROR_SUCCESS;
  4691. }
  4692. RegCloseKey(key);
  4693. } else {
  4694. DEBUG_PRINT(("Cannot OpenAdapterKey KEY_TCP '%s', gle=%d\n",
  4695. adapter->AdapterName,
  4696. GetLastError()));
  4697. }
  4698. }
  4699. KillAdapterInfo(adapterList);
  4700. } else {
  4701. DEBUG_PRINT(("GetDnsServerList: GetAdapterInfo returns NULL\n"));
  4702. }
  4703. TRACE_PRINT(("Exit GetDnsServerList\n"));
  4704. return (err == ERROR_SUCCESS);
  4705. }
  4706. /*******************************************************************************
  4707. * GetAdapterOrderMap
  4708. *
  4709. * This routine builds an array which maps interface indices to their
  4710. * respective adapter orderings.
  4711. *
  4712. * ENTRY nothing
  4713. *
  4714. * EXIT nothing
  4715. *
  4716. * RETURNS IP_ADAPTER_ORDER_MAP
  4717. *
  4718. ******************************************************************************/
  4719. PIP_ADAPTER_ORDER_MAP APIENTRY GetAdapterOrderMap()
  4720. {
  4721. LPWSTR AdapterOrder = NULL;
  4722. LPWSTR Adapter;
  4723. PIP_ADAPTER_ORDER_MAP AdapterOrderMap = NULL;
  4724. DWORD dwErr;
  4725. DWORD dwType;
  4726. DWORD dwSize;
  4727. DWORD i;
  4728. DWORD j;
  4729. PIP_INTERFACE_INFO InterfaceInfo = NULL;
  4730. do {
  4731. //
  4732. // Retrieve the 'Bind' REG_MULTI_SZ from the Tcpip\Linkage key.
  4733. // This string-list tells us the current adapter order,
  4734. // with each entry being of the form \Device\{GUID}.
  4735. //
  4736. dwSize = 0;
  4737. dwErr = RegQueryValueExW(TcpipLinkageKey, L"Bind", NULL, &dwType,
  4738. NULL, &dwSize);
  4739. if (dwErr != NO_ERROR || dwType != REG_MULTI_SZ) { break; }
  4740. AdapterOrder = (LPWSTR)GrabMemory(dwSize);
  4741. if (!AdapterOrder) { break; }
  4742. dwErr = RegQueryValueExW(TcpipLinkageKey, L"Bind", NULL, &dwType,
  4743. (LPBYTE)AdapterOrder, &dwSize);
  4744. if (dwErr != NO_ERROR || dwType != REG_MULTI_SZ) { break; }
  4745. //
  4746. // Retrieve the IP interface information from TCP/IP.
  4747. // This information tells us the interface index
  4748. // for each adapter GUID,
  4749. //
  4750. dwSize = 0;
  4751. dwErr = GetInterfaceInfo(NULL, &dwSize);
  4752. if (dwErr != ERROR_INSUFFICIENT_BUFFER &&
  4753. dwErr != ERROR_BUFFER_OVERFLOW) {
  4754. break;
  4755. }
  4756. InterfaceInfo = GrabMemory(dwSize);
  4757. if (!InterfaceInfo) { break; }
  4758. dwErr = GetInterfaceInfo(InterfaceInfo, &dwSize);
  4759. if (dwErr != NO_ERROR) { break; }
  4760. //
  4761. // Construct a mapping from the interfaces in 'InterfaceInfo'
  4762. // to their positions in 'AdapterOrder'. In other words,
  4763. // construct an array of interface indices in which location i
  4764. // contains the index of the interface which is in location i
  4765. // in 'AdapterOrder'.
  4766. //
  4767. AdapterOrderMap =
  4768. GrabMemory(FIELD_OFFSET(IP_ADAPTER_ORDER_MAP,
  4769. AdapterOrder[InterfaceInfo->NumAdapters]));
  4770. if (!AdapterOrderMap) { break; }
  4771. for (i = 0, Adapter = AdapterOrder;
  4772. *Adapter && i < (DWORD)InterfaceInfo->NumAdapters;
  4773. Adapter += lstrlenW(Adapter) + 1) {
  4774. //
  4775. // See if this is the NdiswanIp device, which corresponds to
  4776. // all Ndiswan interfaces. To implement adapter ordering
  4777. // for Ndiswan interfaces, we store their indices
  4778. // into successive locations in the adapter-order map
  4779. // based on the location of the string '\Device\NdiswanIp'
  4780. // in the adapter-order list.
  4781. //
  4782. if (lstrcmpiW(c_szDeviceNdiswanIp, Adapter) == 0) {
  4783. //
  4784. // This is the \Device\NdiswanIp entry, so list all Ndiswan
  4785. // interfaces in the adapter-order map now.
  4786. // Unfortunately, 'InterfaceInfo' does not tell us the type
  4787. // of each interface. In order to figure out which interfaces
  4788. // are Ndiswan interfaces, we enumerate all interfaces (again)
  4789. // and look for entries whose type is 'IF_TYPE_PPP'.
  4790. //
  4791. PMIB_IFTABLE IfTable;
  4792. dwErr = AllocateAndGetIfTableFromStack(&IfTable, FALSE,
  4793. GetProcessHeap(), 0,
  4794. FALSE);
  4795. if (dwErr == NO_ERROR) {
  4796. for (j = 0;
  4797. j < IfTable->dwNumEntries &&
  4798. i < (DWORD)InterfaceInfo->NumAdapters; j++) {
  4799. if (IfTable->table[j].dwType == IF_TYPE_PPP) {
  4800. AdapterOrderMap->AdapterOrder[i++] =
  4801. IfTable->table[j].dwIndex;
  4802. }
  4803. }
  4804. HeapFree(GetProcessHeap(), 0, IfTable);
  4805. }
  4806. continue;
  4807. }
  4808. //
  4809. // Now handle all other interfaces by matching the GUID
  4810. // in 'Adapter' to the GUID of an interface in 'InterfaceInfo'.
  4811. // We then store the index of the interface found, if any,
  4812. // in the next location in 'AdapterOrderMap'.
  4813. //
  4814. for (j = 0; j < (DWORD)InterfaceInfo->NumAdapters; j++) {
  4815. if (lstrcmpiW(InterfaceInfo->Adapter[j].Name +
  4816. sizeof(c_szDeviceTcpip) - 1,
  4817. Adapter + sizeof(c_szDevice) - 1) == 0) {
  4818. AdapterOrderMap->AdapterOrder[i++] =
  4819. InterfaceInfo->Adapter[j].Index;
  4820. break;
  4821. }
  4822. }
  4823. }
  4824. AdapterOrderMap->NumAdapters = i;
  4825. ReleaseMemory(InterfaceInfo);
  4826. ReleaseMemory(AdapterOrder);
  4827. return AdapterOrderMap;
  4828. } while(FALSE);
  4829. if (InterfaceInfo) { ReleaseMemory(InterfaceInfo); }
  4830. if (AdapterOrder) { ReleaseMemory(AdapterOrder); }
  4831. return NULL;
  4832. }