Leaked source code of windows server 2003
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.

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