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.

1727 lines
49 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. info.c
  5. Abstract:
  6. exports GetNetworkInformation routine
  7. --*/
  8. #include <precomp.h>
  9. //
  10. // seems that if WINS addresses not specified, NetBT reports 127.0.0.0 so if
  11. // this value is returned, we won't display them
  12. //
  13. #define LOCAL_WINS_ADDRESS 0x0000007f // 127.0.0.0
  14. #define New(Size) LocalAlloc( LPTR, Size)
  15. #define Delete(Ptr) if( NULL != Ptr ) LocalFree( Ptr )
  16. #define CheckBoolError(Internal) if( FALSE == fSuccess ) {\
  17. (*InternalError) = Internal; Error = GetLastError(); break; }
  18. #define CheckError(Internal) if( NO_ERROR != Error ) {\
  19. (*InternalError) = Internal; break; }
  20. VOID
  21. FreeIfInfo(
  22. IN OUT PINTERFACE_NETWORK_INFO IfInfo
  23. )
  24. {
  25. if( NULL == IfInfo ) return;
  26. Delete( IfInfo->FriendlyName );
  27. Delete( IfInfo->ConnectionName );
  28. Delete( IfInfo->DhcpClassId );
  29. Delete( IfInfo->IpAddress );
  30. Delete( IfInfo->Ipv6Address );
  31. Delete( IfInfo->IpMask );
  32. Delete( IfInfo->Router );
  33. Delete( IfInfo->WinsServer );
  34. Delete( IfInfo->DnsServer );
  35. Delete( IfInfo->Ipv6DnsServer );
  36. Delete( IfInfo );
  37. }
  38. VOID
  39. FreeNetworkInfo(
  40. IN OUT PNETWORK_INFO NetInfo
  41. )
  42. {
  43. DWORD i;
  44. if( NULL == NetInfo ) return;
  45. for( i = 0; i < NetInfo->nInterfaces ; i ++ ) {
  46. FreeIfInfo( NetInfo->IfInfo[i] );
  47. }
  48. Delete( NetInfo->SuffixSearchList );
  49. Delete( NetInfo );
  50. }
  51. DWORD
  52. MapIfType(
  53. IN OUT PINTERFACE_NETWORK_INFO IfInfo,
  54. IN ULONG IfType
  55. )
  56. {
  57. DWORD i;
  58. DWORD Map[][2] = {
  59. IF_TYPE_OTHER, IfTypeOther,
  60. IF_TYPE_ETHERNET_CSMACD, IfTypeEthernet,
  61. IF_TYPE_ISO88025_TOKENRING, IfTypeTokenring,
  62. IF_TYPE_FDDI, IfTypeFddi,
  63. IF_TYPE_PPP, IfTypePPP,
  64. IF_TYPE_SOFTWARE_LOOPBACK, IfTypeLoopback,
  65. IF_TYPE_SLIP, IfTypeSlip,
  66. IF_TYPE_TUNNEL, IfTypeTunnel,
  67. IF_TYPE_IEEE1394, IfType1394
  68. };
  69. for( i = 0; i < sizeof(Map)/sizeof(Map[0]); i ++ ) {
  70. if( Map[i][0] == IfType ) {
  71. IfInfo->IfType = Map[i][1];
  72. return NO_ERROR;
  73. }
  74. }
  75. return ERROR_NOT_FOUND;
  76. }
  77. LPWSTR
  78. GetProperty(
  79. IN HDEVINFO hdi,
  80. IN SP_DEVINFO_DATA *deid,
  81. IN ULONG Property
  82. )
  83. {
  84. BOOL fSuccess;
  85. ULONG Error, cbSize;
  86. LPWSTR RetVal;
  87. cbSize = 0;
  88. fSuccess = SetupDiGetDeviceRegistryPropertyW(
  89. hdi, deid, Property, NULL, NULL, 0, &cbSize
  90. );
  91. if( fSuccess ) {
  92. RetVal = LocalAlloc(LPTR, sizeof(WCHAR));
  93. if( NULL == RetVal ) return NULL;
  94. (*RetVal) = L'\0';
  95. return RetVal;
  96. }
  97. Error = GetLastError();
  98. if( ERROR_INSUFFICIENT_BUFFER != Error ) return NULL;
  99. RetVal = New( cbSize * sizeof(WCHAR) );
  100. if( NULL == RetVal ) return NULL ;
  101. fSuccess = SetupDiGetDeviceRegistryPropertyW(
  102. hdi, deid, Property, NULL, (PVOID)RetVal, cbSize, NULL
  103. );
  104. if( FALSE == fSuccess ) {
  105. Error = GetLastError();
  106. Delete( RetVal );
  107. SetLastError(Error);
  108. return NULL;
  109. }
  110. return RetVal;
  111. }
  112. LPWSTR
  113. GetDescriptionFromGuid(
  114. IN GUID *Guid
  115. )
  116. {
  117. WCHAR InstanceIdBuf[1000];
  118. ULONG BufSizeInWChars = sizeof(InstanceIdBuf)/sizeof(WCHAR);
  119. HRESULT hr;
  120. HDEVINFO hdi;
  121. SP_DEVINFO_DATA deid;
  122. BOOL fSuccess;
  123. ULONG Error;
  124. LPWSTR DescrName = NULL;
  125. deid.cbSize = sizeof(SP_DEVINFO_DATA);
  126. hr = HrPnpInstanceIdFromGuid(Guid, InstanceIdBuf, BufSizeInWChars);
  127. if( !SUCCEEDED(hr) ) {
  128. SetLastError( HRESULT_CODE(hr) );
  129. IPCFG_TRACE(IPCFG_TRACE_TCPIP, ("HrPnpInstanceIdFromGuid returns 0x%lx (%d)\n", hr, hr));
  130. return NULL;
  131. }
  132. hdi = SetupDiCreateDeviceInfoList(&GUID_DEVCLASS_NET, NULL);
  133. if( INVALID_HANDLE_VALUE != hdi ) {
  134. fSuccess = SetupDiOpenDeviceInfoW(hdi, InstanceIdBuf, NULL, 0, &deid);
  135. if( fSuccess ) {
  136. DescrName = GetProperty(hdi, &deid, SPDRP_FRIENDLYNAME);
  137. if( NULL == DescrName ) {
  138. Error = GetLastError();
  139. if( ERROR_SUCCESS != Error ) {
  140. DescrName = GetProperty( hdi, &deid, SPDRP_DEVICEDESC );
  141. if( NULL == DescrName ) {
  142. Error = GetLastError();
  143. } else {
  144. Error = ERROR_SUCCESS;
  145. }
  146. } else {
  147. //
  148. // Error already set.
  149. //
  150. }
  151. } else {
  152. //
  153. // We succeeded..
  154. //
  155. Error = ERROR_SUCCESS;
  156. }
  157. } else {
  158. Error = GetLastError();
  159. }
  160. SetupDiDestroyDeviceInfoList(hdi);
  161. } else {
  162. Error = GetLastError();
  163. }
  164. SetLastError(Error);
  165. return (ERROR_SUCCESS == Error)?DescrName:NULL;
  166. }
  167. LPWSTR
  168. GetDescription(
  169. IN GUID *Guid,
  170. IN LPWSTR GuidString
  171. )
  172. {
  173. LPWSTR RetVal = GetDescriptionFromGuid(Guid);
  174. WCHAR GuidStringBuf[500];
  175. GUID GuidStruct;
  176. ULONG Status;
  177. if( NULL != RetVal ) return RetVal;
  178. SetLastError( ERROR_CAN_NOT_COMPLETE );
  179. if( NULL == GuidString ) return NULL;
  180. if( wcslen(GuidString)*sizeof(WCHAR) >= sizeof(GuidStringBuf)) {
  181. return NULL;
  182. }
  183. if( GuidString[0] != L'{' ) return NULL;
  184. wcscpy(GuidStringBuf, &GuidString[1]);
  185. if( L'}' != GuidStringBuf[wcslen(GuidStringBuf)-1] ) {
  186. return NULL;
  187. }
  188. GuidStringBuf[wcslen(GuidStringBuf)-1] = L'\0';
  189. Status = UuidFromStringW(GuidStringBuf, &GuidStruct);
  190. if( RPC_S_OK != Status ) {
  191. SetLastError( Status );
  192. return NULL;
  193. }
  194. return GetDescriptionFromGuid(&GuidStruct);
  195. }
  196. VOID
  197. GetInterfaceGuidAndDeviceName(
  198. IN PMIB_IFROW IfRow,
  199. IN PIP_INTERFACE_INFO InterfaceInfo,
  200. IN PIP_INTERFACE_NAME_INFO IfNameInfo,
  201. IN ULONG IfNameCount,
  202. OUT GUID *IfGuid,
  203. OUT LPWSTR *IfDeviceName
  204. )
  205. {
  206. DWORD i;
  207. //
  208. // Search interface name info to get the interface guid for
  209. // this interface. Also, search the InterfaceInfo to get the
  210. // devicename for this interface.
  211. //
  212. ZeroMemory( IfGuid, sizeof(*IfGuid) );
  213. for( i = 0; i < IfNameCount ; i ++ ) {
  214. if( IfRow->dwIndex != IfNameInfo[i].Index ) continue;
  215. (*IfGuid) = IfNameInfo[i].InterfaceGuid;
  216. break;
  217. }
  218. (*IfDeviceName) = NULL;
  219. for( i = 0; i < (DWORD)InterfaceInfo->NumAdapters; i ++ ) {
  220. if( InterfaceInfo->Adapter[i].Index != IfRow->dwIndex ) continue;
  221. (*IfDeviceName) = InterfaceInfo->Adapter[i].Name + strlen(
  222. "\\Device\\Tcpip_" );
  223. break;
  224. }
  225. }
  226. DWORD
  227. MapFriendlyAndConnectionNames(
  228. IN OUT PINTERFACE_NETWORK_INFO IfInfo,
  229. IN PMIB_IFROW IfRow,
  230. IN GUID IfGuid,
  231. IN LPWSTR IfDeviceName
  232. )
  233. {
  234. DWORD Size, Error;
  235. WCHAR ConnName[500];
  236. //
  237. // Try to get friendly device name from IfGuid or DeviceName
  238. // or failing both just use the description provided by tcpip
  239. //
  240. IfInfo->FriendlyName = GetDescription( &IfGuid, IfDeviceName );
  241. IPCFG_TRACE(IPCFG_TRACE_TCPIP, ("GetDescription returns %p for %ws\n", IfInfo->FriendlyName, IfDeviceName));
  242. if( NULL == IfInfo->FriendlyName ) {
  243. Size = MultiByteToWideChar(
  244. CP_ACP, 0, (LPSTR)IfRow->bDescr, IfRow->dwDescrLen, NULL, 0 );
  245. if( Size == 0 ) return GetLastError();
  246. Size ++;
  247. IfInfo->FriendlyName = New( Size * sizeof(WCHAR) );
  248. if (IfInfo->FriendlyName == NULL) return GetLastError();
  249. Size = MultiByteToWideChar(
  250. CP_ACP, 0, (LPSTR)IfRow->bDescr, IfRow->dwDescrLen,
  251. IfInfo->FriendlyName, Size );
  252. if( 0 == Size ) return GetLastError();
  253. }
  254. IPCFG_TRACE(IPCFG_TRACE_TCPIP, ("\tFriendly Name: %ws\n", IfInfo->FriendlyName));
  255. //
  256. // Now get the connection name. First try with LAN, then RAS
  257. //
  258. Size = sizeof(ConnName)/sizeof(WCHAR);
  259. Error = HrLanConnectionNameFromGuidOrPath(
  260. NULL, IfDeviceName, ConnName, &Size );
  261. if( NO_ERROR != Error ) {
  262. //
  263. // NhGetInterfaceNameFromGuid uses a byte count rather than a
  264. // character count.
  265. //
  266. Size = sizeof(ConnName);
  267. IPCFG_TRACE(IPCFG_TRACE_TCPIP, ("HrLanConnectionNameFromGuidOrPath fails 0x%lx(%d)", Error, Error));
  268. Error = NhGetInterfaceNameFromGuid(
  269. &IfGuid, ConnName, &Size, FALSE, FALSE );
  270. if( NO_ERROR != Error ) {
  271. ConnName[0] = L'\0';
  272. IPCFG_TRACE(IPCFG_TRACE_TCPIP, (" NhGetInterfaceNameFromGuid fails 0x%lx(%d)", Error, Error));
  273. //return Error;
  274. }
  275. }
  276. IPCFG_TRACE(IPCFG_TRACE_TCPIP, ("\tConnection Name: %ws\n", ConnName));
  277. IfInfo->ConnectionName = New( sizeof(WCHAR)*(1+wcslen(ConnName)));
  278. if( NULL == IfInfo->ConnectionName ) return GetLastError();
  279. wcscpy(IfInfo->ConnectionName, ConnName );
  280. return NO_ERROR;
  281. }
  282. DWORD
  283. GetMediaStatus(
  284. IN LPWSTR IfDeviceName,
  285. OUT BOOL *fDisconnected
  286. )
  287. {
  288. WCHAR NdisDeviceString[512];
  289. UNICODE_STRING NdisDevice;
  290. NIC_STATISTICS NdisStats;
  291. wcscpy((LPWSTR)NdisDeviceString, (LPWSTR)L"\\Device\\" );
  292. wcscat((LPWSTR)NdisDeviceString, IfDeviceName );
  293. ZeroMemory(&NdisStats, sizeof(NdisStats));
  294. NdisStats.Size = sizeof(NdisStats);
  295. RtlInitUnicodeString(&NdisDevice, (LPWSTR)NdisDeviceString);
  296. if( FALSE == NdisQueryStatistics(&NdisDevice, &NdisStats) ) {
  297. ULONG Error;
  298. //
  299. // Could not get statistics.. use default answer.
  300. //
  301. Error = GetLastError();
  302. IPCFG_TRACE(IPCFG_TRACE_TCPIP, ("NdisQueryStatistics: %d\n", Error));
  303. if( ERROR_NOT_READY == Error ) {
  304. *fDisconnected = TRUE;
  305. return NO_ERROR;
  306. }
  307. return Error;
  308. }
  309. IPCFG_TRACE(IPCFG_TRACE_TCPIP, ("MediaState: %d\n", NdisStats.MediaState));
  310. if( NdisStats.MediaState == MEDIA_STATE_DISCONNECTED ) {
  311. *fDisconnected = TRUE;
  312. } else {
  313. *fDisconnected = FALSE;
  314. }
  315. return NO_ERROR;
  316. }
  317. BOOL
  318. IsMediaSenseDisabled(
  319. HKEY RegKey
  320. )
  321. {
  322. LPTSTR regValueName = (LPTSTR)(TEXT ("DisableDHCPMediaSense") );
  323. DWORD regValueData;
  324. DWORD regValueDataType;
  325. DWORD regValueDataLen = sizeof(DWORD);
  326. DWORD Error;
  327. Error = RegQueryValueEx(
  328. RegKey,
  329. regValueName,
  330. NULL,
  331. &regValueDataType,
  332. (LPBYTE)&regValueData,
  333. &regValueDataLen);
  334. return (Error == NO_ERROR) &&
  335. (regValueDataType == REG_DWORD) &&
  336. (regValueData != 0);
  337. }
  338. DWORD
  339. OpenRegKey(
  340. IN LPCWSTR Device,
  341. IN DWORD KeyType,
  342. IN DWORD AccessType,
  343. OUT HKEY *phKey
  344. )
  345. {
  346. DWORD Access;
  347. WCHAR KeyLoc[256];
  348. LPTSTR TcpipParmLoc = (LPTSTR)(TEXT( "SYSTEM\\CurrentControlSet\\Services" )
  349. TEXT( "\\Tcpip\\Parameters" ) );
  350. LPTSTR TcpipLoc = (LPTSTR)(TEXT( "SYSTEM\\CurrentControlSet\\Services" )
  351. TEXT( "\\Tcpip\\Parameters\\Interfaces\\") );
  352. LPTSTR NbtLoc = (LPTSTR)(TEXT("SYSTEM\\CurrentControlSet\\Services")
  353. TEXT("\\Netbt\\Parameters\\Interfaces\\Tcpip_"));
  354. switch (KeyType)
  355. {
  356. case OpenTcpipParmKey:
  357. wcscpy(KeyLoc, TcpipParmLoc);
  358. break;
  359. case OpenTcpipKey:
  360. wcscpy(KeyLoc, TcpipLoc);
  361. wcscat(KeyLoc, Device);
  362. break;
  363. case OpenNbtKey:
  364. wcscpy(KeyLoc, NbtLoc);
  365. wcscat(KeyLoc, Device);
  366. break;
  367. }
  368. Access = KEY_READ;
  369. if( AccessType & OpenKeyForWrite ) Access |= KEY_WRITE;
  370. return RegOpenKeyEx(
  371. HKEY_LOCAL_MACHINE, KeyLoc, 0, Access, phKey );
  372. }
  373. VOID
  374. SecondsToAbsolute(
  375. OUT FILETIME *SysTime,
  376. IN LONGLONG SecondsDifference
  377. )
  378. {
  379. LONGLONG Diff = SecondsDifference;
  380. Diff *= 10000; Diff *= 1000;
  381. GetSystemTimeAsFileTime( SysTime );
  382. (*((LONGLONG UNALIGNED64 *)SysTime)) -= Diff;
  383. }
  384. DWORD
  385. GetDhcpValues(
  386. IN PNETWORK_INFO NetInfo,
  387. IN OUT PINTERFACE_NETWORK_INFO IfInfo,
  388. IN HKEY hKey
  389. )
  390. {
  391. WCHAR ClassId[200];
  392. LPSTR DhcpServer;
  393. DWORD Error, Value, Size, Type;
  394. time_t CurrentTime, Obtained, Expires;
  395. //
  396. // First check if dhcp is enabled
  397. //
  398. do {
  399. Size = sizeof(Value);
  400. Error = RegQueryValueEx(
  401. hKey, (LPTSTR)TEXT("EnableDHCP"), NULL, &Type,
  402. (LPBYTE)&Value, &Size );
  403. if( NO_ERROR != Error ) return Error;
  404. if( Type != REG_DWORD ) return ERROR_INVALID_DATA;
  405. IfInfo->EnableDhcp = (Value != 0 );
  406. } while ( 0 );
  407. //
  408. // Now check for class id
  409. //
  410. do {
  411. Size = sizeof(ClassId);
  412. Error = RegQueryValueExW(
  413. hKey, (LPWSTR)L"DhcpClassId", NULL, &Type, (LPBYTE)ClassId,
  414. &Size );
  415. if( ERROR_FILE_NOT_FOUND == Error ) {
  416. Error = NO_ERROR;
  417. Size = 0;
  418. }
  419. if( NO_ERROR != Error ) return Error;
  420. if( Size == 0 ) break;
  421. if( Type != REG_SZ ) return ERROR_INVALID_DATA;
  422. Size = sizeof(WCHAR)*(1+wcslen(ClassId));
  423. IfInfo->DhcpClassId = New( Size );
  424. if( NULL == IfInfo->DhcpClassId ) return GetLastError();
  425. wcscpy(IfInfo->DhcpClassId, ClassId );
  426. } while( 0 );
  427. //
  428. // Now check if autoconfiguration is enabled
  429. //
  430. if( IfInfo->EnableDhcp ) do {
  431. Size = sizeof(Value);
  432. Error = RegQueryValueEx(
  433. hKey, (LPTSTR)TEXT("IPAutoconfigurationEnabled"),
  434. NULL, &Type, (LPBYTE)&Value, &Size );
  435. if( ERROR_FILE_NOT_FOUND == Error ) {
  436. IfInfo->EnableAutoconfig = NetInfo->GlobalEnableAutoconfig;
  437. } else if( NO_ERROR != Error ) return Error;
  438. else if( REG_DWORD != Type ) return ERROR_INVALID_DATA;
  439. else IfInfo->EnableAutoconfig = (Value != 0 );
  440. } while ( 0 );
  441. //
  442. // Get Dhcp server value
  443. //
  444. if( IfInfo->EnableDhcp ) do {
  445. Size = sizeof(ClassId);
  446. DhcpServer = (LPSTR)ClassId;
  447. Error = RegQueryValueExA(
  448. hKey, "DhcpServer", NULL, &Type,
  449. (LPBYTE)DhcpServer, &Size );
  450. if( ERROR_FILE_NOT_FOUND == Error ) break;
  451. if( NO_ERROR != Error ) return Error;
  452. if( REG_SZ != Type ) return ERROR_INVALID_DATA;
  453. IfInfo->DhcpServer = inet_addr(DhcpServer);
  454. } while( 0 );
  455. //
  456. // Now get lease expired and obtained times
  457. //
  458. CurrentTime = time(NULL);
  459. if( IfInfo->EnableDhcp ) do {
  460. Size = sizeof(Value);
  461. Error = RegQueryValueEx(
  462. hKey, (LPTSTR)TEXT("LeaseObtainedTime"),
  463. NULL, &Type, (LPBYTE)&Value, &Size );
  464. if( ERROR_FILE_NOT_FOUND == Error ) break;
  465. if( NO_ERROR != Error ) return Error;
  466. if( REG_DWORD != Type ) return ERROR_INVALID_DATA;
  467. Obtained = (time_t)Value;
  468. SecondsToAbsolute(
  469. (FILETIME *)(&IfInfo->LeaseObtainedTime),
  470. ((LONGLONG)CurrentTime) - ((LONGLONG)Obtained) );
  471. } while ( 0 );
  472. if( IfInfo->EnableDhcp ) do {
  473. Size = sizeof(Value);
  474. Error = RegQueryValueEx(
  475. hKey, (LPTSTR)TEXT("LeaseTerminatesTime"),
  476. NULL, &Type, (LPBYTE)&Value, &Size );
  477. if( ERROR_FILE_NOT_FOUND == Error ) break;
  478. if( NO_ERROR != Error ) return Error;
  479. if( REG_DWORD != Type ) return ERROR_INVALID_DATA;
  480. Expires = (time_t)Value;
  481. SecondsToAbsolute(
  482. (FILETIME *)(&IfInfo->LeaseExpiresTime),
  483. ((LONGLONG)CurrentTime) - ((LONGLONG)Expires) );
  484. } while ( 0 );
  485. return NO_ERROR;
  486. }
  487. DWORD
  488. GetDnsValues(
  489. IN OUT PINTERFACE_NETWORK_INFO IfInfo,
  490. IN HKEY hKey
  491. )
  492. {
  493. CHAR *Servers = NULL, *Str;
  494. DWORD Error, BufferSize, Size, Type, i, Count, *ThisAddr;
  495. //
  496. // First get DnsSuffix for the interface
  497. //
  498. Size = sizeof(IfInfo->DnsSuffix)/sizeof(WCHAR);
  499. Error = RegQueryValueExW(
  500. hKey, (LPWSTR)L"Domain", NULL, &Type,
  501. (LPBYTE)IfInfo->DnsSuffix, &Size );
  502. if( NO_ERROR != Error ) {
  503. if( ERROR_FILE_NOT_FOUND != Error ) return Error;
  504. Size = 0;
  505. Type = REG_SZ;
  506. }
  507. if( REG_SZ != Type ) return ERROR_INVALID_DATA;
  508. if( 0 == Size || 0 == wcslen(IfInfo->DnsSuffix) ) {
  509. Size = sizeof(IfInfo->DnsSuffix)/sizeof(WCHAR);
  510. Error = RegQueryValueExW(
  511. hKey, (LPWSTR)L"DhcpDomain", NULL, &Type,
  512. (LPBYTE)IfInfo->DnsSuffix, &Size );
  513. if( NO_ERROR != Error ) {
  514. if( ERROR_FILE_NOT_FOUND != Error ) return Error;
  515. Size = 0;
  516. IfInfo->DnsSuffix[0] = L'\0';
  517. }
  518. }
  519. //
  520. // Now attempt to read the DnsServers list
  521. //
  522. BufferSize = 800;
  523. do {
  524. Servers = New( BufferSize );
  525. if( NULL == Servers) return GetLastError();
  526. ZeroMemory(Servers, BufferSize);
  527. Size = BufferSize;
  528. Error = RegQueryValueExA(
  529. hKey, (LPSTR)"NameServer", NULL, &Type, (LPBYTE)Servers,
  530. &Size );
  531. if( NO_ERROR == Error ) {
  532. break;
  533. }
  534. Delete(Servers);
  535. Servers = NULL;
  536. if( ERROR_FILE_NOT_FOUND == Error ) {
  537. Size = 0;
  538. Type = REG_SZ;
  539. break;
  540. }
  541. if (Error != ERROR_MORE_DATA) {
  542. return Error;
  543. }
  544. BufferSize *= 2;
  545. } while(1);
  546. if( REG_SZ != Type ) return ERROR_INVALID_DATA;
  547. if( 0 == Size || NULL == Servers || 0 == strlen(Servers) ) {
  548. if (Servers) Delete(Servers);
  549. BufferSize = 800;
  550. do {
  551. Servers = New( BufferSize );
  552. if( NULL == Servers) return GetLastError();
  553. ZeroMemory(Servers, BufferSize);
  554. Size = BufferSize;
  555. Error = RegQueryValueExA(
  556. hKey, (LPSTR)"DhcpNameServer", NULL, &Type,
  557. (LPBYTE)Servers, &Size );
  558. if( NO_ERROR == Error ) {
  559. break;
  560. }
  561. Delete(Servers);
  562. Servers = NULL;
  563. if( ERROR_FILE_NOT_FOUND == Error ) {
  564. Size = 0;
  565. Type = REG_SZ;
  566. break;
  567. }
  568. if (Error != ERROR_MORE_DATA) {
  569. return Error;
  570. }
  571. BufferSize *= 2;
  572. } while(1);
  573. }
  574. //
  575. // If there are any DNS Servers, convert them to IPaddr
  576. //
  577. if( 0 != Size && NULL != Servers && strlen(Servers) ) {
  578. for( i = 0; i < Size; i ++ ) {
  579. if( Servers[i] == ' ' || Servers[i] == ','
  580. || Servers[i] == ';' ) {
  581. Servers[i] = '\0';
  582. }
  583. }
  584. Servers[Size] = '\0';
  585. Count = 0; Str = (LPSTR)Servers;
  586. while( strlen(Str) ) {
  587. Count ++;
  588. Str += strlen(Str); Str ++;
  589. }
  590. ThisAddr = New( sizeof(IPV4_ADDRESS) * Count );
  591. if( NULL == ThisAddr ) return GetLastError();
  592. IfInfo->DnsServer = ThisAddr;
  593. for (i = 0, Str = (LPSTR)Servers;
  594. *Str != '\0';
  595. Str += strlen(Str) + 1)
  596. {
  597. IfInfo->DnsServer[i] = inet_addr( Str );
  598. if (IfInfo->DnsServer[i] != 0)
  599. i++;
  600. }
  601. IfInfo->nDnsServers = i;
  602. }
  603. if (Servers) {
  604. Delete (Servers);
  605. }
  606. return NO_ERROR;
  607. }
  608. DWORD
  609. GetWinsValues(
  610. IN OUT PINTERFACE_NETWORK_INFO IfInfo,
  611. IN LPCWSTR DeviceName,
  612. IN OUT ULONG *NodeType
  613. )
  614. {
  615. WCHAR NbtDevice[MAX_PATH];
  616. UNICODE_STRING NbtDeviceString;
  617. HANDLE h;
  618. OBJECT_ATTRIBUTES objAttr;
  619. IO_STATUS_BLOCK iosb;
  620. NTSTATUS status;
  621. tWINS_NODE_INFO NodeInfo;
  622. DWORD Count;
  623. INT i;
  624. wcscpy(NbtDevice, (LPWSTR)L"\\Device\\NetBT_Tcpip_");
  625. wcscat(NbtDevice, DeviceName);
  626. RtlInitUnicodeString( &NbtDeviceString, (LPWSTR)NbtDevice );
  627. InitializeObjectAttributes(
  628. &objAttr,
  629. &NbtDeviceString,
  630. OBJ_CASE_INSENSITIVE,
  631. (HANDLE)NULL,
  632. (PSECURITY_DESCRIPTOR)NULL
  633. );
  634. status = NtCreateFile(
  635. &h, SYNCHRONIZE | GENERIC_EXECUTE, &objAttr, &iosb, NULL,
  636. FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE,
  637. FILE_OPEN_IF, 0, NULL, 0 );
  638. if (!NT_SUCCESS(status)) {
  639. DWORD w32error = RtlNtStatusToDosError( status );
  640. IfInfo->EnableNbtOverTcpip = FALSE;
  641. (*NodeType) = NodeTypeUnknown;
  642. return w32error == ERROR_FILE_NOT_FOUND ? NO_ERROR : w32error;
  643. }
  644. status = NtDeviceIoControlFile(
  645. h, NULL, NULL, NULL, &iosb, IOCTL_NETBT_GET_WINS_ADDR,
  646. NULL, 0, (PVOID)&NodeInfo, sizeof(NodeInfo) );
  647. if (status == STATUS_PENDING) {
  648. status = NtWaitForSingleObject(h, TRUE, NULL);
  649. if (NT_SUCCESS(status)) {
  650. status = iosb.Status;
  651. }
  652. }
  653. NtClose(h);
  654. if (!NT_SUCCESS(status)) {
  655. return RtlNtStatusToDosError( status );
  656. }
  657. //
  658. // for some reason, NetBT returns the addresses in low-byte order. We have
  659. // to swap them
  660. //
  661. Count = 0;
  662. for( i = 0; i < 2+MAX_NUM_OTHER_NAME_SERVERS; i ++ ) {
  663. NodeInfo.AllNameServers[i] = htonl(NodeInfo.AllNameServers[i]);
  664. if( LOCAL_WINS_ADDRESS == NodeInfo.AllNameServers[i] ||
  665. INADDR_ANY == NodeInfo.AllNameServers[i] ||
  666. INADDR_BROADCAST == NodeInfo.AllNameServers[i] ) {
  667. break;
  668. }
  669. Count ++;
  670. }
  671. for ( i = IfInfo->nIpAddresses-1; i >= 0; i--)
  672. if (IfInfo->IpAddress[i] != 0)
  673. break;
  674. if (Count > (DWORD)(NodeInfo.NumOtherServers + 2)) {
  675. Count = (DWORD)(NodeInfo.NumOtherServers + 2);
  676. }
  677. if( i != -1 && Count != 0 ) {
  678. IfInfo->WinsServer = New( sizeof(IPV4_ADDRESS)*Count );
  679. if( NULL == IfInfo->WinsServer ) return GetLastError();
  680. IfInfo->nWinsServers = Count;
  681. for( i = 0; (DWORD)i < Count; i ++ ) {
  682. IfInfo->WinsServer[i] = NodeInfo.AllNameServers[i];
  683. }
  684. }
  685. IfInfo->EnableNbtOverTcpip = NodeInfo.NetbiosEnabled;
  686. #define NODE_TYPE_BROADCAST 1
  687. #define NODE_TYPE_PEER_PEER 2
  688. #define NODE_TYPE_MIXED 4
  689. #define NODE_TYPE_HYBRID 8
  690. switch( NodeInfo.NodeType ) {
  691. case NODE_TYPE_BROADCAST : (*NodeType) = NodeTypeBroadcast; break;
  692. case NODE_TYPE_PEER_PEER : (*NodeType) = NodeTypePeerPeer; break;
  693. case NODE_TYPE_MIXED : (*NodeType) = NodeTypeMixed; break;
  694. case NODE_TYPE_HYBRID : (*NodeType) = NodeTypeHybrid ; break;
  695. default: (*NodeType) = NodeTypeUnknown; break;
  696. }
  697. return NO_ERROR;
  698. }
  699. DWORD
  700. GetAddressValues(
  701. IN OUT PINTERFACE_NETWORK_INFO IfInfo,
  702. IN PMIB_IPADDRTABLE AddrTable,
  703. IN ULONG IfIndex
  704. )
  705. {
  706. DWORD i, Count;
  707. if( NULL == AddrTable ) return ERROR_NOT_FOUND;
  708. Count = 0;
  709. for( i = 0; i < AddrTable->dwNumEntries ; i ++ ) {
  710. if( AddrTable->table[i].dwIndex == IfIndex ) {
  711. Count ++;
  712. }
  713. }
  714. if( 0 == Count ) return NO_ERROR;
  715. //
  716. // Allocate space for this
  717. //
  718. IfInfo->IpAddress = New( sizeof(IPV4_ADDRESS)*Count );
  719. if( NULL == IfInfo->IpAddress ) return GetLastError();
  720. IfInfo->IpMask = New( sizeof(IPV4_ADDRESS)*Count );
  721. if( NULL == IfInfo->IpMask ) return GetLastError();
  722. IfInfo->nIpAddresses = IfInfo->nIpMasks = Count;
  723. //
  724. // First add the primary addresses
  725. //
  726. Count = 0;
  727. for( i = 0; i < AddrTable->dwNumEntries; i ++ ) {
  728. if( AddrTable->table[i].dwIndex != IfIndex ) continue;
  729. if( !(AddrTable->table[i].wType & MIB_IPADDR_PRIMARY)) continue;
  730. IfInfo->IpAddress[Count] = AddrTable->table[i].dwAddr;
  731. IfInfo->IpMask[Count] = AddrTable->table[i].dwMask;
  732. Count ++;
  733. }
  734. //
  735. // Now add just the non-primary addresses
  736. //
  737. for( i = 0; i < AddrTable->dwNumEntries; i ++ ) {
  738. if( AddrTable->table[i].dwIndex != IfIndex ) continue;
  739. if(AddrTable->table[i].wType & MIB_IPADDR_PRIMARY) continue;
  740. IfInfo->IpAddress[Count] = AddrTable->table[i].dwAddr;
  741. IfInfo->IpMask[Count] = AddrTable->table[i].dwMask;
  742. Count ++;
  743. }
  744. return NO_ERROR;
  745. }
  746. DWORD
  747. GetRouteValues(
  748. IN OUT PINTERFACE_NETWORK_INFO IfInfo,
  749. IN PMIB_IPFORWARDTABLE RouteTable,
  750. IN ULONG IfIndex
  751. )
  752. {
  753. DWORD i, Count;
  754. if( NULL == RouteTable ) return ERROR_NOT_FOUND;
  755. Count = 0;
  756. for( i = 0; i < RouteTable->dwNumEntries; i ++ ) {
  757. if( RouteTable->table[i].dwForwardIfIndex == IfIndex &&
  758. INADDR_ANY == RouteTable->table[i].dwForwardDest &&
  759. MIB_IPROUTE_TYPE_INVALID !=
  760. RouteTable->table[i].dwForwardType ) {
  761. Count ++;
  762. }
  763. }
  764. if( 0 == Count ) return NO_ERROR;
  765. IfInfo->Router = New( sizeof(IPV4_ADDRESS)*Count);
  766. if( NULL == IfInfo->Router ) return GetLastError();
  767. IfInfo->nRouters = Count;
  768. Count = 0;
  769. for( i = 0; i < RouteTable->dwNumEntries; i ++ ) {
  770. if( RouteTable->table[i].dwForwardIfIndex == IfIndex &&
  771. INADDR_ANY == RouteTable->table[i].dwForwardDest &&
  772. MIB_IPROUTE_TYPE_INVALID !=
  773. RouteTable->table[i].dwForwardType ) {
  774. IfInfo->Router[Count] = RouteTable->table[i].dwForwardNextHop;
  775. Count ++;
  776. }
  777. }
  778. return NO_ERROR;
  779. }
  780. VOID
  781. IncrementCount(
  782. IN IPV6_INFO_ROUTE_TABLE *RTE,
  783. IN PVOID Arg1,
  784. IN OUT PVOID Count
  785. )
  786. {
  787. PIP_ADAPTER_ADDRESSES If = (PIP_ADAPTER_ADDRESSES)Arg1;
  788. if ((RTE->This.PrefixLength == 0) &&
  789. (RTE->This.Neighbor.IF.Index == If->Ipv6IfIndex)) {
  790. (*(ULONG *)Count)++;
  791. }
  792. }
  793. VOID
  794. AddRouter(
  795. IN IPV6_INFO_ROUTE_TABLE *RTE,
  796. IN PVOID Arg1,
  797. IN OUT PVOID Arg2
  798. )
  799. {
  800. PIP_ADAPTER_ADDRESSES If = (PIP_ADAPTER_ADDRESSES)Arg1;
  801. PINTERFACE_NETWORK_INFO pIfInfo = (PINTERFACE_NETWORK_INFO)Arg2;
  802. ULONG Index;
  803. LPSOCKADDR_IN6 Addr;
  804. if (RTE->This.PrefixLength != 0) {
  805. return;
  806. }
  807. if (RTE->This.Neighbor.IF.Index != If->Ipv6IfIndex) {
  808. return;
  809. }
  810. //
  811. // We now have a default router to add to the list.
  812. //
  813. Index = pIfInfo->nIpv6Routers++;
  814. Addr = &pIfInfo->Ipv6Router[Index];
  815. Addr->sin6_family = AF_INET6;
  816. Addr->sin6_addr = RTE->This.Neighbor.Address;
  817. Addr->sin6_port = 0;
  818. if (IN6_IS_ADDR_LINKLOCAL(&Addr->sin6_addr)) {
  819. Addr->sin6_scope_id = If->ZoneIndices[ScopeLevelLink];
  820. } else if (IN6_IS_ADDR_SITELOCAL(&Addr->sin6_addr)) {
  821. Addr->sin6_scope_id = If->ZoneIndices[ScopeLevelSite];
  822. } else {
  823. Addr->sin6_scope_id = 0;
  824. }
  825. }
  826. ULONG
  827. ForEachRoute(
  828. IN VOID (*Func)(IPV6_INFO_ROUTE_TABLE *, PVOID, PVOID),
  829. IN PVOID Arg1,
  830. IN OUT PVOID Arg2
  831. )
  832. {
  833. IPV6_QUERY_ROUTE_TABLE Query, NextQuery;
  834. IPV6_INFO_ROUTE_TABLE RTE;
  835. ULONG BytesReturned;
  836. static HANDLE Ipv6Handle = INVALID_HANDLE_VALUE;
  837. if (Ipv6Handle == INVALID_HANDLE_VALUE) {
  838. //
  839. // Open a handle to the IPv6 device on our first invocation.
  840. // Keep it open until the process terminates, since we'll
  841. // terminate once we've generated the output.
  842. //
  843. Ipv6Handle = CreateFileW(WIN_IPV6_DEVICE_NAME,
  844. 0,
  845. FILE_SHARE_READ | FILE_SHARE_WRITE,
  846. NULL, // security attributes
  847. OPEN_EXISTING,
  848. 0, // flags & attributes
  849. NULL); // template file
  850. }
  851. NextQuery.Neighbor.IF.Index = 0;
  852. for (;;) {
  853. Query = NextQuery;
  854. if (!DeviceIoControl(Ipv6Handle, IOCTL_IPV6_QUERY_ROUTE_TABLE,
  855. &Query, sizeof Query,
  856. &RTE, sizeof RTE, &BytesReturned,
  857. NULL)) {
  858. return GetLastError();
  859. }
  860. NextQuery = RTE.Next;
  861. if (Query.Neighbor.IF.Index != 0) {
  862. RTE.This = Query;
  863. (*Func)(&RTE, Arg1, Arg2);
  864. }
  865. if (NextQuery.Neighbor.IF.Index == 0)
  866. break;
  867. }
  868. return NO_ERROR;
  869. }
  870. VOID
  871. AddIpv6PerInterfaceInfo(
  872. IN DWORD IfIndex,
  873. IN PINTERFACE_NETWORK_INFO pIfInfo,
  874. IN PIP_ADAPTER_ADDRESSES IfList
  875. )
  876. {
  877. PIP_ADAPTER_ADDRESSES If;
  878. PIP_ADAPTER_UNICAST_ADDRESS Addr;
  879. PIP_ADAPTER_DNS_SERVER_ADDRESS Dns;
  880. ULONG Count, BytesReturned;
  881. LPSOCKADDR_IN6 SockAddr;
  882. IPV6_QUERY_ROUTE_TABLE Query, NextQuery;
  883. IPV6_INFO_ROUTE_TABLE RTE;
  884. //
  885. // Find matching entry in the IPv6 interface list.
  886. //
  887. for (If = IfList; If; If = If->Next) {
  888. if (IfIndex == If->IfIndex) {
  889. break;
  890. }
  891. }
  892. if ((If == NULL) || (If->Ipv6IfIndex == 0)) {
  893. return;
  894. }
  895. //
  896. // Append IPv6 unicast addresses.
  897. //
  898. Count = 0;
  899. for (Addr = If->FirstUnicastAddress; Addr; Addr = Addr->Next) {
  900. if ((Addr->Address.lpSockaddr->sa_family == AF_INET6) &&
  901. (Addr->DadState >= IpDadStateDeprecated)) {
  902. Count++;
  903. }
  904. }
  905. pIfInfo->Ipv6Address = New(Count * sizeof(SOCKADDR_IN6));
  906. if (pIfInfo->Ipv6Address != NULL) {
  907. Count = 0;
  908. for (Addr = If->FirstUnicastAddress; Addr; Addr = Addr->Next) {
  909. if ((Addr->Address.lpSockaddr->sa_family == AF_INET6) &&
  910. (Addr->DadState >= IpDadStateDeprecated)) {
  911. CopyMemory(&pIfInfo->Ipv6Address[Count++],
  912. Addr->Address.lpSockaddr,
  913. sizeof(SOCKADDR_IN6));
  914. }
  915. }
  916. pIfInfo->nIpv6Addresses = Count;
  917. } else {
  918. pIfInfo->nIpv6Addresses = 0;
  919. }
  920. //
  921. // Append IPv6 DNS server addresses.
  922. //
  923. Count = 0;
  924. for (Dns = If->FirstDnsServerAddress; Dns; Dns = Dns->Next) {
  925. if (Dns->Address.lpSockaddr->sa_family == AF_INET6) {
  926. Count++;
  927. }
  928. }
  929. pIfInfo->Ipv6DnsServer = New(Count * sizeof(SOCKADDR_IN6));
  930. if (pIfInfo->Ipv6DnsServer != NULL) {
  931. Count = 0;
  932. for (Dns = If->FirstDnsServerAddress; Dns; Dns = Dns->Next) {
  933. if (Dns->Address.lpSockaddr->sa_family == AF_INET6) {
  934. CopyMemory(&pIfInfo->Ipv6DnsServer[Count++],
  935. Dns->Address.lpSockaddr,
  936. sizeof(SOCKADDR_IN6));
  937. }
  938. }
  939. pIfInfo->nIpv6DnsServers = Count;
  940. } else {
  941. pIfInfo->nIpv6DnsServers = 0;
  942. }
  943. //
  944. // Append IPv6 default router addresses.
  945. //
  946. Count = 0;
  947. ForEachRoute(IncrementCount, If, &Count);
  948. pIfInfo->nIpv6Routers = 0;
  949. pIfInfo->Ipv6Router = New(Count * sizeof(SOCKADDR_IN6));
  950. if (pIfInfo->Ipv6Router != NULL) {
  951. ForEachRoute(AddRouter, If, pIfInfo);
  952. }
  953. }
  954. DWORD
  955. GetPerInterfaceInfo(
  956. IN OUT PNETWORK_INFO NetInfo,
  957. OUT PINTERFACE_NETWORK_INFO *pIfInfo,
  958. IN PMIB_IFROW IfRow,
  959. IN PIP_INTERFACE_INFO InterfaceInfo,
  960. IN PIP_INTERFACE_NAME_INFO IfNameInfo,
  961. IN ULONG IfNameCount,
  962. IN PMIB_IPADDRTABLE AddrTable,
  963. IN PMIB_IPFORWARDTABLE RouteTable,
  964. IN PIP_ADAPTER_ADDRESSES IfList,
  965. IN OUT DWORD *InternalError
  966. )
  967. {
  968. DWORD Error, NodeType;
  969. PINTERFACE_NETWORK_INFO IfInfo = New( sizeof(*IfInfo) );
  970. GUID IfGuid;
  971. LPWSTR IfDeviceName;
  972. HKEY TcpipKey = NULL;
  973. HKEY TcpipParmKey = NULL;
  974. if( NULL == IfInfo ) return GetLastError();
  975. (*pIfInfo) = IfInfo;
  976. ZeroMemory( &IfGuid, sizeof(IfGuid) );
  977. IfDeviceName = NULL;
  978. GetInterfaceGuidAndDeviceName(
  979. IfRow, InterfaceInfo, IfNameInfo, IfNameCount,
  980. &IfGuid, &IfDeviceName );
  981. if( NULL == IfDeviceName ) {
  982. (*InternalError) = InterfaceUnknownTcpipDevice;
  983. return ERROR_NOT_FOUND;
  984. }
  985. IPCFG_TRACE(IPCFG_TRACE_TCPIP, ("\tDeviceName: %ws\n", IfDeviceName));
  986. wcscpy(IfInfo->DeviceGuidName, IfDeviceName );
  987. Error = OpenRegKey(
  988. IfDeviceName, OpenTcpipKey, OpenKeyForRead, &TcpipKey );
  989. if (Error == NO_ERROR)
  990. Error = OpenRegKey(
  991. IfDeviceName, OpenTcpipParmKey, OpenKeyForRead, &TcpipParmKey );
  992. if( NO_ERROR != Error ) {
  993. (*InternalError) = InterfaceOpenTcpipKeyReadFailure;
  994. }
  995. while (Error == NO_ERROR)
  996. {
  997. Error = MapIfType( IfInfo, IfRow->dwType);
  998. CheckError( InterfaceUnknownType );
  999. IfInfo->PhysicalNameLength = IfRow->dwPhysAddrLen;
  1000. CopyMemory(
  1001. IfInfo->PhysicalName,IfRow->bPhysAddr,
  1002. IfRow->dwPhysAddrLen );
  1003. Error = MapFriendlyAndConnectionNames(
  1004. IfInfo, IfRow, IfGuid, IfDeviceName );
  1005. CheckError( InterfaceUnknownFriendlyName );
  1006. if( IfRow->dwType == IF_TYPE_PPP ||
  1007. IfRow->dwType == IF_TYPE_TUNNEL ||
  1008. IsMediaSenseDisabled(TcpipParmKey)) {
  1009. IfInfo->MediaDisconnected = FALSE;
  1010. } else {
  1011. Error = GetMediaStatus(
  1012. IfDeviceName, &IfInfo->MediaDisconnected );
  1013. CheckError( InterfaceUnknownMediaStatus );
  1014. }
  1015. Error = GetDhcpValues( NetInfo, IfInfo, TcpipKey );
  1016. CheckError( InterfaceDhcpValuesFailure );
  1017. Error = GetDnsValues( IfInfo, TcpipKey );
  1018. CheckError( InterfaceDnsValuesFailure );
  1019. Error = GetAddressValues(
  1020. IfInfo, AddrTable, IfRow->dwIndex );
  1021. CheckError( InterfaceAddressValuesFailure );
  1022. Error = GetRouteValues(
  1023. IfInfo, RouteTable, IfRow->dwIndex );
  1024. CheckError( InterfaceRouteValuesFailure );
  1025. Error = GetWinsValues( IfInfo, IfDeviceName, &NodeType );
  1026. CheckError( InterfaceWinsValuesFailure );
  1027. //
  1028. // Now set the node type as well
  1029. //
  1030. NetInfo->NodeType = NodeType;
  1031. //
  1032. // Now write out if autoconfig is active. The way this
  1033. // works is to check if dhcp is enabled and dhcpserver
  1034. // address is zero or all ones
  1035. //
  1036. if( IfInfo->EnableDhcp && IfInfo->EnableAutoconfig
  1037. && IfInfo->nIpAddresses
  1038. && IfInfo->IpAddress[0] != INADDR_ANY
  1039. && ( IfInfo->DhcpServer == INADDR_BROADCAST ||
  1040. IfInfo->DhcpServer == INADDR_ANY ) ) {
  1041. IfInfo->AutoconfigActive = TRUE;
  1042. }
  1043. break;
  1044. }
  1045. if (TcpipKey != NULL)
  1046. RegCloseKey( TcpipKey );
  1047. if (TcpipParmKey != NULL)
  1048. RegCloseKey( TcpipParmKey );
  1049. AddIpv6PerInterfaceInfo( IfRow->dwIndex, IfInfo, IfList );
  1050. return Error;
  1051. }
  1052. DWORD
  1053. GetIpv6OnlyPerInterfaceInfo(
  1054. OUT PINTERFACE_NETWORK_INFO *pIfInfo,
  1055. IN PIP_ADAPTER_ADDRESSES If
  1056. )
  1057. {
  1058. DWORD Error = NO_ERROR;
  1059. PINTERFACE_NETWORK_INFO IfInfo;
  1060. IfInfo = New( sizeof(*IfInfo) );
  1061. if( NULL == IfInfo ) return GetLastError();
  1062. (*pIfInfo) = IfInfo;
  1063. ZeroMemory(IfInfo, sizeof(*IfInfo));
  1064. MapIfType(IfInfo, If->IfType);
  1065. IfInfo->PhysicalNameLength = If->PhysicalAddressLength;
  1066. CopyMemory(IfInfo->PhysicalName, If->PhysicalAddress,
  1067. If->PhysicalAddressLength);
  1068. //
  1069. // INTERFACE_NETWORK_INFO has weird field names compared to
  1070. // IP_ADAPTER_ADDRESSES. The former puts the description in its
  1071. // "friendly name" field.
  1072. //
  1073. IfInfo->FriendlyName = New((wcslen(If->Description) + 1) * sizeof(WCHAR));
  1074. if( NULL != IfInfo->FriendlyName ) {
  1075. wcscpy(IfInfo->FriendlyName, If->Description);
  1076. }
  1077. IfInfo->ConnectionName = New((wcslen(If->FriendlyName) + 1) * sizeof(WCHAR));
  1078. if( NULL != IfInfo->ConnectionName ) {
  1079. wcscpy(IfInfo->ConnectionName, If->FriendlyName);
  1080. }
  1081. IfInfo->MediaDisconnected = (If->OperStatus == IfOperStatusLowerLayerDown);
  1082. IfInfo->EnableAutoconfig = TRUE;
  1083. wcscpy(IfInfo->DnsSuffix, If->DnsSuffix);
  1084. AddIpv6PerInterfaceInfo(0, IfInfo, If);
  1085. return Error;
  1086. }
  1087. BOOL
  1088. GetGlobalTcpipAutoconfigFlag()
  1089. {
  1090. HKEY hKey;
  1091. BOOL rtn;
  1092. DWORD Error;
  1093. DWORD Type, Value, Size;
  1094. rtn = TRUE;
  1095. Size = sizeof(Value);
  1096. Error = OpenRegKey(
  1097. NULL, OpenTcpipParmKey, OpenKeyForRead, &hKey );
  1098. if (Error != NO_ERROR) {
  1099. return TRUE;
  1100. }
  1101. Error = RegQueryValueEx(
  1102. hKey, (LPTSTR)TEXT("IPAutoconfigurationEnabled"),
  1103. NULL, &Type, (LPBYTE)&Value, &Size );
  1104. if (Error == NO_ERROR && Type == REG_DWORD) {
  1105. rtn = (Value)? TRUE: FALSE;
  1106. }
  1107. RegCloseKey( hKey );
  1108. return rtn;
  1109. }
  1110. ULONG
  1111. CountIpv6OnlyInterfaces(
  1112. IN PIP_ADAPTER_ADDRESSES IfList
  1113. )
  1114. {
  1115. PIP_ADAPTER_ADDRESSES If;
  1116. ULONG Count = 0;
  1117. for (If = IfList; If; If = If->Next) {
  1118. if ((If->IfIndex == 0) && (If->Ipv6IfIndex != 0) &&
  1119. (If->IfType != IF_TYPE_SOFTWARE_LOOPBACK) &&
  1120. ((If->IfType != IF_TYPE_TUNNEL) || (If->FirstUnicastAddress != NULL))) {
  1121. Count++;
  1122. }
  1123. }
  1124. return Count;
  1125. }
  1126. DWORD
  1127. GetNetworkInformation(
  1128. OUT PNETWORK_INFO *pNetInfo,
  1129. IN OUT DWORD *InternalError
  1130. )
  1131. {
  1132. DWORD Size, Length, Error, i, j, k, IfNameCount, IfCount;
  1133. BOOL fSuccess;
  1134. PNETWORK_INFO NetInfo;
  1135. MIB_IPSTATS IpStats;
  1136. FIXED_INFO *FixedInfo;
  1137. PDNS_SEARCH_INFORMATION SearchInfo;
  1138. PMIB_IFTABLE pIfTable;
  1139. PIP_INTERFACE_INFO InterfaceInfo;
  1140. PIP_INTERFACE_NAME_INFO IfNameInfo;
  1141. PMIB_IPADDRTABLE AddrTable;
  1142. PMIB_IPFORWARDTABLE RouteTable;
  1143. PIP_ADAPTER_ADDRESSES IfList, If;
  1144. ULONG BufferLength, Flags;
  1145. //
  1146. // Allocate main structure
  1147. //
  1148. (*InternalError) = NO_ERROR;
  1149. (*pNetInfo) = NetInfo = New( sizeof(NETWORK_INFO ) );
  1150. if( NULL == NetInfo ) return GetLastError();
  1151. Flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST;
  1152. GetAdaptersAddresses(AF_UNSPEC, Flags, NULL, NULL, &BufferLength);
  1153. IfList = (PIP_ADAPTER_ADDRESSES)New(BufferLength);
  1154. if( NULL == IfList ) return GetLastError();
  1155. Error = GetAdaptersAddresses(AF_UNSPEC, Flags, NULL, IfList, &BufferLength);
  1156. if( Error != NO_ERROR ) {
  1157. Delete(IfList);
  1158. return Error;
  1159. }
  1160. SearchInfo = NULL;
  1161. pIfTable = NULL;
  1162. InterfaceInfo = NULL;
  1163. IfNameInfo = NULL;
  1164. AddrTable = NULL;
  1165. RouteTable = NULL;
  1166. do {
  1167. //
  1168. // Fill important fields of the main structure
  1169. //
  1170. Length = MaxHostNameSize;
  1171. fSuccess = GetComputerNameExW(
  1172. ComputerNameDnsHostname, NetInfo->HostName, &Length );
  1173. CheckBoolError( GlobalHostNameFailure );
  1174. Length = MaxDomainNameSize;
  1175. fSuccess = GetComputerNameExW(
  1176. ComputerNameDnsDomain, NetInfo->DomainName, &Length );
  1177. if( FALSE == fSuccess ) NetInfo->DomainName[0] = L'\0';
  1178. Error = GetIpStatistics( &IpStats );
  1179. CheckError( GlobalEnableRouterFailure );
  1180. NetInfo->EnableRouting = (
  1181. IpStats.dwForwarding == MIB_IP_FORWARDING );
  1182. //
  1183. // EnableProxy and EnableDnsForNetbios both come from the
  1184. // registry directly? We will use the GetNetworkParams
  1185. // API for this instead.
  1186. //
  1187. Size = 1000;
  1188. FixedInfo = NULL;
  1189. do {
  1190. Delete(FixedInfo);
  1191. FixedInfo = (PFIXED_INFO)New(Size);
  1192. if (NULL == FixedInfo) {
  1193. Error = ERROR_NOT_ENOUGH_MEMORY;
  1194. break;
  1195. }
  1196. Length = Size;
  1197. Error = GetNetworkParams( FixedInfo, &Length );
  1198. Size = Length;
  1199. } while (Error == ERROR_BUFFER_OVERFLOW);
  1200. CheckError( GlobalEnableDnsFailure );
  1201. NetInfo->EnableProxy = FixedInfo->EnableProxy;
  1202. NetInfo->EnableDnsForNetbios = FixedInfo->EnableDns;
  1203. Delete(FixedInfo);
  1204. FixedInfo = NULL;
  1205. //
  1206. // Now get the suffix search list from Dns
  1207. //
  1208. SearchInfo = DnsQueryConfigAlloc(
  1209. DnsConfigSearchInformation,
  1210. NULL );
  1211. if( NULL != SearchInfo ) {
  1212. Length = 0;
  1213. for( i = 0; i < SearchInfo->cNameCount ; i ++ ) {
  1214. Length += MultiByteToWideChar(
  1215. CP_UTF8, 0, SearchInfo->aSearchListNames[i],
  1216. -1, NULL, 0 );
  1217. }
  1218. if( Length != 0 ) {
  1219. Length ++;
  1220. NetInfo->SuffixSearchList = New( sizeof(WCHAR)*Length);
  1221. if( NULL == NetInfo->SuffixSearchList ) {
  1222. Error = GetLastError(); break;
  1223. }
  1224. Size = Length; Length = 0;
  1225. for( i = 0; i < SearchInfo->cNameCount ; i ++ ) {
  1226. Length += MultiByteToWideChar(
  1227. CP_UTF8, 0, SearchInfo->aSearchListNames[i],
  1228. -1, &NetInfo->SuffixSearchList[Length],
  1229. Size - Length );
  1230. }
  1231. }
  1232. }
  1233. //
  1234. // Now go for the interface specific stuff.
  1235. //
  1236. Error = NhpAllocateAndGetInterfaceInfoFromStack(
  1237. &IfNameInfo, &IfNameCount, TRUE, GetProcessHeap(),
  1238. HEAP_NO_SERIALIZE );
  1239. CheckError( GlobalIfNameInfoFailure );
  1240. #ifdef __IPCFG_ENABLE_LOG__
  1241. IPCFG_TRACE(IPCFG_TRACE_TCPIP, ("NhpAllocateAndGetInterfaceInfoFromStack returns 0x%lx (%d) %d Interfaces\n",
  1242. Error, Error, IfNameCount));
  1243. for (i = 0; i < IfNameCount; i++) {
  1244. LPWSTR DeviceGuid, InterfaceGuid;
  1245. DeviceGuid = InterfaceGuid = NULL;
  1246. UuidToStringW(&IfNameInfo[i].DeviceGuid, &DeviceGuid);
  1247. UuidToStringW(&IfNameInfo[i].InterfaceGuid, &InterfaceGuid);
  1248. if (DeviceGuid == NULL || InterfaceGuid == NULL) {
  1249. if (DeviceGuid) RpcStringFree(&DeviceGuid);
  1250. if (InterfaceGuid) RpcStringFree(&InterfaceGuid);
  1251. IPCFG_TRACE(IPCFG_TRACE_TCPIP, ("\t%2d. Index=0x%x DeviceGUID=<fail> InterfaceGUID=<fail>\n",
  1252. i + 1, IfNameInfo[i].Index));
  1253. } else {
  1254. IPCFG_TRACE(IPCFG_TRACE_TCPIP, ("\t%2d. Index=0x%x\n\t DeviceGUID=%ws\n\t InterfaceGUID=%ws\n",
  1255. i + 1, IfNameInfo[i].Index, DeviceGuid, InterfaceGuid));
  1256. RpcStringFree(&DeviceGuid);
  1257. RpcStringFree(&InterfaceGuid);
  1258. }
  1259. }
  1260. #endif
  1261. Size = 1000;
  1262. do {
  1263. Delete( RouteTable );
  1264. RouteTable = New( Size );
  1265. if( NULL == RouteTable ) {
  1266. Error = GetLastError();
  1267. } else {
  1268. Error = GetIpForwardTable(
  1269. RouteTable, &Size, FALSE );
  1270. }
  1271. } while( ERROR_INSUFFICIENT_BUFFER == Error );
  1272. #ifdef __IPCFG_ENABLE_LOG__
  1273. if (RouteTable) {
  1274. IPCFG_TRACE(IPCFG_TRACE_TCPIP, ("GetIpForwardTable returns 0x%lx (%d) %d routing entries\n",
  1275. Error, Error, RouteTable->dwNumEntries));
  1276. for (i = 0; i < RouteTable->dwNumEntries; i++) {
  1277. IPCFG_TRACE(IPCFG_TRACE_TCPIP, ("\t%2d. Index=0x%x Next Hop=%s ",
  1278. i + 1, RouteTable->table[i].dwForwardIfIndex,
  1279. inet_ntoa(*(struct in_addr*)&RouteTable->table[i].dwForwardNextHop)));
  1280. IPCFG_TRACE(IPCFG_TRACE_TCPIP, ("Mask=%s Type=0x%x\n",
  1281. inet_ntoa(*(struct in_addr*)&RouteTable->table[i].dwForwardMask),
  1282. RouteTable->table[i].dwForwardType));
  1283. }
  1284. }
  1285. #endif
  1286. Size = 1000;
  1287. do {
  1288. Delete( AddrTable );
  1289. AddrTable = New( Size );
  1290. if( NULL == AddrTable ) {
  1291. Error = GetLastError();
  1292. } else {
  1293. Error = GetIpAddrTable( AddrTable, &Size, TRUE );
  1294. }
  1295. } while( ERROR_INSUFFICIENT_BUFFER == Error );
  1296. CheckError( GlobalAddrTableFailure );
  1297. #ifdef __IPCFG_ENABLE_LOG__
  1298. IPCFG_TRACE(IPCFG_TRACE_TCPIP, ("GetIpAddrTable returns 0x%lx (%d) %d IP entries\n",
  1299. Error, Error, AddrTable->dwNumEntries));
  1300. for (i = 0; i < AddrTable->dwNumEntries; i++) {
  1301. IPCFG_TRACE(IPCFG_TRACE_TCPIP, ("\t%2d. Index=0x%x IP=%s",
  1302. i + 1, AddrTable->table[i].dwIndex,
  1303. inet_ntoa(*(struct in_addr*)&AddrTable->table[i].dwAddr)));
  1304. IPCFG_TRACE(IPCFG_TRACE_TCPIP, (" mask=%s Type=0x%x\n",
  1305. inet_ntoa(*(struct in_addr*)&AddrTable->table[i].dwMask),
  1306. AddrTable->table[i].wType));
  1307. }
  1308. #endif
  1309. pIfTable = NULL;
  1310. Error = AllocateAndGetIfTableFromStack( &pIfTable, TRUE, GetProcessHeap(), 0, TRUE);
  1311. CheckError( GlobalIfTableFailure );
  1312. #ifdef __IPCFG_ENABLE_LOG__
  1313. IPCFG_TRACE(IPCFG_TRACE_TCPIP, ("GetIfTable returns 0x%lx (%d) %d Interfaces\n",
  1314. Error, Error, pIfTable->dwNumEntries));
  1315. for( i = 0; i < pIfTable->dwNumEntries; i ++ ) {
  1316. IPCFG_TRACE(IPCFG_TRACE_TCPIP, ("\t%2d. IfIndex=0x%x Name=%ws IfType=0x%x\n",
  1317. i + 1, pIfTable->table[i].dwIndex, pIfTable->table[i].wszName, pIfTable->table[i].dwType));
  1318. }
  1319. #endif
  1320. Size = 1000;
  1321. do {
  1322. Delete( InterfaceInfo );
  1323. InterfaceInfo = New( Size );
  1324. if( NULL == InterfaceInfo ) {
  1325. Error = GetLastError();
  1326. } else {
  1327. Error = GetInterfaceInfo( InterfaceInfo, &Size );
  1328. }
  1329. } while( ERROR_INSUFFICIENT_BUFFER == Error );
  1330. CheckError( GlobalIfInfoFailure );
  1331. #ifdef __IPCFG_ENABLE_LOG__
  1332. IPCFG_TRACE(IPCFG_TRACE_TCPIP, ("GetInterfaceInfo returns 0x%lx (%d) %d Interfaces\n",
  1333. Error, Error, InterfaceInfo->NumAdapters));
  1334. for( i = 0; i < (DWORD)InterfaceInfo->NumAdapters; i ++ ) {
  1335. IPCFG_TRACE(IPCFG_TRACE_TCPIP, ("\t%2d. Index=0x%x\n\t Name=%ws\n",
  1336. i + 1, InterfaceInfo->Adapter[i].Index, InterfaceInfo->Adapter[i].Name));
  1337. }
  1338. #endif
  1339. //
  1340. // Get global AutoConfig settings
  1341. //
  1342. NetInfo->GlobalEnableAutoconfig = GetGlobalTcpipAutoconfigFlag();
  1343. IPCFG_TRACE(IPCFG_TRACE_TCPIP, ("GlobalAutoConfigFlag: %d\n", NetInfo->GlobalEnableAutoconfig));
  1344. //
  1345. // Check for number of interfaces and allocate required
  1346. // space in the IfInfo field
  1347. //
  1348. IfCount = pIfTable->dwNumEntries;
  1349. IfCount += CountIpv6OnlyInterfaces(IfList);
  1350. if( IfCount > 1 ) {
  1351. NetInfo->nInterfaces = IfCount-1;
  1352. NetInfo->IfInfo = New(
  1353. NetInfo->nInterfaces * sizeof(PVOID) );
  1354. if( NULL == NetInfo->IfInfo ) {
  1355. Error = GetLastError(); break;
  1356. }
  1357. //
  1358. // First add interfaces running IPv4.
  1359. //
  1360. j = 0;
  1361. for( i = 0; i < pIfTable->dwNumEntries ; i ++ ) {
  1362. BOOL fFound = FALSE;
  1363. for( k = 0; k <
  1364. (DWORD)InterfaceInfo->NumAdapters; k ++ ) {
  1365. if( pIfTable->table[i].dwIndex ==
  1366. InterfaceInfo->Adapter[k].Index ) {
  1367. fFound = TRUE;
  1368. break;
  1369. }
  1370. }
  1371. if( fFound &&
  1372. pIfTable->table[i].dwType != IF_TYPE_SOFTWARE_LOOPBACK ) {
  1373. IPCFG_TRACE(IPCFG_TRACE_TCPIP, ("\n\n************ GetPerInterfaceInfo for "
  1374. "IfIndex=0x%x Name=%ws IfType=0x%x\n",
  1375. pIfTable->table[i].dwIndex, pIfTable->table[i].wszName, pIfTable->table[i].dwType));
  1376. Error = GetPerInterfaceInfo(
  1377. NetInfo, &NetInfo->IfInfo[j],
  1378. &pIfTable->table[i], InterfaceInfo,
  1379. IfNameInfo, IfNameCount, AddrTable,
  1380. RouteTable, IfList, InternalError );
  1381. if( NO_ERROR != Error ) break;
  1382. j ++;
  1383. }
  1384. }
  1385. //
  1386. // Now add any IPv6-only interfaces.
  1387. //
  1388. for (If = IfList; If; If = If->Next) {
  1389. if ((If->IfIndex == 0) && (If->Ipv6IfIndex != 0) &&
  1390. (If->IfType != IF_TYPE_SOFTWARE_LOOPBACK) &&
  1391. ((If->IfType != IF_TYPE_TUNNEL) || (If->FirstUnicastAddress != NULL))) {
  1392. Error = GetIpv6OnlyPerInterfaceInfo(&NetInfo->IfInfo[j],
  1393. If);
  1394. if( NO_ERROR != Error ) break;
  1395. j ++;
  1396. }
  1397. }
  1398. NetInfo->nInterfaces = j;
  1399. if( NO_ERROR != Error ) break;
  1400. }
  1401. } while ( 0 );
  1402. if (pIfTable) {
  1403. HeapFree(GetProcessHeap(), 0, pIfTable );
  1404. pIfTable = NULL;
  1405. }
  1406. Delete( InterfaceInfo );
  1407. Delete( IfNameInfo );
  1408. Delete( AddrTable );
  1409. Delete( RouteTable );
  1410. Delete( FixedInfo );
  1411. Delete( IfList );
  1412. if ( SearchInfo ) {
  1413. DnsFreeConfigStructure(
  1414. SearchInfo,
  1415. DnsConfigSearchInformation );
  1416. }
  1417. return Error;
  1418. }