Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1195 lines
31 KiB

  1. /*++
  2. Copyright(c) 1995 Microsoft Corporation
  3. MODULE NAME
  4. netmap.c
  5. ABSTRACT
  6. Network map routines
  7. AUTHOR
  8. Anthony Discolo (adiscolo) 21-May-1996
  9. REVISION HISTORY
  10. --*/
  11. #define UNICODE
  12. #define _UNICODE
  13. #include <nt.h>
  14. #include <ntrtl.h>
  15. #include <nturtl.h>
  16. #include <stdlib.h>
  17. #include <windows.h>
  18. #include <tdi.h>
  19. #include <nb30.h>
  20. #include <nbtioctl.h>
  21. #include <stdio.h>
  22. #include <npapi.h>
  23. #include <ctype.h>
  24. #include <winsock.h>
  25. #include <acd.h>
  26. #include <ras.h>
  27. #include <raserror.h>
  28. #include <rasman.h>
  29. #include <debug.h>
  30. #include <ipexport.h>
  31. #include <icmpapi.h>
  32. #include "reg.h"
  33. #include "misc.h"
  34. #include "table.h"
  35. #include "access.h"
  36. #include "rasprocs.h"
  37. //
  38. // We keep a map of network name to
  39. // address that groups related addresses
  40. // by network name. We use the network
  41. // name as a remote network identifier to
  42. // allow us to quickly determine whether
  43. // any address belongs to a network that
  44. // is connected or not.
  45. //
  46. typedef struct _NETWORK_MAP_ENTRY {
  47. BOOLEAN bUp; // network is connected
  48. DWORD dwConnectionTag; // unique index for connections
  49. PHASH_TABLE pTable; // table of addresses
  50. LIST_ENTRY listEntry; // addresses sorted by tag
  51. } NETWORK_MAP_ENTRY, *PNETWORK_MAP_ENTRY;
  52. //
  53. // The network map.
  54. //
  55. //
  56. typedef struct _NETWORK_MAP {
  57. CRITICAL_SECTION csLock;
  58. LPTSTR pszDnsAddresses; // DNS server list
  59. DWORD dwcConnections; // number of RAS connections
  60. DWORD dwcUpNetworks; // number of up networks
  61. DWORD dwConnectionTag; // unique index for connections for NULL network
  62. PHASH_TABLE pTable; // network table
  63. } NETWORK_MAP, PNETWORK_MAP;
  64. //
  65. // This structure is passed to an address
  66. // enumerator procedure to keep track of
  67. // any hosts that are accessible.
  68. //
  69. typedef struct _NETWORK_MAP_ACCESS {
  70. LPTSTR pszNbDevice; // Netbios device for find name requests
  71. BOOLEAN bUp; // network is up
  72. DWORD dwFailures; // number of host access failures
  73. } NETWORK_MAP_ACCESS, *PNETWORK_MAP_ACCESS;
  74. //
  75. // This structure is used to store the
  76. // network addresses sorted by tag.
  77. //
  78. typedef struct _TAGGED_ADDRESS {
  79. DWORD dwTag; // the tag
  80. LPTSTR pszAddress; // the address
  81. LIST_ENTRY listEntry; // sorted address list
  82. } TAGGED_ADDRESS, *PTAGGED_ADDRESS;
  83. //
  84. // Netbios device information passed
  85. // to AcsCheckNetworkThread
  86. //
  87. typedef struct _CHECK_NETWORK_INFO {
  88. LPTSTR *pszNbDevices; // array of Netbios device strings
  89. DWORD dwcNbDevices; // array size
  90. BOOLEAN fDns; // DNS server is up
  91. } CHECK_NETWORK_INFO, *PCHECK_NETWORK_INFO;
  92. //
  93. // Global variables
  94. //
  95. NETWORK_MAP NetworkMapG;
  96. LPTSTR
  97. GetPrimaryNetbiosDevice(VOID)
  98. {
  99. typedef struct _LANA_MAP {
  100. BOOLEAN fEnum;
  101. UCHAR bLana;
  102. } LANA_MAP, *PLANA_MAP;
  103. BOOLEAN fNetworkPresent = FALSE;
  104. HKEY hKey;
  105. PLANA_MAP pLanaMap = NULL, pLana;
  106. DWORD dwError, dwcbLanaMap;
  107. PWCHAR pwszLanas = NULL, pwszBuf;
  108. DWORD dwcBindings, dwcMaxLanas, i, dwcbLanas;
  109. LONG iLana;
  110. DWORD dwZero = 0;
  111. PWCHAR *paszLanas = NULL;
  112. SOCKET s;
  113. NTSTATUS status;
  114. UNICODE_STRING deviceName;
  115. OBJECT_ATTRIBUTES attributes;
  116. IO_STATUS_BLOCK iosb;
  117. HANDLE handle;
  118. PWCHAR pwszDevice = NULL;
  119. dwError = RegOpenKeyEx(
  120. HKEY_LOCAL_MACHINE,
  121. L"System\\CurrentControlSet\\Services\\Netbios\\Linkage",
  122. 0,
  123. KEY_READ,
  124. &hKey);
  125. if (dwError != ERROR_SUCCESS) {
  126. RASAUTO_TRACE1(
  127. "GetPrimaryNetbiosDevice: RegKeyOpenEx failed (dwError=%d)",
  128. GetLastError());
  129. return FALSE;
  130. }
  131. //
  132. // Read in the LanaMap.
  133. //
  134. if (!RegGetValue(hKey, L"LanaMap", &pLanaMap, &dwcbLanaMap, NULL)) {
  135. RASAUTO_TRACE("GetPrimaryNetbiosDevice: RegGetValue(LanaMap) failed");
  136. goto done;
  137. }
  138. dwcBindings = dwcbLanaMap / sizeof (LANA_MAP);
  139. //
  140. // Read in the bindings.
  141. //
  142. if (!RegGetValue(hKey, L"bind", &pwszLanas, &dwcbLanas, NULL)) {
  143. RASAUTO_TRACE("GetPrimaryNetbiosDevice: RegGetValue(bind) failed");
  144. goto done;
  145. }
  146. //
  147. // Allocate a buffer for the binding array.
  148. //
  149. paszLanas = LocalAlloc(LPTR, dwcBindings * sizeof (PWCHAR));
  150. if (paszLanas == NULL) {
  151. RASAUTO_TRACE("GetPrimaryNetbiosDevice: LocalAlloc failed");
  152. goto done;
  153. }
  154. //
  155. // Parse the bindings into an array of strings.
  156. //
  157. for (dwcMaxLanas = 0, pwszBuf = pwszLanas;
  158. (*pwszBuf) && (dwcMaxLanas < dwcBindings);
  159. pwszBuf++)
  160. {
  161. paszLanas[dwcMaxLanas++] = pwszBuf;
  162. while(*++pwszBuf);
  163. }
  164. for (iLana = 0, pLana = pLanaMap; dwcBindings--; iLana++, pLana++) {
  165. int iLanaMap = (int)pLana->bLana;
  166. if (pLana->fEnum && (DWORD)iLana < dwcMaxLanas) {
  167. int iError;
  168. WCHAR *pwsz, szDevice[MAX_DEVICE_NAME + 1];
  169. if (wcsstr(paszLanas[iLana], L"NwlnkNb") != NULL ||
  170. wcsstr(paszLanas[iLana], L"_NdisWan") != NULL)
  171. {
  172. RASAUTO_TRACE1(
  173. "GetPrimaryNetbiosDevice: ignoring %S",
  174. RASAUTO_TRACESTRW(paszLanas[iLana]));
  175. continue;
  176. }
  177. RtlInitUnicodeString(&deviceName, paszLanas[iLana]);
  178. InitializeObjectAttributes(
  179. &attributes,
  180. &deviceName,
  181. OBJ_CASE_INSENSITIVE,
  182. NULL,
  183. NULL);
  184. //
  185. // Open the lana device.
  186. //
  187. status = NtOpenFile(&handle, READ_CONTROL, &attributes, &iosb, 0, 0);
  188. NtClose(handle);
  189. if (!NT_SUCCESS(status)) {
  190. RASAUTO_TRACE2(
  191. "GetPrimaryNetbiosDevice: NtOpenFile(%S) failed (status=0x%x)",
  192. RASAUTO_TRACESTRW(paszLanas[iLana]),
  193. status);
  194. continue;
  195. }
  196. RASAUTO_TRACE1("GetPrimaryNetbiosDevice: opened %S", paszLanas[iLana]);
  197. //
  198. // If we succeed in opening the lana
  199. // device, we need to make sure the
  200. // underlying netcard device is loaded
  201. // as well, since transports create
  202. // device object for non-existent devices.
  203. //
  204. pwsz = wcsrchr(paszLanas[iLana], '_');
  205. if (pwsz == NULL) {
  206. RASAUTO_TRACE1(
  207. "GetPrimaryNetbiosDevice: couldn't parse %S",
  208. paszLanas[iLana]);
  209. continue;
  210. }
  211. wsprintf(szDevice, L"\\Device\\%s", pwsz + 1);
  212. //
  213. // Open the underlying netcard device.
  214. //
  215. RtlInitUnicodeString(&deviceName, szDevice);
  216. InitializeObjectAttributes(
  217. &attributes,
  218. &deviceName,
  219. OBJ_CASE_INSENSITIVE,
  220. NULL,
  221. NULL);
  222. status = NtOpenFile(&handle, READ_CONTROL, &attributes, &iosb, 0, 0);
  223. NtClose(handle);
  224. if (!NT_SUCCESS(status)) {
  225. RASAUTO_TRACE2(
  226. "GetPrimaryNetbiosDevice: NtOpenFile(%S) failed (status=0x%x)",
  227. RASAUTO_TRACESTRW(szDevice),
  228. status);
  229. continue;
  230. }
  231. //
  232. // We've succeeded. The netcard device must
  233. // be really loaded.
  234. //
  235. RASAUTO_TRACE3(
  236. "GetPrimaryNetbiosDevice: network (%S, %S, %d) is up",
  237. RASAUTO_TRACESTRW(paszLanas[iLana]),
  238. szDevice,
  239. iLana);
  240. pwszDevice = CopyString(paszLanas[iLana]);
  241. break;
  242. }
  243. }
  244. //
  245. // Free resources.
  246. //
  247. done:
  248. if (paszLanas != NULL)
  249. LocalFree(paszLanas);
  250. if (pwszLanas != NULL)
  251. LocalFree(pwszLanas);
  252. if (pLanaMap != NULL)
  253. LocalFree(pLanaMap);
  254. RegCloseKey(hKey);
  255. return pwszDevice;
  256. } // GetPrimaryNetbiosDevice
  257. LPTSTR
  258. DnsAddresses()
  259. /*++
  260. DESCRIPTION
  261. Return the list of DNS servers for this host.
  262. ARGUMENTS
  263. None.
  264. RETURN VALUE
  265. NULL if no DNS servers are configured; a list
  266. of IP addresses separated by a space otherwise.
  267. --*/
  268. {
  269. HKEY hkey;
  270. BOOLEAN fFound = FALSE;
  271. LPTSTR pszIpAddresses = NULL;
  272. LPTSTR pszIpAddress, pszIpAddressEnd;
  273. DWORD dwcbIpAddresses = 0;
  274. //
  275. // Look in various places in the registry
  276. // for one or more DNS addresses.
  277. //
  278. if (RegOpenKeyEx(
  279. HKEY_LOCAL_MACHINE,
  280. L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Transient",
  281. 0,
  282. KEY_QUERY_VALUE,
  283. &hkey) == ERROR_SUCCESS)
  284. {
  285. fFound = RegGetValue(
  286. hkey,
  287. L"NameServer",
  288. &pszIpAddresses,
  289. &dwcbIpAddresses,
  290. NULL);
  291. RegCloseKey(hkey);
  292. }
  293. if (fFound && dwcbIpAddresses > sizeof (TCHAR))
  294. goto found;
  295. if (pszIpAddresses != NULL) {
  296. LocalFree(pszIpAddresses);
  297. pszIpAddresses = NULL;
  298. }
  299. if (RegOpenKeyEx(
  300. HKEY_LOCAL_MACHINE,
  301. L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",
  302. 0,
  303. KEY_QUERY_VALUE,
  304. &hkey) == ERROR_SUCCESS)
  305. {
  306. fFound = RegGetValue(
  307. hkey,
  308. L"NameServer",
  309. &pszIpAddresses,
  310. &dwcbIpAddresses,
  311. NULL);
  312. if (fFound && dwcbIpAddresses > sizeof (TCHAR)) {
  313. RegCloseKey(hkey);
  314. goto found;
  315. }
  316. if (pszIpAddresses != NULL) {
  317. LocalFree(pszIpAddresses);
  318. pszIpAddresses = NULL;
  319. }
  320. fFound = RegGetValue(
  321. hkey,
  322. L"DhcpNameServer",
  323. &pszIpAddresses,
  324. &dwcbIpAddresses,
  325. NULL);
  326. RegCloseKey(hkey);
  327. if (fFound && dwcbIpAddresses > sizeof (TCHAR))
  328. goto found;
  329. if (pszIpAddresses != NULL) {
  330. LocalFree(pszIpAddresses);
  331. pszIpAddresses = NULL;
  332. }
  333. }
  334. found:
  335. RASAUTO_TRACE1("DnsAddresses: pszIpAddresses=%S", RASAUTO_TRACESTRW(pszIpAddresses));
  336. return pszIpAddresses;
  337. } // DnsAddresses
  338. BOOLEAN
  339. PingAddressList(
  340. IN LPTSTR pszAddresses
  341. )
  342. {
  343. TCHAR szAddress[17];
  344. TCHAR *pSrc, *pDst;
  345. //
  346. // If the address list is NULL, we're done.
  347. //
  348. if (pszAddresses == NULL)
  349. return FALSE;
  350. //
  351. // Loop through the addresses and try to
  352. // ping each until one succeeds.
  353. //
  354. for (;;) {
  355. //
  356. // Copy the next address into szAddress.
  357. //
  358. for (pSrc = pszAddresses, pDst = szAddress;
  359. *pSrc != TEXT(' ') && *pSrc != TEXT(',') && *pSrc != TEXT('\0');
  360. *pSrc++, *pDst++)
  361. {
  362. *pDst = *pSrc;
  363. }
  364. *pDst = TEXT('\0');
  365. //
  366. // Ping it. If it succeeds, then
  367. // we're done.
  368. //
  369. if (PingIpAddress(szAddress))
  370. return TRUE;
  371. //
  372. // Skip to the next address.
  373. //
  374. if (*pSrc == TEXT('\0'))
  375. break;
  376. pSrc++;
  377. if (*pSrc == TEXT('\0'))
  378. break;
  379. pszAddresses = pSrc;
  380. }
  381. return FALSE;
  382. } // PingAddressList
  383. BOOLEAN
  384. InitializeNetworkMap(VOID)
  385. {
  386. InitializeCriticalSection(&NetworkMapG.csLock);
  387. NetworkMapG.pszDnsAddresses = NULL;
  388. NetworkMapG.dwcConnections = 0;
  389. NetworkMapG.dwcUpNetworks = 0;
  390. NetworkMapG.dwConnectionTag = 0;
  391. NetworkMapG.pTable = NewTable();
  392. if (NetworkMapG.pTable == NULL) {
  393. RASAUTO_TRACE("InitializeNetworkMap: NewTable failed");
  394. return FALSE;
  395. }
  396. return TRUE;
  397. } // InitializeNetworkMap
  398. VOID
  399. LockNetworkMap(VOID)
  400. {
  401. EnterCriticalSection(&NetworkMapG.csLock);
  402. } // LockNetworkMap
  403. VOID
  404. UnlockNetworkMap(VOID)
  405. {
  406. LeaveCriticalSection(&NetworkMapG.csLock);
  407. } // UnlockNetworkMap
  408. PNETWORK_MAP_ENTRY
  409. NewNetworkMapEntry(
  410. IN LPTSTR pszNetwork
  411. )
  412. {
  413. PNETWORK_MAP_ENTRY pNetworkMapEntry;
  414. DWORD i;
  415. pNetworkMapEntry = LocalAlloc(LPTR, sizeof (NETWORK_MAP_ENTRY));
  416. if (pNetworkMapEntry == NULL) {
  417. RASAUTO_TRACE("NewNetworkMapEntry: LocalAlloc failed");
  418. return NULL;
  419. }
  420. pNetworkMapEntry->bUp = FALSE;
  421. pNetworkMapEntry->dwConnectionTag = 0;
  422. pNetworkMapEntry->pTable = NewTable();
  423. if (pNetworkMapEntry->pTable == NULL) {
  424. RASAUTO_TRACE("NewNetworkMapEntry: NewTable failed");
  425. LocalFree(pNetworkMapEntry);
  426. return NULL;
  427. }
  428. InitializeListHead(&pNetworkMapEntry->listEntry);
  429. if (!PutTableEntry(NetworkMapG.pTable, pszNetwork, pNetworkMapEntry)) {
  430. RASAUTO_TRACE("NewNetworkMapEntry: PutTableEntry failed");
  431. LocalFree(pNetworkMapEntry);
  432. return NULL;
  433. }
  434. return pNetworkMapEntry;
  435. } // NewNetworkMapEntry
  436. VOID
  437. FreeNetworkMapEntry(
  438. IN PNETWORK_MAP_ENTRY pNetworkMapEntry
  439. )
  440. {
  441. PLIST_ENTRY pEntry;
  442. PTAGGED_ADDRESS pTaggedAddress;
  443. /*
  444. //
  445. // Since the PTAGGED_ADDRESS structures are
  446. // in a hash table and a list, we need to
  447. // free the structures in a special way. The
  448. // table package automatically frees the
  449. // structures when a PutTableEntry(pTable, address, NULL)
  450. // is called.
  451. //
  452. for (pEntry = pNetworkMapEntry->listEntry.Flink;
  453. pEntry != &pNetworkMapEntry->listEntry;
  454. pEntry = pEntry->Flink)
  455. {
  456. pTaggedAddress = CONTAINING_RECORD(pEntry, TAGGED_ADDRESS, listEntry);
  457. LocalFree(pTaggedAddress->pszAddress);
  458. }
  459. */
  460. while (!IsListEmpty(&pNetworkMapEntry->listEntry)) {
  461. LPTSTR pszAddress;
  462. pEntry = RemoveHeadList(&pNetworkMapEntry->listEntry);
  463. pTaggedAddress = CONTAINING_RECORD(pEntry, TAGGED_ADDRESS, listEntry);
  464. pszAddress = pTaggedAddress->pszAddress;
  465. //
  466. // The following call frees the
  467. // pTaggedAddress structure, as
  468. // well as frees the table entry.
  469. //
  470. PutTableEntry(pNetworkMapEntry->pTable, pszAddress, NULL);
  471. LocalFree(pszAddress);
  472. }
  473. ClearTable(pNetworkMapEntry->pTable);
  474. } // FreeNetworkMapEntry
  475. ACD_ADDR_TYPE
  476. AddressToType(
  477. IN LPTSTR pszAddress
  478. )
  479. {
  480. LONG inaddr;
  481. CHAR szAddress[17];
  482. UnicodeStringToAnsiString(pszAddress, szAddress, sizeof (szAddress));
  483. inaddr = inet_addr(szAddress);
  484. if (inaddr != INADDR_NONE)
  485. return ACD_ADDR_IP;
  486. if (wcschr(pszAddress, ':') != NULL)
  487. return ACD_ADDR_IPX;
  488. if (wcschr(pszAddress, '.') != NULL)
  489. return ACD_ADDR_INET;
  490. return ACD_ADDR_NB;
  491. } // AddressToType
  492. PNETWORK_MAP_ENTRY
  493. GetNetworkMapEntry(
  494. IN LPTSTR pszNetwork
  495. )
  496. {
  497. PNETWORK_MAP_ENTRY pNetworkMapEntry;
  498. if (GetTableEntry(
  499. NetworkMapG.pTable,
  500. pszNetwork,
  501. &pNetworkMapEntry))
  502. {
  503. return pNetworkMapEntry;
  504. }
  505. return NULL;
  506. } // GetNetworkMapEntry
  507. BOOLEAN
  508. AddNetworkAddress(
  509. IN LPTSTR pszNetwork,
  510. IN LPTSTR pszAddress,
  511. IN DWORD dwTag
  512. )
  513. {
  514. PNETWORK_MAP_ENTRY pNetworkMapEntry;
  515. PTAGGED_ADDRESS pNewTaggedAddress, pTaggedAddress;
  516. PLIST_ENTRY pPrevEntry, pEntry;
  517. BOOLEAN bInserted = FALSE;
  518. BOOLEAN bCreateNew = TRUE;
  519. RASAUTO_TRACE3(
  520. "AddNetworkAddress(%S,%S,%d)",
  521. RASAUTO_TRACESTRW(pszNetwork),
  522. pszAddress,
  523. dwTag);
  524. //
  525. // Create the network map entry if necessary.
  526. //
  527. LockNetworkMap();
  528. pNetworkMapEntry = GetNetworkMapEntry(pszNetwork);
  529. if (pNetworkMapEntry == NULL) {
  530. pNetworkMapEntry = NewNetworkMapEntry(pszNetwork);
  531. if (pNetworkMapEntry == NULL) {
  532. UnlockNetworkMap();
  533. return FALSE;
  534. }
  535. }
  536. else {
  537. //
  538. // Check to see if the address already exists.
  539. //
  540. if (GetTableEntry(
  541. pNetworkMapEntry->pTable,
  542. pszAddress,
  543. &pNewTaggedAddress))
  544. {
  545. RASAUTO_TRACE2(
  546. "AddNetworkAddress: %S exists with dwTag=%d",
  547. pszAddress,
  548. pNewTaggedAddress->dwTag);
  549. //
  550. // If the address exists with a lower tag, then
  551. // we don't need to do anything.
  552. //
  553. if (pNewTaggedAddress->dwTag <= dwTag) {
  554. UnlockNetworkMap();
  555. return TRUE;
  556. }
  557. //
  558. // If the address exists with a higher tag, then
  559. // we need to remove the existing entry from
  560. // the list.
  561. //
  562. RemoveEntryList(&pNewTaggedAddress->listEntry);
  563. bCreateNew = FALSE;
  564. }
  565. }
  566. if (bCreateNew) {
  567. //
  568. // Create the new tagged address structure.
  569. //
  570. pNewTaggedAddress = LocalAlloc(LPTR, sizeof (TAGGED_ADDRESS));
  571. if (pNewTaggedAddress == NULL) {
  572. RASAUTO_TRACE("AddNetworkMap: LocalAlloc failed");
  573. UnlockNetworkMap();
  574. return FALSE;
  575. }
  576. pNewTaggedAddress->pszAddress = CopyString(pszAddress);
  577. if (pNewTaggedAddress->pszAddress == NULL) {
  578. RASAUTO_TRACE("AddNetworkMap: LocalAlloc failed");
  579. UnlockNetworkMap();
  580. LocalFree(pNewTaggedAddress);
  581. LocalFree(pNetworkMapEntry);
  582. return FALSE;
  583. }
  584. if (!PutTableEntry(
  585. pNetworkMapEntry->pTable,
  586. pszAddress,
  587. pNewTaggedAddress))
  588. {
  589. RASAUTO_TRACE("AddNetworkMap: PutTableEntry failed");
  590. UnlockNetworkMap();
  591. LocalFree(pNewTaggedAddress->pszAddress);
  592. LocalFree(pNewTaggedAddress);
  593. return FALSE;
  594. }
  595. }
  596. pNewTaggedAddress->dwTag = dwTag;
  597. //
  598. // Insert the new address into the list sorted by tag.
  599. //
  600. pPrevEntry = &pNetworkMapEntry->listEntry;
  601. for (pEntry = pNetworkMapEntry->listEntry.Flink;
  602. pEntry != &pNetworkMapEntry->listEntry;
  603. pEntry = pEntry->Flink)
  604. {
  605. pTaggedAddress = CONTAINING_RECORD(pEntry, TAGGED_ADDRESS, listEntry);
  606. if (pTaggedAddress->dwTag >= pNewTaggedAddress->dwTag) {
  607. InsertHeadList(pPrevEntry, &pNewTaggedAddress->listEntry);
  608. bInserted = TRUE;
  609. break;
  610. }
  611. pPrevEntry = pEntry;
  612. }
  613. if (!bInserted) {
  614. InsertTailList(
  615. &pNetworkMapEntry->listEntry,
  616. &pNewTaggedAddress->listEntry);
  617. }
  618. UnlockNetworkMap();
  619. return TRUE;
  620. } // AddNetworkAddress
  621. BOOLEAN
  622. ClearNetworkMapEntry(
  623. IN PVOID pArg,
  624. IN LPTSTR pszNetwork,
  625. IN PVOID pData
  626. )
  627. {
  628. PNETWORK_MAP_ENTRY pNetworkMapEntry = (PNETWORK_MAP_ENTRY)pData;
  629. FreeNetworkMapEntry(pNetworkMapEntry);
  630. return TRUE;
  631. } // ClearNetworkMapEntry
  632. VOID
  633. ClearNetworkMap(VOID)
  634. {
  635. LockNetworkMap();
  636. NetworkMapG.dwcConnections = 0;
  637. NetworkMapG.dwcUpNetworks = 0;
  638. NetworkMapG.dwConnectionTag = 0;
  639. EnumTable(NetworkMapG.pTable, ClearNetworkMapEntry, NULL);
  640. ClearTable(NetworkMapG.pTable);
  641. UnlockNetworkMap();
  642. } // ClearNetworkMap
  643. BOOLEAN
  644. IsAddressAccessible(
  645. IN LPTSTR *pszNbDevices,
  646. IN DWORD dwcNbDevices,
  647. IN BOOLEAN fDnsAvailable,
  648. IN LPTSTR pszAddress
  649. )
  650. {
  651. ACD_ADDR_TYPE fType;
  652. BOOLEAN bSuccess = FALSE;
  653. //
  654. // Get the type of the address.
  655. //
  656. fType = AddressToType(pszAddress);
  657. RASAUTO_TRACE2(
  658. "IsAddressAccessible: fType=%d, pszAddress=%S",
  659. fType,
  660. pszAddress);
  661. //
  662. // Call the address-specific accessibility routine.
  663. //
  664. switch (fType) {
  665. case ACD_ADDR_IP:
  666. bSuccess = PingIpAddress(pszAddress);
  667. break;
  668. case ACD_ADDR_IPX:
  669. RASAUTO_TRACE("IsAddressAccessible: IPX address!");
  670. break;
  671. case ACD_ADDR_NB:
  672. bSuccess = NetbiosFindName(pszNbDevices, dwcNbDevices, pszAddress);
  673. break;
  674. case ACD_ADDR_INET:
  675. if (fDnsAvailable) {
  676. struct hostent *hp;
  677. struct in_addr in;
  678. PCHAR pch;
  679. TCHAR szIpAddress[17];
  680. LPTSTR psz;
  681. psz = LocalAlloc(LPTR, (lstrlen(pszAddress) + 1) * sizeof(TCHAR));
  682. if(NULL == psz)
  683. {
  684. break;
  685. }
  686. lstrcpy(psz, pszAddress);
  687. UnlockNetworkMap();
  688. hp = InetAddressToHostent(psz);
  689. LocalFree(psz);
  690. LockNetworkMap();
  691. if (hp != NULL) {
  692. in.s_addr = *(PULONG)hp->h_addr;
  693. pch = inet_ntoa(in);
  694. if (pch != NULL) {
  695. AnsiStringToUnicodeString(
  696. pch,
  697. szIpAddress,
  698. sizeof (szIpAddress));
  699. bSuccess = PingIpAddress(szIpAddress);
  700. }
  701. }
  702. }
  703. break;
  704. default:
  705. RASAUTO_TRACE1("IsAddressAccessible: invalid type: %d", fType);
  706. break;
  707. }
  708. return bSuccess;
  709. } // IsAddressAccessible
  710. BOOLEAN
  711. CheckNetwork(
  712. IN PVOID pArg,
  713. IN LPTSTR pszNetwork,
  714. IN PVOID pData
  715. )
  716. {
  717. PCHECK_NETWORK_INFO pCheckNetworkInfo = (PCHECK_NETWORK_INFO)pArg;
  718. PNETWORK_MAP_ENTRY pNetworkMapEntry = (PNETWORK_MAP_ENTRY)pData;
  719. PLIST_ENTRY pEntry;
  720. DWORD dwFailures = 0;
  721. PTAGGED_ADDRESS pTaggedAddress;
  722. LockNetworkMap();
  723. //
  724. // Check the accessiblilty of up
  725. // to three addresses to
  726. // determine if the network is up.
  727. //
  728. if (!pNetworkMapEntry->bUp) {
  729. for (pEntry = pNetworkMapEntry->listEntry.Flink;
  730. pEntry != &pNetworkMapEntry->listEntry;
  731. pEntry = pEntry->Flink)
  732. {
  733. pTaggedAddress = CONTAINING_RECORD(pEntry, TAGGED_ADDRESS, listEntry);
  734. if (IsAddressAccessible(
  735. pCheckNetworkInfo->pszNbDevices,
  736. pCheckNetworkInfo->dwcNbDevices,
  737. pCheckNetworkInfo->fDns,
  738. pTaggedAddress->pszAddress))
  739. {
  740. pNetworkMapEntry->bUp = TRUE;
  741. NetworkMapG.dwcUpNetworks++;
  742. break;
  743. }
  744. //
  745. // Sanity check to see if the pEntry is
  746. // still valid - since IsAddressAccessible
  747. // releases the network map lock.
  748. //
  749. {
  750. PLIST_ENTRY pEntryT;
  751. for (pEntryT = pNetworkMapEntry->listEntry.Flink;
  752. pEntryT != &pNetworkMapEntry->listEntry;
  753. pEntryT = pEntryT->Flink)
  754. {
  755. if(pEntryT == pEntry)
  756. {
  757. RASAUTO_TRACE("CheckNetworkMap: Entry valid");
  758. break;
  759. }
  760. }
  761. if(pEntryT != pEntry)
  762. {
  763. RASAUTO_TRACE1("CheckNetworkMap: Entry %p is invalid!",
  764. pEntry);
  765. break;
  766. }
  767. }
  768. if (dwFailures++ > 2)
  769. break;
  770. }
  771. }
  772. RASAUTO_TRACE3(
  773. "CheckNetwork: %S is %s (NetworkMapG.dwcUpNetworks=%d",
  774. pszNetwork,
  775. pNetworkMapEntry->bUp ? "up" : "down",
  776. NetworkMapG.dwcUpNetworks);
  777. UnlockNetworkMap();
  778. return TRUE;
  779. } // CheckNetwork
  780. BOOLEAN
  781. MarkNetworkDown(
  782. IN PVOID pArg,
  783. IN LPTSTR pszNetwork,
  784. IN PVOID pData
  785. )
  786. {
  787. PNETWORK_MAP_ENTRY pNetworkMapEntry = (PNETWORK_MAP_ENTRY)pData;
  788. pNetworkMapEntry->bUp = FALSE;
  789. pNetworkMapEntry->dwConnectionTag = 0;
  790. return TRUE;
  791. } // MarkNetworkDown
  792. DWORD
  793. AcsCheckNetworkThread(
  794. LPVOID lpArg
  795. )
  796. {
  797. PCHECK_NETWORK_INFO pCheckNetworkInfo = (PCHECK_NETWORK_INFO)lpArg;
  798. RASAUTO_TRACE("AcsCheckNetworkThread");
  799. EnumTable(NetworkMapG.pTable, CheckNetwork, pCheckNetworkInfo);
  800. return 0;
  801. } // AcsCheckNetworkThread
  802. BOOLEAN
  803. UpdateNetworkMap(
  804. IN BOOLEAN bForce
  805. )
  806. {
  807. LPTSTR *pszNbDevices = NULL;
  808. DWORD i, dwcConnections, dwcNbDevices = 0;
  809. LPTSTR pszNetwork, *lpActiveEntries = NULL;
  810. LPTSTR pszDnsAddresses;
  811. HRASCONN *lphRasconns = NULL;
  812. PNETWORK_MAP_ENTRY pNetworkMapEntry;
  813. CHECK_NETWORK_INFO checkNetworkInfo;
  814. HANDLE hThread;
  815. DWORD dwThreadId;
  816. BOOL fLockAcquired = FALSE;
  817. LockNetworkMap();
  818. fLockAcquired = TRUE;
  819. //
  820. // If the previous number of RAS connections
  821. // equals the current number of RAS connections,
  822. // then don't waste our time.
  823. //
  824. dwcConnections = ActiveConnections(TRUE, &lpActiveEntries, &lphRasconns);
  825. if (!bForce && dwcConnections == NetworkMapG.dwcConnections) {
  826. RASAUTO_TRACE1("UpdateNetworkMap: no change (%d connections)", dwcConnections);
  827. goto done;
  828. }
  829. //
  830. // Allocate the Netbios device array up front.
  831. //
  832. pszNbDevices = (LPTSTR *)LocalAlloc(
  833. LPTR,
  834. (dwcConnections + 1) *
  835. sizeof (LPTSTR));
  836. if (pszNbDevices == NULL) {
  837. RASAUTO_TRACE("UpdateNetworkMap: LocalAlloc failed");
  838. goto done;
  839. }
  840. pszNbDevices[0] = GetPrimaryNetbiosDevice();
  841. if (pszNbDevices[0] != NULL)
  842. dwcNbDevices++;
  843. //
  844. // Wait up to 3 seconds for the new
  845. // DNS servers to get set. Otherwise,
  846. // we may get inaccurate results from
  847. // subsequent Winsock getxbyy calls.
  848. //
  849. if (dwcConnections != NetworkMapG.dwcConnections) {
  850. for (i = 0; i < 3; i++) {
  851. BOOLEAN bChanged;
  852. pszDnsAddresses = DnsAddresses();
  853. RASAUTO_TRACE2(
  854. "UpdateNetworkMap: old DNS=%S, new DNS=%S",
  855. RASAUTO_TRACESTRW(NetworkMapG.pszDnsAddresses),
  856. RASAUTO_TRACESTRW(pszDnsAddresses));
  857. bChanged = (pszDnsAddresses != NULL && NetworkMapG.pszDnsAddresses != NULL) ?
  858. wcscmp(pszDnsAddresses, NetworkMapG.pszDnsAddresses) :
  859. (pszDnsAddresses != NULL || NetworkMapG.pszDnsAddresses != NULL);
  860. if (bChanged) {
  861. if (NetworkMapG.pszDnsAddresses != NULL)
  862. LocalFree(NetworkMapG.pszDnsAddresses);
  863. NetworkMapG.pszDnsAddresses = pszDnsAddresses;
  864. break;
  865. }
  866. LocalFree(pszDnsAddresses);
  867. Sleep(1000);
  868. }
  869. }
  870. else if (bForce && NetworkMapG.pszDnsAddresses == NULL)
  871. NetworkMapG.pszDnsAddresses = DnsAddresses();
  872. //
  873. //
  874. NetworkMapG.dwcConnections = dwcConnections;
  875. NetworkMapG.dwConnectionTag = 0;
  876. //
  877. // Mark all networks as down initially.
  878. //
  879. NetworkMapG.dwcUpNetworks = dwcNbDevices;
  880. EnumTable(NetworkMapG.pTable, MarkNetworkDown, NULL);
  881. //
  882. // Enumerate the connected phonebook entries
  883. // and automatically mark those networks as
  884. // connected.
  885. //
  886. for (i = 0; i < dwcConnections; i++) {
  887. pszNetwork = EntryToNetwork(lpActiveEntries[i]);
  888. RASAUTO_TRACE2(
  889. "UpdateNetworkMap: entry %S, network %S is connected",
  890. lpActiveEntries[i],
  891. RASAUTO_TRACESTRW(pszNetwork));
  892. //
  893. // Increment the number of up networks.
  894. //
  895. NetworkMapG.dwcUpNetworks++;
  896. if (pszNetwork != NULL) {
  897. pNetworkMapEntry = GetNetworkMapEntry(pszNetwork);
  898. if (pNetworkMapEntry != NULL) {
  899. pNetworkMapEntry->bUp = TRUE;
  900. RASAUTO_TRACE2(
  901. "UpdateNetworkMap: network %S is up (dwcUpNetworks=%d)",
  902. pszNetwork,
  903. NetworkMapG.dwcUpNetworks);
  904. }
  905. LocalFree(pszNetwork);
  906. }
  907. else {
  908. //
  909. // Add a Netbios device associated with
  910. // this phonebook entry to the list
  911. // of Netbios devices representing unknown
  912. // networks so we can do FIND NAME
  913. // requests on them below.
  914. //
  915. pszNbDevices[dwcNbDevices] = GetNetbiosDevice(lphRasconns[i]);
  916. if (pszNbDevices[dwcNbDevices] != NULL)
  917. dwcNbDevices++;
  918. }
  919. }
  920. UnlockNetworkMap();
  921. fLockAcquired = FALSE;
  922. //
  923. // Now go through all the networks that are
  924. // not associated with a connected phonebook
  925. // entry and see if they are connected (via
  926. // a netcard). We need to do this in a new
  927. // thread because only new Winsock threads
  928. // will get the new DNS server addresses.
  929. //
  930. checkNetworkInfo.pszNbDevices = pszNbDevices;
  931. checkNetworkInfo.dwcNbDevices = dwcNbDevices;
  932. checkNetworkInfo.fDns = PingAddressList(NetworkMapG.pszDnsAddresses);
  933. RASAUTO_TRACE1(
  934. "UpdateNetworkMap: DNS is %s",
  935. checkNetworkInfo.fDns ? "up" : "down");
  936. hThread = CreateThread(
  937. NULL,
  938. 10000L,
  939. (LPTHREAD_START_ROUTINE)AcsCheckNetworkThread,
  940. &checkNetworkInfo,
  941. 0,
  942. &dwThreadId);
  943. if (hThread == NULL) {
  944. RASAUTO_TRACE1(
  945. "UpdateNetworkMap: CreateThread failed (error=0x%x)",
  946. GetLastError());
  947. goto done;
  948. }
  949. //
  950. // Wait for the thread to terminate.
  951. //
  952. RASAUTO_TRACE("UpdateNetworkMap: waiting for AcsCheckNetworkThread to terminate...");
  953. WaitForSingleObject(hThread, INFINITE);
  954. RASAUTO_TRACE1(
  955. "UpdateNetworkMap: AcsCheckNetworkThread done (NetworkMapG.dwcUpNetworks=%d",
  956. NetworkMapG.dwcUpNetworks);
  957. CloseHandle(hThread);
  958. done:
  959. if(fLockAcquired)
  960. UnlockNetworkMap();
  961. if (lpActiveEntries != NULL)
  962. FreeStringArray(lpActiveEntries, dwcConnections);
  963. if (lphRasconns != NULL)
  964. LocalFree(lphRasconns);
  965. if (pszNbDevices != NULL)
  966. FreeStringArray(pszNbDevices, dwcNbDevices);
  967. return TRUE;
  968. } // UpdateNetworkMap
  969. BOOLEAN
  970. GetNetworkConnected(
  971. IN LPTSTR pszNetwork,
  972. OUT PBOOLEAN pbConnected
  973. )
  974. {
  975. PNETWORK_MAP_ENTRY pNetworkMapEntry;
  976. pNetworkMapEntry = GetNetworkMapEntry(pszNetwork);
  977. if (pNetworkMapEntry == NULL)
  978. return FALSE;
  979. *pbConnected = pNetworkMapEntry->bUp;
  980. RASAUTO_TRACE2("GetNetworkConnected: %S is %d", pszNetwork, *pbConnected);
  981. return TRUE;
  982. } // GetNetworkConnected
  983. BOOLEAN
  984. SetNetworkConnected(
  985. IN LPTSTR pszNetwork,
  986. IN BOOLEAN bConnected
  987. )
  988. {
  989. PNETWORK_MAP_ENTRY pNetworkMapEntry;
  990. pNetworkMapEntry = GetNetworkMapEntry(pszNetwork);
  991. if (pNetworkMapEntry != NULL)
  992. pNetworkMapEntry->bUp = bConnected;
  993. if (bConnected)
  994. NetworkMapG.dwcUpNetworks++;
  995. else
  996. NetworkMapG.dwcUpNetworks--;
  997. RASAUTO_TRACE3(
  998. "SetNetworkConnected: %S is %d (dwcUpNetworks=%d)",
  999. RASAUTO_TRACESTRW(pszNetwork),
  1000. bConnected,
  1001. NetworkMapG.dwcUpNetworks);
  1002. return TRUE;
  1003. } // SetNetworkConnected
  1004. DWORD
  1005. GetNetworkConnectionTag(
  1006. IN LPTSTR pszNetwork,
  1007. IN BOOLEAN bIncrement
  1008. )
  1009. {
  1010. PNETWORK_MAP_ENTRY pNetworkMapEntry = NULL;
  1011. DWORD dwTag;
  1012. if (pszNetwork != NULL)
  1013. pNetworkMapEntry = GetNetworkMapEntry(pszNetwork);
  1014. if (bIncrement) {
  1015. dwTag = (pNetworkMapEntry == NULL) ?
  1016. NetworkMapG.dwConnectionTag++ :
  1017. pNetworkMapEntry->dwConnectionTag++;
  1018. }
  1019. else {
  1020. dwTag = (pNetworkMapEntry == NULL) ?
  1021. NetworkMapG.dwConnectionTag :
  1022. pNetworkMapEntry->dwConnectionTag;
  1023. }
  1024. RASAUTO_TRACE2(
  1025. "GetNetworkConnectionTag: network=%S, tag=%d",
  1026. RASAUTO_TRACESTRW(pszNetwork),
  1027. dwTag);
  1028. return dwTag;
  1029. } // GetNetworkConnectionTag
  1030. BOOLEAN
  1031. IsNetworkConnected(VOID)
  1032. {
  1033. BOOLEAN bConnected;
  1034. LockNetworkMap();
  1035. bConnected = (NetworkMapG.dwcUpNetworks > 0);
  1036. RASAUTO_TRACE1("IsNetworkConnected: dwcUpNetworks=%d", NetworkMapG.dwcUpNetworks);
  1037. UnlockNetworkMap();
  1038. return bConnected;
  1039. } // IsNetworkConnected
  1040. VOID
  1041. UninitializeNetworkMap(VOID)
  1042. {
  1043. DeleteCriticalSection(&NetworkMapG.csLock);
  1044. }