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.

1158 lines
34 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997.
  5. //
  6. // File: L A N C M N . C P P
  7. //
  8. // Contents: Implementation of LAN Connection related functions common
  9. // to the shell and netman.
  10. //
  11. // Notes:
  12. //
  13. // Author: danielwe 7 Oct 1997
  14. //
  15. //----------------------------------------------------------------------------
  16. #include <pch.h>
  17. #pragma hdrstop
  18. #include <winsock2.h>
  19. #include <mswsock.h>
  20. #include <iphlpapi.h>
  21. #include "lancmn.h"
  22. #include "ncnetcfg.h"
  23. #include "ncnetcon.h"
  24. #include "ncreg.h"
  25. #include "ncstring.h"
  26. #include "netconp.h"
  27. #include "ndispnp.h"
  28. #include "naming.h"
  29. extern const DECLSPEC_SELECTANY WCHAR c_szConnName[] = L"Name";
  30. extern const DECLSPEC_SELECTANY WCHAR c_szRegKeyConFmt[] = L"System\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\%s\\Connection";
  31. extern const DECLSPEC_SELECTANY WCHAR c_szRegKeyIrdaFmt[] = L"System\\CurrentControlSet\\Control\\Network\\{6BDD1FC5-810F-11D0-BEC7-08002BE2092F}\\%s\\Connection";
  32. extern const DECLSPEC_SELECTANY WCHAR c_szRegKeyHwConFmt[] = L"System\\CurrentControlSet\\Control\\Network\\Connections\\%s";
  33. extern const DECLSPEC_SELECTANY WCHAR c_szRegValuePnpInstanceId[] = L"PnpInstanceID";
  34. extern const DECLSPEC_SELECTANY WCHAR c_szRegKeyNetworkAdapters[] = L"System\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002bE10318}";
  35. extern const DECLSPEC_SELECTANY WCHAR c_szRegValueNetCfgInstanceId[] = L"NetCfgInstanceId";
  36. extern const DECLSPEC_SELECTANY WCHAR c_szRegValueMediaSubType[] = L"MediaSubType";
  37. //
  38. // Helper functions
  39. //
  40. //+---------------------------------------------------------------------------
  41. //
  42. // Function: HrOpenConnectionKey
  43. //
  44. // Purpose: Opens the "Connection" subkey under the gievn connection
  45. // GUID.
  46. //
  47. // Arguments:
  48. // pguid [in] GUID of net card in use by the connection
  49. // pszGuid [in] String version of GUID of net card in use by
  50. // the connection
  51. // sam [in] SAM desired
  52. // occFlags [in] Flags determining how to open the key
  53. // pszPnpId [in] The Pnp id of the net card in use by the
  54. // connection. This is used if the key is created.
  55. // phkey [out] Returns hkey of connection subkey
  56. //
  57. // Returns: S_OK if success, OLE or Win32 error otherwise.
  58. //
  59. // Author: danielwe 7 Oct 1997
  60. //
  61. // Notes: Only pguid or pszGuid should be specified, not both. Specifying
  62. // both will result in an E_INVALIDARG error
  63. //
  64. //
  65. HRESULT
  66. HrOpenConnectionKey (
  67. IN const GUID* pguid,
  68. IN PCWSTR pszGuid,
  69. IN REGSAM sam,
  70. IN OCC_FLAGS occFlags,
  71. IN PCWSTR pszPnpId,
  72. OUT HKEY *phkey)
  73. {
  74. HRESULT hr = S_OK;
  75. WCHAR szRegPath[256];
  76. WCHAR szGuid[c_cchGuidWithTerm];
  77. Assert(phkey);
  78. Assert(pguid || (pszGuid && *pszGuid));
  79. Assert(!(pguid && pszGuid));
  80. Assert (FImplies (OCCF_CREATE_IF_NOT_EXIST == occFlags, pszPnpId && *pszPnpId));
  81. *phkey = NULL;
  82. if (pguid)
  83. {
  84. StringFromGUID2(*pguid, szGuid, c_cchGuidWithTerm);
  85. pszGuid = szGuid;
  86. }
  87. wsprintfW(szRegPath, c_szRegKeyConFmt, pszGuid);
  88. if (occFlags & OCCF_CREATE_IF_NOT_EXIST)
  89. {
  90. DWORD dwDisp;
  91. hr = HrRegCreateKeyEx(HKEY_LOCAL_MACHINE, szRegPath, 0,
  92. sam, NULL, phkey, &dwDisp);
  93. if ((S_OK == hr))
  94. {
  95. DWORD dwMediaSubType;
  96. // Store the pnp instance id as our back pointer to the pnp tree.
  97. //
  98. hr = HrRegSetSz (*phkey, c_szRegValuePnpInstanceId, pszPnpId);
  99. TraceError("HrRegSetSz in HrOpenConnectionKey failed.", hr);
  100. HRESULT hrT = HrRegQueryDword(*phkey, c_szRegValueMediaSubType, &dwMediaSubType);
  101. if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hrT)
  102. {
  103. CIntelliName inName(NULL, NULL);
  104. NETCON_MEDIATYPE ncMediaType = NCM_NONE;
  105. NETCON_SUBMEDIATYPE ncMediaSubType = NCSM_NONE;
  106. hrT = inName.HrGetPseudoMediaTypes(*pguid, &ncMediaType, &ncMediaSubType);
  107. if (SUCCEEDED(hrT) && (NCSM_LAN != ncMediaSubType) )
  108. {
  109. hrT = HrRegSetDword(*phkey, c_szRegValueMediaSubType, ncMediaSubType);
  110. }
  111. }
  112. TraceError("Could not set media subtype for adapter", hrT);
  113. }
  114. }
  115. else if (occFlags & OCCF_DELETE_IF_EXIST)
  116. {
  117. if (wcslen(szGuid) > 0)
  118. {
  119. wcscpy(szRegPath, c_szRegKeyNetworkAdapters);
  120. wcscat(szRegPath, L"\\");
  121. wcscat(szRegPath, szGuid);
  122. hr = HrRegDeleteKeyTree(HKEY_LOCAL_MACHINE, szRegPath);
  123. }
  124. }
  125. else
  126. {
  127. hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, szRegPath, sam, phkey);
  128. }
  129. TraceErrorOptional("HrOpenConnectionKey", hr,
  130. HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr);
  131. return hr;
  132. }
  133. //+---------------------------------------------------------------------------
  134. //
  135. // Function: HrOpenHwConnectionKey
  136. //
  137. // Purpose: Opens the per-hardware profile registry key for this connection
  138. //
  139. // Arguments:
  140. // refGuid [in] GUID of net card in use by the connection
  141. // sam [in] SAM desired
  142. // occFlags [in] Flags determining how to open the key
  143. // phkey [out] Returns hkey of connection subkey
  144. //
  145. // Returns: S_OK if success, OLE or Win32 error otherwise.
  146. //
  147. // Author: danielwe 9 Oct 1997
  148. //
  149. // Notes:
  150. //
  151. HRESULT
  152. HrOpenHwConnectionKey(
  153. REFGUID refGuid,
  154. REGSAM sam,
  155. OCC_FLAGS occFlags,
  156. HKEY *phkey)
  157. {
  158. HRESULT hr = S_OK;
  159. WCHAR szRegPath[256];
  160. WCHAR szGuid[c_cchGuidWithTerm];
  161. Assert(phkey);
  162. *phkey = NULL;
  163. StringFromGUID2(refGuid, szGuid, c_cchGuidWithTerm);
  164. wsprintfW(szRegPath, c_szRegKeyHwConFmt, szGuid);
  165. if (occFlags & OCCF_CREATE_IF_NOT_EXIST)
  166. {
  167. DWORD dwDisp;
  168. hr = HrRegCreateKeyEx(HKEY_CURRENT_CONFIG, szRegPath, 0,
  169. sam, NULL, phkey, &dwDisp);
  170. }
  171. else
  172. {
  173. hr = HrRegOpenKeyEx(HKEY_CURRENT_CONFIG, szRegPath, sam, phkey);
  174. }
  175. TraceError("HrOpenHwConnectionKey", hr);
  176. return hr;
  177. }
  178. //+---------------------------------------------------------------------------
  179. //
  180. // Function: HrIsConnectionNameUnique
  181. //
  182. // Purpose: Returns whether or not the given connection name is unique.
  183. //
  184. // Arguments:
  185. // guidExclude [in,ref] Device GUID of Connection to exclude from
  186. // consideration (can be {0})
  187. // pszName [in] Name to verify for uniqueness
  188. //
  189. // Returns: S_OK if name is unique, S_FALSE if it is a duplicate, or OLE
  190. // or Win32 error otherwise
  191. //
  192. // Author: danielwe 14 Nov 1997
  193. //
  194. // Notes:
  195. //
  196. HRESULT
  197. HrIsConnectionNameUnique(
  198. REFGUID guidExclude,
  199. PCWSTR pszName)
  200. {
  201. Assert(pszName);
  202. BOOL fDupe = FALSE;
  203. // Iterate all LAN connections
  204. //
  205. INetConnectionManager * pconMan;
  206. HRESULT hr = HrCreateInstance(CLSID_LanConnectionManager,
  207. CLSCTX_SERVER | CLSCTX_NO_CODE_DOWNLOAD, &pconMan);
  208. TraceHr(ttidError, FAL, hr, FALSE, "HrCreateInstance");
  209. if (SUCCEEDED(hr))
  210. {
  211. CIterNetCon ncIter(pconMan, NCME_DEFAULT);
  212. INetConnection * pconn;
  213. while (SUCCEEDED(hr) && !fDupe &&
  214. (S_OK == (ncIter.HrNext(&pconn))))
  215. {
  216. // Exclude if GUID passed in matches this connection's GUID.
  217. //
  218. if (!FPconnEqualGuid(pconn, guidExclude))
  219. {
  220. NETCON_PROPERTIES* pProps;
  221. hr = pconn->GetProperties(&pProps);
  222. if (SUCCEEDED(hr))
  223. {
  224. AssertSz(pProps->pszwName, "NULL pszwName!");
  225. if (!lstrcmpiW(pProps->pszwName, pszName))
  226. {
  227. // Names match.. This is a dupe.
  228. fDupe = TRUE;
  229. }
  230. FreeNetconProperties(pProps);
  231. }
  232. }
  233. ReleaseObj(pconn);
  234. }
  235. ReleaseObj(pconMan);
  236. }
  237. if (SUCCEEDED(hr))
  238. {
  239. hr = fDupe ? S_FALSE : S_OK;
  240. }
  241. TraceErrorOptional("HrIsConnectionNameUnique", hr, (S_FALSE == hr));
  242. return hr;
  243. }
  244. //+---------------------------------------------------------------------------
  245. //
  246. // Function: HrLanConnectionNameFromGuidOrPath
  247. //
  248. // Purpose: Retrieves the display-name of a LAN connection given its GUID.
  249. //
  250. // Arguments:
  251. // guid [in] GUID of net card in question
  252. // pszPath [in] Bind path that contains the GUID of the net
  253. // card in question
  254. // pszName [out] receives the retrieved name
  255. // pcchMax [inout] indicates the capacity of 'pszName' on input,
  256. // contains the required capacity on output.
  257. //
  258. // Returns: S_OK if success, OLE or Win32 error otherwise.
  259. //
  260. // Author: aboladeg 30 May 1998
  261. //
  262. // Notes: Only pguid or pszGuidPath should be specified, not both.
  263. // Specifying both will result in an E_INVALIDARG error
  264. //
  265. EXTERN_C
  266. HRESULT
  267. WINAPI
  268. HrLanConnectionNameFromGuidOrPath(
  269. const GUID* pguid,
  270. PCWSTR pszPath,
  271. PWSTR pszName,
  272. LPDWORD pcchMax)
  273. {
  274. HRESULT hr = S_OK;
  275. Assert(pcchMax);
  276. // If neither a guid nor a path was specified then return an error.
  277. //
  278. if (!pguid && (!pszPath || !*pszPath))
  279. {
  280. hr = E_INVALIDARG;
  281. }
  282. // If both pguid and a path were specified then return an error.
  283. //
  284. else if (pguid && (pszPath && *pszPath))
  285. {
  286. hr = E_INVALIDARG;
  287. }
  288. else
  289. {
  290. WCHAR szGuid [c_cchGuidWithTerm];
  291. PCWSTR pszGuid = NULL;
  292. // If we don't have pguid, it means we are to parset if from
  293. // pszPath.
  294. //
  295. if (!pguid)
  296. {
  297. Assert(pszPath && *pszPath);
  298. // Search for the beginning brace of the supposed GUID and
  299. // copy the remaining characters into szGuid.
  300. // If no guid is found, return file not found since
  301. // there will be no connection name found.
  302. //
  303. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  304. for (const WCHAR* pch = pszPath; *pch; pch++)
  305. {
  306. if (*pch == L'{')
  307. {
  308. wcsncpy (szGuid, pch, celems(szGuid)-1);
  309. szGuid[celems(szGuid)-1] = 0;
  310. pszGuid = szGuid;
  311. hr = S_OK;
  312. break;
  313. }
  314. }
  315. }
  316. if (S_OK == hr)
  317. {
  318. HKEY hkey;
  319. hr = HrOpenConnectionKey(pguid, pszGuid, KEY_READ,
  320. OCCF_NONE, NULL, &hkey);
  321. if (S_OK == hr)
  322. {
  323. DWORD dwType;
  324. *pcchMax *= sizeof(WCHAR);
  325. hr = HrRegQueryValueEx(hkey, c_szConnName, &dwType,
  326. (LPBYTE)pszName, pcchMax);
  327. *pcchMax /= sizeof(WCHAR);
  328. RegCloseKey(hkey);
  329. }
  330. }
  331. }
  332. TraceError("HrLanConnectionNameFromGuid",
  333. (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) ? S_OK : hr);
  334. return hr;
  335. }
  336. //+---------------------------------------------------------------------------
  337. //
  338. // Function: HrPnccFromGuid
  339. //
  340. // Purpose: Given a GUID of an adapter, returns the INetCfgComponent
  341. // that corresponds to it.
  342. //
  343. // Arguments:
  344. // pnc [in] INetCfg to work with
  345. // refGuid [in] GUID of adapter to look for
  346. // ppncc [out] Returns INetCfgComponent already AddRef'd
  347. //
  348. // Returns: S_OK if found, S_FALSE if not (out param will be NULL), or
  349. // OLE or Win32 error otherwise
  350. //
  351. // Author: danielwe 6 Nov 1997
  352. //
  353. // Notes: Caller should ReleaseObj the returned pointer
  354. //
  355. HRESULT HrPnccFromGuid(INetCfg *pnc, const GUID &refGuid,
  356. INetCfgComponent **ppncc)
  357. {
  358. HRESULT hr = S_OK;
  359. Assert(pnc);
  360. if (!ppncc)
  361. {
  362. hr = E_POINTER;
  363. }
  364. else
  365. {
  366. *ppncc = NULL;
  367. BOOL fFound = FALSE;
  368. CIterNetCfgComponent nccIter(pnc, &GUID_DEVCLASS_NET);
  369. INetCfgComponent * pncc;
  370. while (!fFound && SUCCEEDED(hr) &&
  371. S_OK == (hr = nccIter.HrNext(&pncc)))
  372. {
  373. GUID guidTest;
  374. hr = pncc->GetInstanceGuid(&guidTest);
  375. if (S_OK == hr)
  376. {
  377. if (guidTest == refGuid)
  378. {
  379. // Found our adapter
  380. fFound = TRUE;
  381. // Give another reference so it's not released down below
  382. AddRefObj(pncc);
  383. *ppncc = pncc;
  384. Assert (S_OK == hr);
  385. }
  386. }
  387. ReleaseObj(pncc);
  388. }
  389. if (SUCCEEDED(hr) && !fFound)
  390. {
  391. hr = S_FALSE;
  392. }
  393. }
  394. TraceErrorOptional("HrPnccFromGuid", hr, (S_FALSE == hr));
  395. return hr;
  396. }
  397. //+---------------------------------------------------------------------------
  398. //
  399. // Function: HrIsConnection
  400. //
  401. // Purpose: Determines whether the given component has an associated
  402. // LAN connection.
  403. //
  404. // Arguments:
  405. // pncc [in] Component to test
  406. //
  407. // Returns: S_OK if it does, S_FALSE if not, otherwise a Win32 error code
  408. //
  409. // Author: danielwe 2 Oct 1997
  410. //
  411. // Notes:
  412. //
  413. HRESULT HrIsConnection(INetCfgComponent *pncc)
  414. {
  415. HRESULT hr = S_FALSE;
  416. GUID guid;
  417. Assert(pncc);
  418. // Get the component instance GUID
  419. //
  420. hr = pncc->GetInstanceGuid(&guid);
  421. if (SUCCEEDED(hr))
  422. {
  423. HKEY hkey;
  424. // Check for the existence of the connection sub-key
  425. hr = HrOpenConnectionKey(&guid, NULL, KEY_READ,
  426. OCCF_NONE, NULL, &hkey);
  427. if (SUCCEEDED(hr))
  428. {
  429. RegCloseKey(hkey);
  430. }
  431. else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
  432. {
  433. // Key not there, return FALSE
  434. hr = S_FALSE;
  435. }
  436. }
  437. TraceErrorOptional("HrIsConnection", hr, (S_FALSE == hr));
  438. return hr;
  439. }
  440. //+---------------------------------------------------------------------------
  441. //
  442. // Function: HrGetDeviceGuid
  443. //
  444. // Purpose: Given a LAN connection object, returns the device GUID
  445. // associated with it.
  446. //
  447. // Arguments:
  448. // pconn [in] LAN connection object
  449. // pguid [out] Returns device GUID
  450. //
  451. // Returns: S_OK if success, OLE or Win32 error if failed
  452. //
  453. // Author: danielwe 23 Dec 1997
  454. //
  455. // Notes:
  456. //
  457. HRESULT HrGetDeviceGuid(INetConnection *pconn, GUID *pguid)
  458. {
  459. HRESULT hr = S_OK;
  460. INetLanConnection * plan = NULL;
  461. Assert(pguid);
  462. hr = HrQIAndSetProxyBlanket(pconn, &plan);
  463. if (SUCCEEDED(hr))
  464. {
  465. hr = plan->GetDeviceGuid(pguid);
  466. ReleaseObj(plan);
  467. }
  468. TraceError("HrGetDeviceGuid", hr);
  469. return hr;
  470. }
  471. //+---------------------------------------------------------------------------
  472. //
  473. // Function: FPconnEqualGuid
  474. //
  475. // Purpose: Determines if the given connection's device GUID matches the
  476. // guid passed in.
  477. //
  478. // Arguments:
  479. // pconn [in] Connection object to examine (must be a LAN connection)
  480. // guid [in,ref] Guid to compare with
  481. //
  482. // Returns: TRUE if connection's device guid matches passed in guid, FALSE
  483. // if not.
  484. //
  485. // Author: danielwe 23 Dec 1997
  486. //
  487. // Notes:
  488. //
  489. BOOL FPconnEqualGuid(INetConnection *pconn, REFGUID guid)
  490. {
  491. HRESULT hr = S_OK;
  492. GUID guidDev;
  493. BOOL fRet = FALSE;
  494. hr = HrGetDeviceGuid(pconn, &guidDev);
  495. if (SUCCEEDED(hr))
  496. {
  497. fRet = (guidDev == guid);
  498. }
  499. TraceError("FPconnEqualGuid", hr);
  500. return fRet;
  501. }
  502. //+---------------------------------------------------------------------------
  503. //
  504. // Function: HrPnpInstanceIdFromGuid
  505. //
  506. // Purpose: Given a GUID of a network device, returns its PnP Instance ID
  507. //
  508. // Arguments:
  509. // pguid [in] NetCfg instance GUID of device
  510. // pszInstance [out] PnP instance ID (string)
  511. //
  512. // Returns: S_OK if success, Win32 error code otherwise
  513. //
  514. // Author: danielwe 30 Oct 1998
  515. //
  516. // Notes:
  517. //
  518. HRESULT
  519. HrPnpInstanceIdFromGuid(
  520. const GUID* pguid,
  521. PWSTR pszInstance,
  522. UINT cchInstance)
  523. {
  524. HRESULT hr = S_OK;
  525. WCHAR szRegPath[MAX_PATH];
  526. HKEY hkey;
  527. DWORD cb;
  528. WCHAR szGuid[c_cchGuidWithTerm];
  529. StringFromGUID2(*pguid, szGuid, c_cchGuidWithTerm);
  530. wsprintfW(szRegPath, c_szRegKeyConFmt, szGuid);
  531. hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, szRegPath, KEY_READ, &hkey);
  532. if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
  533. {
  534. wsprintfW(szRegPath, c_szRegKeyIrdaFmt, szGuid);
  535. hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, szRegPath, KEY_READ, &hkey);
  536. }
  537. if (S_OK == hr)
  538. {
  539. cb = cchInstance * sizeof(WCHAR);
  540. hr = HrRegQuerySzBuffer(hkey, c_szRegValuePnpInstanceId,
  541. pszInstance, &cb);
  542. RegCloseKey(hkey);
  543. }
  544. #ifdef ENABLETRACE
  545. if (FAILED(hr))
  546. {
  547. TraceHr (ttidError, FAL, hr, IsEqualGUID(*pguid, GUID_NULL), "HrPnpInstanceIdFromGuid "
  548. "failed getting id for %S", szGuid);
  549. }
  550. #endif
  551. TraceHr (ttidError, FAL, hr,
  552. HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr,
  553. "HrPnpInstanceIdFromGuid");
  554. return hr;
  555. }
  556. //+---------------------------------------------------------------------------
  557. //
  558. // Function: HrGetPnpDeviceStatus
  559. //
  560. // Purpose: Given a network device GUID, returns its status
  561. //
  562. // Arguments:
  563. // pguid [in] NetCfg instance GUID of network device
  564. // pStatus [out] Status of device
  565. //
  566. // Returns: S_OK if success, Win32 error code otherwise
  567. //
  568. // Author: danielwe 30 Oct 1998
  569. //
  570. // Notes:
  571. //
  572. EXTERN_C
  573. HRESULT
  574. WINAPI
  575. HrGetPnpDeviceStatus(
  576. const GUID* pguid,
  577. NETCON_STATUS *pStatus)
  578. {
  579. HRESULT hr = S_OK;
  580. if (!pStatus || !pguid)
  581. {
  582. hr = E_POINTER;
  583. goto err;
  584. }
  585. WCHAR szInstance[MAX_PATH];
  586. hr = HrPnpInstanceIdFromGuid(pguid, szInstance, celems(szInstance));
  587. if (SUCCEEDED(hr))
  588. {
  589. DEVINST devinst;
  590. CONFIGRET cr;
  591. cr = CM_Locate_DevNode(&devinst, szInstance,
  592. CM_LOCATE_DEVNODE_NORMAL);
  593. if (CR_SUCCESS == cr)
  594. {
  595. hr = HrGetDevInstStatus(devinst, pguid, pStatus);
  596. }
  597. else if (CR_NO_SUCH_DEVNODE == cr)
  598. {
  599. // If the devnode doesn't exist, the hardware is not physically
  600. // present
  601. //
  602. *pStatus = NCS_HARDWARE_NOT_PRESENT;
  603. }
  604. }
  605. err:
  606. TraceError("HrGetPnpDeviceStatus", hr);
  607. return hr;
  608. }
  609. extern const WCHAR c_szDevice[];
  610. //+---------------------------------------------------------------------------
  611. //
  612. // Function: HrQueryLanMediaState
  613. //
  614. // Purpose: Determines as best as can be basically whether the cable is
  615. // plugged in to the network card.
  616. //
  617. // Arguments:
  618. // pguid [in] GUID of device to tes
  619. // pfEnabled [out] Returns TRUE if media is connected, FALSE if not
  620. //
  621. // Returns: S_OK if success, Win32 error otherwise
  622. //
  623. // Author: danielwe 13 Nov 1998
  624. //
  625. // Notes:
  626. //
  627. EXTERN_C
  628. HRESULT
  629. WINAPI
  630. HrQueryLanMediaState(
  631. const GUID* pguid,
  632. BOOL* pfEnabled)
  633. {
  634. HRESULT hr = S_OK;
  635. if (!pfEnabled)
  636. {
  637. hr = E_POINTER;
  638. }
  639. else
  640. {
  641. UINT uiRet = 0;
  642. NIC_STATISTICS nsNewLanStats = {0};
  643. tstring strDevice;
  644. UNICODE_STRING ustrDevice;
  645. WCHAR szGuid[c_cchGuidWithTerm];
  646. // Initialize to TRUE
  647. //
  648. *pfEnabled = TRUE;
  649. StringFromGUID2(*pguid, szGuid, c_cchGuidWithTerm);
  650. strDevice = c_szDevice;
  651. strDevice.append(szGuid);
  652. RtlInitUnicodeString(&ustrDevice, strDevice.c_str());
  653. nsNewLanStats.Size = sizeof(NIC_STATISTICS);
  654. uiRet = NdisQueryStatistics(&ustrDevice, &nsNewLanStats);
  655. if (uiRet)
  656. {
  657. *pfEnabled = (nsNewLanStats.MediaState == MEDIA_STATE_CONNECTED);
  658. }
  659. else
  660. {
  661. hr = HrFromLastWin32Error();
  662. }
  663. }
  664. TraceHr (ttidError, FAL, hr,
  665. HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr,
  666. "HrQueryLanMediaState");
  667. return hr;
  668. }
  669. //+---------------------------------------------------------------------------
  670. //
  671. // Function: FIsMediaPresent
  672. //
  673. // Purpose: Determines as best as can be basically whether the cable is
  674. // plugged in to the network card.
  675. //
  676. // Arguments:
  677. // pGuid [in] GUID of device to test
  678. //
  679. // Returns: TRUE if media is connected, FALSE otherwise
  680. //
  681. // Author: danielwe 30 Oct 1998
  682. //
  683. // Notes:
  684. //
  685. BOOL
  686. FIsMediaPresent(
  687. const GUID *pguid)
  688. {
  689. BOOL fEnabled;
  690. if (SUCCEEDED(HrQueryLanMediaState(pguid, &fEnabled)))
  691. {
  692. return fEnabled;
  693. }
  694. // Assume media is connected on failure
  695. return TRUE;
  696. }
  697. //+---------------------------------------------------------------------------
  698. //
  699. // Function: HrGetDevInstStatus
  700. //
  701. // Purpose: Determines status of the given Pnp device instance
  702. //
  703. // Arguments:
  704. // devinst [in] PnP device instance
  705. // pGuid [in] GUID of said device
  706. // pStatus [out] Status of device
  707. //
  708. // Returns: S_OK if success, Win32 error code otherwise
  709. //
  710. // Author: danielwe 30 Oct 1998
  711. //
  712. // Notes:
  713. //
  714. HRESULT
  715. HrGetDevInstStatus(
  716. DEVINST devinst,
  717. const GUID* pguid,
  718. NETCON_STATUS* pStatus)
  719. {
  720. HRESULT hr = S_OK;
  721. ULONG ulStatus;
  722. ULONG ulProblem;
  723. CONFIGRET cfgRet;
  724. if (!pguid)
  725. {
  726. return E_INVALIDARG;
  727. }
  728. if (!pStatus)
  729. {
  730. return E_POINTER;
  731. }
  732. cfgRet = CM_Get_DevNode_Status_Ex(&ulStatus, &ulProblem,
  733. devinst, 0, NULL);
  734. if (CR_SUCCESS == cfgRet)
  735. {
  736. TraceTag(ttidLanCon, "CM_Get_DevNode_Status_Ex: ulProblem "
  737. "= 0x%08X, ulStatus = 0x%08X.",
  738. ulProblem, ulStatus);
  739. switch (ulProblem)
  740. {
  741. case 0:
  742. // No problem, we're connected
  743. *pStatus = NCS_CONNECTED;
  744. break;
  745. case CM_PROB_DEVICE_NOT_THERE:
  746. case CM_PROB_MOVED:
  747. // Device not present
  748. *pStatus = NCS_HARDWARE_NOT_PRESENT;
  749. break;
  750. case CM_PROB_HARDWARE_DISABLED:
  751. // Device was disabled via Device Manager
  752. *pStatus = NCS_HARDWARE_DISABLED;
  753. break;
  754. case CM_PROB_DISABLED:
  755. // Device was disconnected
  756. *pStatus = NCS_DISCONNECTED;
  757. break;
  758. default:
  759. // All other problems
  760. *pStatus = NCS_HARDWARE_MALFUNCTION;
  761. break;
  762. }
  763. if (*pStatus == NCS_CONNECTED)
  764. {
  765. // Check DeviceState and MediaState from NdisQueryStatistics
  766. UINT uiRet = 0;
  767. NIC_STATISTICS nsNewLanStats = {0};
  768. tstring strDevice;
  769. UNICODE_STRING ustrDevice;
  770. WCHAR szGuid[c_cchGuidWithTerm];
  771. StringFromGUID2(*pguid, szGuid, c_cchGuidWithTerm);
  772. strDevice = c_szDevice;
  773. strDevice.append(szGuid);
  774. RtlInitUnicodeString(&ustrDevice, strDevice.c_str());
  775. nsNewLanStats.Size = sizeof(NIC_STATISTICS);
  776. uiRet = NdisQueryStatistics(&ustrDevice, &nsNewLanStats);
  777. if (uiRet)
  778. {
  779. // Check MediaState
  780. if (nsNewLanStats.MediaState == MEDIA_STATE_DISCONNECTED)
  781. {
  782. TraceTag(ttidLanCon, "NdisQueryStatistics reports MediaState of "
  783. "device %S is disconnected.", szGuid);
  784. *pStatus = NCS_MEDIA_DISCONNECTED;
  785. }
  786. else
  787. {
  788. HRESULT hrTmp;
  789. BOOL fValidAddress = TRUE;
  790. hrTmp = HrGetAddressStatusForAdapter(pguid, &fValidAddress);
  791. if (SUCCEEDED(hrTmp))
  792. {
  793. if (!fValidAddress)
  794. {
  795. *pStatus = NCS_INVALID_ADDRESS;
  796. INetCfg *pNetCfg = NULL;
  797. BOOL fInitCom = TRUE;
  798. HRESULT hrT = CoInitializeEx(NULL, COINIT_DISABLE_OLE1DDE | COINIT_MULTITHREADED);
  799. if (RPC_E_CHANGED_MODE == hrT)
  800. {
  801. hrT = S_OK;
  802. fInitCom = FALSE;
  803. }
  804. if (SUCCEEDED(hrT))
  805. {
  806. HRESULT hrT = HrCreateAndInitializeINetCfg(NULL, &pNetCfg, FALSE, 0, NULL, NULL);
  807. if (SUCCEEDED(hrT))
  808. {
  809. INetCfgComponent *pNetCfgComponent = NULL;
  810. hrT = HrPnccFromGuid(pNetCfg, *pguid, &pNetCfgComponent);
  811. if (S_OK == hrT)
  812. {
  813. DWORD dwCharacteristics = 0;
  814. pNetCfgComponent->GetCharacteristics(&dwCharacteristics);
  815. if (NCF_VIRTUAL & dwCharacteristics)
  816. {
  817. *pStatus = NCS_CONNECTED;
  818. TraceTag(ttidLanCon, "NCS_INVALID_ADDRESS status ignored for NCF_VIRTUAL device: %S", szGuid);
  819. }
  820. pNetCfgComponent->Release();
  821. }
  822. HrUninitializeAndReleaseINetCfg(FALSE, pNetCfg, FALSE);
  823. }
  824. if (fInitCom)
  825. {
  826. CoUninitialize();
  827. }
  828. }
  829. TraceError("Error retrieving adapter Characteristics", hrT);
  830. }
  831. }
  832. }
  833. }
  834. else
  835. {
  836. // $REVIEW(tongl 11/25/98): This is added to display proper state
  837. // for ATM ELAN virtual miniports (Raid #253972, 256355).
  838. //
  839. // If we get here for a physical adapter, this means NdisQueryStatistics
  840. // returned different device state from CM_Get_DevNode_Status_Ex, we may
  841. // have a problem.
  842. hr = HrFromLastWin32Error();
  843. if ((HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) &&
  844. (nsNewLanStats.DeviceState == DEVICE_STATE_DISCONNECTED))
  845. {
  846. Assert(nsNewLanStats.MediaState == MEDIA_STATE_UNKNOWN);
  847. TraceTag(ttidLanCon, "NdisQueryStatistics reports DeviceState of "
  848. "device %S is disconnected.", szGuid);
  849. *pStatus = NCS_DISCONNECTED;
  850. hr = S_OK;
  851. }
  852. else if (HRESULT_FROM_WIN32(ERROR_NOT_READY) == hr)
  853. {
  854. // This error means that the device went into power
  855. // management induced sleep and so we should report this
  856. // case as media disconnected, not connection disconnected
  857. TraceTag(ttidLanCon, "NdisQueryStatistics reports device"
  858. " %S is asleep. Returning status of media "
  859. "disconnected.", szGuid);
  860. *pStatus = NCS_MEDIA_DISCONNECTED;
  861. hr = S_OK;
  862. }
  863. else if (HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) == hr)
  864. {
  865. TraceTag(ttidLanCon, "NdisQueryStatistics reports device %S is still connecting.",
  866. szGuid);
  867. *pStatus = NCS_CONNECTING;
  868. hr = S_OK;
  869. }
  870. else
  871. {
  872. // Treat as disconected, if we return failure the folder will
  873. // not display this connection at all.
  874. TraceHr (ttidLanCon, FAL, hr, FALSE, "NdisQueryStatistics reports error on device %S",
  875. szGuid);
  876. *pStatus = NCS_DISCONNECTED;
  877. hr = S_OK;
  878. }
  879. }
  880. }
  881. }
  882. TraceError("HrGetDevInstStatus", hr);
  883. return hr;
  884. }
  885. //+---------------------------------------------------------------------------
  886. //
  887. // Function: HasValidAddress
  888. //
  889. // Purpose: Verifies that the given adapter has a valid address
  890. //
  891. // Arguments:
  892. // IN PIP_ADAPTER_INFO pAdapterInfo - Adapter Info structure
  893. // containing addresses
  894. //
  895. // Returns: True if Valid address, False otherwise
  896. //
  897. // Author: ckotze 11 Jan 2001
  898. //
  899. // Notes:
  900. //
  901. //
  902. //
  903. BOOL HasValidAddress(IN PIP_ADAPTER_INFO pAdapterInfo)
  904. {
  905. PIP_ADDR_STRING pAddrString;
  906. unsigned int addr;
  907. TraceFileFunc(ttidConman);
  908. for(pAddrString = &pAdapterInfo->IpAddressList; pAddrString != NULL; pAddrString = pAddrString->Next)
  909. {
  910. TraceTag(ttidConman, "IP Address: %s", pAddrString->IpAddress.String);
  911. addr = inet_addr(pAddrString->IpAddress.String);
  912. if(!addr)
  913. {
  914. return FALSE;
  915. }
  916. }
  917. return TRUE;
  918. }
  919. //+---------------------------------------------------------------------------
  920. //
  921. // Function: HrGetAddressStatusForAdapter
  922. //
  923. // Purpose: Verifies that the given adapter has a valid address
  924. //
  925. // Arguments:
  926. // IN LPCGUID pguidAdapter - Guid for the adapter
  927. // OUT BOOL* pbValidAddress - BOOL indicating if it has
  928. // has Valid Address
  929. //
  930. // Returns: True if Valid address, False otherwise
  931. //
  932. // Author: ckotze 11 Jan 2001
  933. //
  934. // Notes:
  935. //
  936. //
  937. //
  938. HRESULT HrGetAddressStatusForAdapter(IN LPCGUID pguidAdapter, OUT BOOL* pbValidAddress)
  939. {
  940. HRESULT hr = E_FAIL;
  941. GUID guidId = GUID_NULL;
  942. PIP_ADAPTER_INFO pAdapterInfo = NULL;
  943. PIP_ADAPTER_INFO pAdapters = NULL;
  944. ULONG ulSize = 0;
  945. PIP_ADAPTER_INFO p = NULL;
  946. WCHAR lpszInstanceId[50];
  947. WCHAR szAdapterGUID[MAX_PATH];
  948. WCHAR szAdapterID[MAX_PATH];
  949. if (!pguidAdapter)
  950. {
  951. return E_INVALIDARG;
  952. }
  953. if (!pbValidAddress)
  954. {
  955. return E_POINTER;
  956. }
  957. ZeroMemory(szAdapterGUID, sizeof(WCHAR)*MAX_PATH);
  958. ZeroMemory(szAdapterID, sizeof(WCHAR)*MAX_PATH);
  959. StringFromGUID2(*pguidAdapter, szAdapterGUID, MAX_PATH);
  960. // GetAdaptersInfo returns ERROR_BUFFER_OVERFLOW when it is filling in the size
  961. if ( ERROR_BUFFER_OVERFLOW == GetAdaptersInfo(NULL, &ulSize) )
  962. {
  963. pAdapters = reinterpret_cast<PIP_ADAPTER_INFO>(new BYTE[ulSize]);
  964. if (pAdapters)
  965. {
  966. if(ERROR_SUCCESS == GetAdaptersInfo(pAdapters, &ulSize))
  967. {
  968. for (p = pAdapters; p != NULL; p = p->Next)
  969. {
  970. MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, p->AdapterName, strlen(p->AdapterName), szAdapterID, MAX_PATH);
  971. if (wcscmp(szAdapterGUID, szAdapterID) == 0)
  972. {
  973. TraceTag(ttidConman, "Found Adapter: %s", p->AdapterName);
  974. pAdapterInfo = p;
  975. *pbValidAddress = HasValidAddress(pAdapterInfo);
  976. hr = S_OK;
  977. TraceTag(ttidConman, "Valid Address: %s", (*pbValidAddress) ? "Yes" : "No");
  978. TraceTag(ttidConman, "DHCP: %s", (pAdapterInfo->DhcpEnabled) ? "Yes" : "No");
  979. }
  980. }
  981. }
  982. delete[] reinterpret_cast<BYTE*>(pAdapters);
  983. }
  984. else
  985. {
  986. hr = E_OUTOFMEMORY;
  987. }
  988. }
  989. return hr;
  990. }
  991. HRESULT HrGetPseudoMediaTypeFromConnection(IN REFGUID guidConn, OUT NETCON_SUBMEDIATYPE *pncsm)
  992. {
  993. HRESULT hr = S_OK;
  994. HKEY hkeyConnection;
  995. hr = HrOpenConnectionKey(&guidConn, NULL, KEY_READ, OCCF_NONE, NULL, &hkeyConnection);
  996. if (SUCCEEDED(hr))
  997. {
  998. DWORD dwMediaSubType;
  999. hr = HrRegQueryDword(hkeyConnection, c_szRegValueMediaSubType, &dwMediaSubType);
  1000. if (SUCCEEDED(hr))
  1001. {
  1002. *pncsm = static_cast<NETCON_SUBMEDIATYPE>(dwMediaSubType);
  1003. }
  1004. else
  1005. {
  1006. *pncsm = NCSM_LAN;
  1007. }
  1008. RegCloseKey(hkeyConnection);
  1009. }
  1010. return hr;
  1011. }