wifi_service_win.cc 68 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820
  1. // Copyright 2013 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/wifi/wifi_service.h"
  5. #include <windows.h> // Must be in front of other Windows header files.
  6. #include <iphlpapi.h>
  7. #include <objbase.h>
  8. #include <stddef.h>
  9. #include <stdint.h>
  10. #include <wlanapi.h>
  11. #include <memory>
  12. #include <set>
  13. #include <string>
  14. #include <utility>
  15. #include "base/base_paths_win.h"
  16. #include "base/bind.h"
  17. #include "base/files/file_path.h"
  18. #include "base/logging.h"
  19. #include "base/memory/ref_counted.h"
  20. #include "base/path_service.h"
  21. #include "base/strings/string_util.h"
  22. #include "base/strings/utf_string_conversions.h"
  23. #include "base/task/single_thread_task_runner.h"
  24. #include "base/time/time.h"
  25. #include "base/values.h"
  26. #include "base/win/registry.h"
  27. #include "base/win/win_util.h"
  28. #include "components/onc/onc_constants.h"
  29. #include "components/wifi/network_properties.h"
  30. #include "third_party/abseil-cpp/absl/types/optional.h"
  31. #include "third_party/libxml/chromium/xml_reader.h"
  32. #include "third_party/libxml/chromium/xml_writer.h"
  33. namespace {
  34. const wchar_t kNwCategoryWizardRegKey[] =
  35. L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Network\\"
  36. L"NwCategoryWizard";
  37. const wchar_t kNwCategoryWizardRegValue[] = L"Show";
  38. const wchar_t kNwCategoryWizardSavedRegValue[] = L"ShowSaved";
  39. const wchar_t kNwCategoryWizardDeleteRegValue[] = L"ShowDelete";
  40. const wchar_t kWlanApiDll[] = L"wlanapi.dll";
  41. // Created Profile Dictionary keys
  42. const char kProfileXmlKey[] = "xml";
  43. const char kProfileSharedKey[] = "shared";
  44. // WlanApi function names
  45. const char kWlanConnect[] = "WlanConnect";
  46. const char kWlanCloseHandle[] = "WlanCloseHandle";
  47. const char kWlanDeleteProfile[] = "WlanDeleteProfile";
  48. const char kWlanDisconnect[] = "WlanDisconnect";
  49. const char kWlanEnumInterfaces[] = "WlanEnumInterfaces";
  50. const char kWlanFreeMemory[] = "WlanFreeMemory";
  51. const char kWlanGetAvailableNetworkList[] = "WlanGetAvailableNetworkList";
  52. const char kWlanGetNetworkBssList[] = "WlanGetNetworkBssList";
  53. const char kWlanGetProfile[] = "WlanGetProfile";
  54. const char kWlanOpenHandle[] = "WlanOpenHandle";
  55. const char kWlanQueryInterface[] = "WlanQueryInterface";
  56. const char kWlanRegisterNotification[] = "WlanRegisterNotification";
  57. const char kWlanSaveTemporaryProfile[] = "WlanSaveTemporaryProfile";
  58. const char kWlanScan[] = "WlanScan";
  59. const char kWlanSetProfile[] = "WlanSetProfile";
  60. // WlanApi function definitions
  61. typedef DWORD(WINAPI* WlanConnectFunction)(
  62. HANDLE hClientHandle,
  63. CONST GUID* pInterfaceGuid,
  64. CONST PWLAN_CONNECTION_PARAMETERS pConnectionParameters,
  65. PVOID pReserved);
  66. typedef DWORD (WINAPI* WlanCloseHandleFunction)(
  67. HANDLE hClientHandle,
  68. PVOID pReserved);
  69. typedef DWORD(WINAPI* WlanDeleteProfileFunction)(HANDLE hClientHandle,
  70. const GUID* pInterfaceGuid,
  71. LPCWSTR strProfileName,
  72. PVOID pReserved);
  73. typedef DWORD(WINAPI* WlanDisconnectFunction)(HANDLE hClientHandle,
  74. CONST GUID* pInterfaceGuid,
  75. PVOID pReserved);
  76. typedef DWORD(WINAPI* WlanEnumInterfacesFunction)(
  77. HANDLE hClientHandle,
  78. PVOID pReserved,
  79. PWLAN_INTERFACE_INFO_LIST* ppInterfaceList);
  80. typedef VOID (WINAPI* WlanFreeMemoryFunction)(
  81. _In_ PVOID pMemory);
  82. typedef DWORD(WINAPI* WlanGetAvailableNetworkListFunction)(
  83. HANDLE hClientHandle,
  84. CONST GUID* pInterfaceGuid,
  85. DWORD dwFlags,
  86. PVOID pReserved,
  87. PWLAN_AVAILABLE_NETWORK_LIST* ppAvailableNetworkList);
  88. typedef DWORD (WINAPI* WlanGetNetworkBssListFunction)(
  89. HANDLE hClientHandle,
  90. const GUID* pInterfaceGuid,
  91. const PDOT11_SSID pDot11Ssid,
  92. DOT11_BSS_TYPE dot11BssType,
  93. BOOL bSecurityEnabled,
  94. PVOID pReserved,
  95. PWLAN_BSS_LIST* ppWlanBssList);
  96. typedef DWORD(WINAPI* WlanGetProfileFunction)(HANDLE hClientHandle,
  97. CONST GUID* pInterfaceGuid,
  98. LPCWSTR strProfileName,
  99. PVOID pReserved,
  100. LPWSTR* pstrProfileXml,
  101. DWORD* pdwFlags,
  102. DWORD* pdwGrantedAccess);
  103. typedef DWORD (WINAPI* WlanOpenHandleFunction)(
  104. DWORD dwClientVersion,
  105. PVOID pReserved,
  106. PDWORD pdwNegotiatedVersion,
  107. PHANDLE phClientHandle);
  108. typedef DWORD(WINAPI* WlanQueryInterfaceFunction)(
  109. HANDLE hClientHandle,
  110. const GUID* pInterfaceGuid,
  111. WLAN_INTF_OPCODE OpCode,
  112. PVOID pReserved,
  113. PDWORD pdwDataSize,
  114. PVOID* ppData,
  115. PWLAN_OPCODE_VALUE_TYPE pWlanOpcodeValueType);
  116. typedef DWORD (WINAPI* WlanRegisterNotificationFunction)(
  117. HANDLE hClientHandle,
  118. DWORD dwNotifSource,
  119. BOOL bIgnoreDuplicate,
  120. WLAN_NOTIFICATION_CALLBACK funcCallback,
  121. PVOID pCallbackContext,
  122. PVOID pReserved,
  123. PDWORD pdwPrevNotifSource);
  124. typedef DWORD (WINAPI* WlanSaveTemporaryProfileFunction)(
  125. HANDLE hClientHandle,
  126. CONST GUID* pInterfaceGuid,
  127. LPCWSTR strProfileName,
  128. LPCWSTR strAllUserProfileSecurity,
  129. DWORD dwFlags,
  130. BOOL bOverWrite,
  131. PVOID pReserved);
  132. typedef DWORD(WINAPI* WlanScanFunction)(HANDLE hClientHandle,
  133. CONST GUID* pInterfaceGuid,
  134. CONST PDOT11_SSID pDot11Ssid,
  135. CONST PWLAN_RAW_DATA pIeData,
  136. PVOID pReserved);
  137. typedef DWORD(WINAPI* WlanSetProfileFunction)(HANDLE hClientHandle,
  138. const GUID* pInterfaceGuid,
  139. DWORD dwFlags,
  140. LPCWSTR strProfileXml,
  141. LPCWSTR strAllUserProfileSecurity,
  142. BOOL bOverwrite,
  143. PVOID pReserved,
  144. DWORD* pdwReasonCode);
  145. // Values for WLANProfile XML.
  146. const char kAuthenticationOpen[] = "open";
  147. const char kAuthenticationWepPsk[] = "WEP";
  148. const char kAuthenticationWpaPsk[] = "WPAPSK";
  149. const char kAuthenticationWpa2Psk[] = "WPA2PSK";
  150. const char kEncryptionAES[] = "AES";
  151. const char kEncryptionNone[] = "none";
  152. const char kEncryptionTKIP[] = "TKIP";
  153. const char kEncryptionWEP[] = "WEP";
  154. const char kKeyTypeNetwork[] = "networkKey";
  155. const char kKeyTypePassphrase[] = "passPhrase";
  156. } // namespace
  157. namespace wifi {
  158. // Implementation of WiFiService for Windows.
  159. class WiFiServiceImpl : public WiFiService {
  160. public:
  161. WiFiServiceImpl();
  162. WiFiServiceImpl(const WiFiServiceImpl&) = delete;
  163. WiFiServiceImpl& operator=(const WiFiServiceImpl&) = delete;
  164. ~WiFiServiceImpl() override;
  165. // WiFiService interface implementation.
  166. void Initialize(
  167. scoped_refptr<base::SequencedTaskRunner> task_runner) override;
  168. void UnInitialize() override;
  169. void GetProperties(const std::string& network_guid,
  170. base::Value::Dict* properties,
  171. std::string* error) override;
  172. void GetManagedProperties(const std::string& network_guid,
  173. base::Value::Dict* managed_properties,
  174. std::string* error) override;
  175. void GetState(const std::string& network_guid,
  176. base::Value::Dict* properties,
  177. std::string* error) override;
  178. void SetProperties(const std::string& network_guid,
  179. base::Value::Dict properties,
  180. std::string* error) override;
  181. void CreateNetwork(bool shared,
  182. base::Value::Dict properties,
  183. std::string* network_guid,
  184. std::string* error) override;
  185. void GetVisibleNetworks(const std::string& network_type,
  186. bool include_details,
  187. base::Value::List* network_list) override;
  188. void RequestNetworkScan() override;
  189. void StartConnect(const std::string& network_guid,
  190. std::string* error) override;
  191. void StartDisconnect(const std::string& network_guid,
  192. std::string* error) override;
  193. void GetKeyFromSystem(const std::string& network_guid,
  194. std::string* key_data,
  195. std::string* error) override;
  196. void SetEventObservers(
  197. scoped_refptr<base::SingleThreadTaskRunner> task_runner,
  198. NetworkGuidListCallback networks_changed_observer,
  199. NetworkGuidListCallback network_list_changed_observer) override;
  200. void RequestConnectedNetworkUpdate() override {}
  201. void GetConnectedNetworkSSID(std::string* ssid, std::string* error) override;
  202. private:
  203. typedef int32_t EncryptionType;
  204. enum EncryptionTypeEnum {
  205. kEncryptionTypeAny = 0,
  206. kEncryptionTypeAES = 1,
  207. kEncryptionTypeTKIP = 2
  208. };
  209. // Static callback for Windows WLAN_NOTIFICATION. Calls OnWlanNotification
  210. // on WiFiServiceImpl passed back as |context|.
  211. static void __stdcall OnWlanNotificationCallback(
  212. PWLAN_NOTIFICATION_DATA wlan_notification_data,
  213. PVOID context);
  214. // Callback for Windows WLAN_NOTIFICATION. Called on random thread from
  215. // OnWlanNotificationCallback. Handles network connectivity and scan complete
  216. // notification and posts tasks to main thread.
  217. void OnWlanNotification(PWLAN_NOTIFICATION_DATA wlan_notification_data);
  218. // Handles NetworkScanComplete notification on main thread. Sends
  219. // |NetworkListChanged| event with new list of visible networks.
  220. void OnNetworkScanCompleteOnMainThread();
  221. // Wait up to |kMaxAttempts| with |kAttemptDelayMs| delay for connection
  222. // to network with |network_guid|. Reset DHCP and Notify that |NetworkChanged|
  223. // upon success.
  224. void WaitForNetworkConnect(const std::string& network_guid, int attempt);
  225. // Check |error_code| and if is not |ERROR_SUCCESS|, then store |error_name|
  226. // into |error|.
  227. bool CheckError(DWORD error_code,
  228. const std::string& error_name,
  229. std::string* error) const;
  230. // Return |iterator| to network identified by |network_guid| in |networks|
  231. // list.
  232. NetworkList::iterator FindNetwork(NetworkList& networks,
  233. const std::string& network_guid);
  234. // Save currently connected network profile so it can be re-connected later.
  235. DWORD SaveCurrentConnectedNetwork(const NetworkProperties& properties);
  236. // Sort networks, so connected/connecting is up front, then by type:
  237. // Ethernet, WiFi, Cellular, VPN
  238. static void SortNetworks(NetworkList* networks);
  239. // Open a WLAN client handle, register for WLAN notifications.
  240. DWORD OpenClientHandle();
  241. // Reset DHCP on wireless network to work around an issue when Windows
  242. // takes forever to connect to the network, e.g. after Chromecast
  243. // device reset.
  244. DWORD ResetDHCP();
  245. // Find |adapter_index_map| by |interface_guid| for DHCP reset.
  246. DWORD FindAdapterIndexMapByGUID(const GUID& interface_guid,
  247. IP_ADAPTER_INDEX_MAP* adapter_index_map);
  248. // Avoid the network location wizard to pop up when network is connected.
  249. // Preserve current value in |saved_nw_category_wizard_|.
  250. DWORD DisableNwCategoryWizard();
  251. // Restore network location wizard to value saved by DisableNwCategoryWizard.
  252. DWORD RestoreNwCategoryWizard();
  253. // Ensure that |client_| handle is initialized.
  254. DWORD EnsureInitialized();
  255. // Close |client_| handle if it is open.
  256. DWORD CloseClientHandle();
  257. // Get |profile_name| from unique |network_guid|.
  258. std::wstring ProfileNameFromGUID(const std::string& network_guid) const {
  259. return base::UTF8ToWide(network_guid);
  260. }
  261. // Get |dot11_ssid| from unique |network_guid|.
  262. DOT11_SSID SSIDFromGUID(const std::string& network_guid) const;
  263. // Get unique |network_guid| string based on |dot11_ssid|.
  264. std::string GUIDFromSSID(const DOT11_SSID& dot11_ssid) const {
  265. return std::string(reinterpret_cast<const char*>(dot11_ssid.ucSSID),
  266. dot11_ssid.uSSIDLength);
  267. }
  268. // Get network |ssid| string based on |wlan|.
  269. std::string SSIDFromWLAN(const WLAN_AVAILABLE_NETWORK& wlan) const {
  270. return GUIDFromSSID(wlan.dot11Ssid);
  271. }
  272. // Get unique |network_guid| string based on |wlan|.
  273. std::string GUIDFromWLAN(const WLAN_AVAILABLE_NETWORK& wlan) const {
  274. return SSIDFromWLAN(wlan);
  275. }
  276. // Deduce |onc::wifi| security from |alg|.
  277. std::string SecurityFromDot11AuthAlg(DOT11_AUTH_ALGORITHM alg) const;
  278. // Deduce |onc::connection_state| from |wlan_state|.
  279. std::string ConnectionStateFromInterfaceState(
  280. WLAN_INTERFACE_STATE wlan_state) const;
  281. // Convert |EncryptionType| into WPA(2) encryption type string.
  282. std::string WpaEncryptionFromEncryptionType(
  283. EncryptionType encryption_type) const;
  284. // Deduce WLANProfile |authEncryption| values from |onc::wifi| security.
  285. bool AuthEncryptionFromSecurity(const std::string& security,
  286. EncryptionType encryption_type,
  287. std::string* authentication,
  288. std::string* encryption,
  289. std::string* key_type) const;
  290. // Populate |properties| based on |wlan|.
  291. void NetworkPropertiesFromAvailableNetwork(const WLAN_AVAILABLE_NETWORK& wlan,
  292. NetworkProperties* properties);
  293. // Update |properties| based on bss info from |wlan_bss_list|. If |bssid| in
  294. // |properties| is not empty, then it is not changed and |frequency| is set
  295. // based on that bssid.
  296. void UpdateNetworkPropertiesFromBssList(const std::string& network_guid,
  297. const WLAN_BSS_LIST& wlan_bss_list,
  298. NetworkProperties* properties);
  299. // Get the list of visible wireless networks.
  300. DWORD GetVisibleNetworkList(NetworkList* network_list);
  301. // Get properties of the network currently used (connected or in transition)
  302. // by interface. Populate |current_properties| on success.
  303. DWORD GetCurrentProperties(NetworkProperties* current_properties);
  304. // Get the SSID of the network currently used (connected or in transition)
  305. // by interface. Populate |ssid| on success. This is a stripped down version
  306. // of GetCurrentProperties that doesn't use the BSS list;
  307. DWORD GetCurrentSSID(std::string* ssid);
  308. // Connect to network |network_guid| using previosly stored profile if exists,
  309. // or just network sid. If |frequency| is not |kFrequencyUnknown| then
  310. // connects only to BSS which uses that frequency and returns
  311. // |ERROR_NOT_FOUND| if such BSS cannot be found.
  312. DWORD Connect(const std::string& network_guid, Frequency frequency);
  313. // Disconnect from currently connected network if any.
  314. DWORD Disconnect();
  315. // Get desired connection freqency if it was set using |SetProperties|.
  316. // Default to |kFrequencyAny|.
  317. Frequency GetFrequencyToConnect(const std::string& network_guid) const;
  318. // Get DOT11_BSSID_LIST of desired BSSIDs to connect to |ssid| network on
  319. // given |frequency|.
  320. DWORD GetDesiredBssList(DOT11_SSID& ssid,
  321. Frequency frequency,
  322. std::unique_ptr<DOT11_BSSID_LIST>* desired_list);
  323. // Normalizes |frequency_in_mhz| into one of |Frequency| values.
  324. Frequency GetNormalizedFrequency(int frequency_in_mhz) const;
  325. // Create |profile_xml| based on |network_properties|. If |encryption_type|
  326. // is |kEncryptionTypeAny| applies the type most suitable for parameters in
  327. // |network_properties|.
  328. bool CreateProfile(const NetworkProperties& network_properties,
  329. EncryptionType encryption_type,
  330. std::string* profile_xml);
  331. // Save temporary wireless profile for |network_guid|.
  332. DWORD SaveTempProfile(const std::string& network_guid);
  333. // Get previously stored |profile_xml| for |network_guid|.
  334. // If |get_plaintext_key| is true, and process has sufficient privileges, then
  335. // <sharedKey> data in |profile_xml| will be unprotected.
  336. DWORD GetProfile(const std::string& network_guid,
  337. bool get_plaintext_key,
  338. std::string* profile_xml);
  339. // Set |profile_xml| to current user or all users depending on |shared| flag.
  340. // If |overwrite| is false, then returns an error if profile exists.
  341. DWORD SetProfile(bool shared, const std::string& profile_xml, bool overwrite);
  342. // Return true if there is previously stored profile xml for |network_guid|.
  343. bool HaveProfile(const std::string& network_guid);
  344. // Delete profile that was created, but failed to connect.
  345. DWORD DeleteCreatedProfile(const std::string& network_guid);
  346. // Notify |network_list_changed_observer_| that list of visible networks has
  347. // changed to |networks|.
  348. void NotifyNetworkListChanged(const NetworkList& networks);
  349. // Notify |networks_changed_observer_| that network |network_guid| status has
  350. // changed.
  351. void NotifyNetworkChanged(const std::string& network_guid);
  352. // Load WlanApi.dll from SystemDirectory and get Api function pointers.
  353. DWORD LoadWlanLibrary();
  354. // Instance of WlanApi.dll.
  355. HINSTANCE wlan_api_library_;
  356. // WlanApi function pointers
  357. WlanConnectFunction WlanConnect_function_;
  358. WlanCloseHandleFunction WlanCloseHandle_function_;
  359. WlanDeleteProfileFunction WlanDeleteProfile_function_;
  360. WlanDisconnectFunction WlanDisconnect_function_;
  361. WlanEnumInterfacesFunction WlanEnumInterfaces_function_;
  362. WlanFreeMemoryFunction WlanFreeMemory_function_;
  363. WlanGetAvailableNetworkListFunction WlanGetAvailableNetworkList_function_;
  364. // WlanGetNetworkBssList function may not be avaiable on Windows XP.
  365. WlanGetNetworkBssListFunction WlanGetNetworkBssList_function_;
  366. WlanGetProfileFunction WlanGetProfile_function_;
  367. WlanOpenHandleFunction WlanOpenHandle_function_;
  368. WlanQueryInterfaceFunction WlanQueryInterface_function_;
  369. WlanRegisterNotificationFunction WlanRegisterNotification_function_;
  370. WlanScanFunction WlanScan_function_;
  371. WlanSetProfileFunction WlanSetProfile_function_;
  372. // WlanSaveTemporaryProfile function may not be avaiable on Windows XP.
  373. WlanSaveTemporaryProfileFunction WlanSaveTemporaryProfile_function_;
  374. // WLAN service handle.
  375. HANDLE client_;
  376. // GUID of the currently connected interface, if any, otherwise the GUID of
  377. // one of the WLAN interfaces.
  378. GUID interface_guid_;
  379. // Temporary storage of network properties indexed by |network_guid|. Persist
  380. // only in memory.
  381. base::Value::Dict connect_properties_;
  382. // Preserved WLAN profile xml.
  383. std::map<std::string, std::string> saved_profiles_xml_;
  384. // Created WLAN Profiles, indexed by |network_guid|. Contains xml with TKIP
  385. // encryption type saved by |CreateNetwork| if applicable. Profile has to be
  386. // deleted if connection fails. Implicitly created profiles have to be deleted
  387. // if connection succeeds. Persist only in memory.
  388. base::Value::Dict created_profiles_;
  389. // Observer to get notified when network(s) have changed (e.g. connect).
  390. NetworkGuidListCallback networks_changed_observer_;
  391. // Observer to get notified when network list has changed (scan complete).
  392. NetworkGuidListCallback network_list_changed_observer_;
  393. // Saved value of network location wizard show value.
  394. std::unique_ptr<DWORD> saved_nw_category_wizard_;
  395. // Task runner to post events on UI thread.
  396. scoped_refptr<base::SingleThreadTaskRunner> event_task_runner_;
  397. // Task runner for worker tasks.
  398. scoped_refptr<base::SequencedTaskRunner> task_runner_;
  399. // If |false|, then |networks_changed_observer_| is not notified.
  400. bool enable_notify_network_changed_;
  401. // Number of attempts to check that network has connected successfully.
  402. static const int kMaxAttempts = 100;
  403. // Delay between attempts to check that network has connected successfully.
  404. static const int kAttemptDelayMs = 100;
  405. };
  406. WiFiServiceImpl::WiFiServiceImpl()
  407. : wlan_api_library_(nullptr),
  408. WlanConnect_function_(nullptr),
  409. WlanCloseHandle_function_(nullptr),
  410. WlanDeleteProfile_function_(nullptr),
  411. WlanDisconnect_function_(nullptr),
  412. WlanEnumInterfaces_function_(nullptr),
  413. WlanFreeMemory_function_(nullptr),
  414. WlanGetAvailableNetworkList_function_(nullptr),
  415. WlanGetNetworkBssList_function_(nullptr),
  416. WlanGetProfile_function_(nullptr),
  417. WlanOpenHandle_function_(nullptr),
  418. WlanRegisterNotification_function_(nullptr),
  419. WlanScan_function_(nullptr),
  420. WlanSetProfile_function_(nullptr),
  421. WlanSaveTemporaryProfile_function_(nullptr),
  422. client_(nullptr),
  423. enable_notify_network_changed_(true) {}
  424. WiFiServiceImpl::~WiFiServiceImpl() { UnInitialize(); }
  425. void WiFiServiceImpl::Initialize(
  426. scoped_refptr<base::SequencedTaskRunner> task_runner) {
  427. DCHECK(!client_);
  428. task_runner_.swap(task_runner);
  429. // Restore NwCategoryWizard in case if we crashed during connect.
  430. RestoreNwCategoryWizard();
  431. OpenClientHandle();
  432. }
  433. void WiFiServiceImpl::UnInitialize() {
  434. CloseClientHandle();
  435. }
  436. void WiFiServiceImpl::GetProperties(const std::string& network_guid,
  437. base::Value::Dict* properties,
  438. std::string* error) {
  439. DWORD error_code = EnsureInitialized();
  440. if (CheckError(error_code, kErrorWiFiService, error))
  441. return;
  442. NetworkProperties connected_properties;
  443. error_code = GetCurrentProperties(&connected_properties);
  444. if (error_code == ERROR_SUCCESS &&
  445. connected_properties.guid == network_guid) {
  446. *properties = connected_properties.ToValue(/*network_list=*/false);
  447. return;
  448. }
  449. NetworkList network_list;
  450. error_code = GetVisibleNetworkList(&network_list);
  451. if (error_code == ERROR_SUCCESS) {
  452. NetworkList::const_iterator it = FindNetwork(network_list, network_guid);
  453. if (it != network_list.end()) {
  454. DVLOG(1) << "Get Properties: " << network_guid << ":"
  455. << it->connection_state;
  456. *properties = it->ToValue(/*network_list=*/false);
  457. return;
  458. }
  459. error_code = ERROR_NOT_FOUND;
  460. }
  461. CheckError(error_code, kErrorWiFiService, error);
  462. }
  463. void WiFiServiceImpl::GetManagedProperties(
  464. const std::string& network_guid,
  465. base::Value::Dict* managed_properties,
  466. std::string* error) {
  467. CheckError(ERROR_CALL_NOT_IMPLEMENTED, kErrorWiFiService, error);
  468. }
  469. void WiFiServiceImpl::GetState(const std::string& network_guid,
  470. base::Value::Dict* properties,
  471. std::string* error) {
  472. CheckError(ERROR_CALL_NOT_IMPLEMENTED, kErrorWiFiService, error);
  473. }
  474. void WiFiServiceImpl::SetProperties(const std::string& network_guid,
  475. base::Value::Dict properties,
  476. std::string* error) {
  477. // Temporary preserve WiFi properties (desired frequency, wifi password) to
  478. // use in StartConnect.
  479. if (!properties.Find(onc::network_type::kWiFi)) {
  480. DVLOG(0) << "Missing WiFi properties:" << properties;
  481. *error = kErrorWiFiService;
  482. return;
  483. }
  484. // If the network properties already exist, don't override previously set
  485. // properties, unless they are set in |properties|.
  486. base::Value::Dict* existing_properties =
  487. connect_properties_.FindDict(network_guid);
  488. if (existing_properties) {
  489. existing_properties->Merge(std::move(properties));
  490. } else {
  491. connect_properties_.Set(network_guid, std::move(properties));
  492. }
  493. }
  494. void WiFiServiceImpl::CreateNetwork(bool shared,
  495. base::Value::Dict properties,
  496. std::string* network_guid,
  497. std::string* error) {
  498. DWORD error_code = EnsureInitialized();
  499. if (CheckError(error_code, kErrorWiFiService, error))
  500. return;
  501. NetworkProperties network_properties;
  502. if (!network_properties.UpdateFromValue(properties)) {
  503. CheckError(ERROR_INVALID_DATA, kErrorWiFiService, error);
  504. return;
  505. }
  506. network_properties.guid = network_properties.ssid;
  507. std::string profile_xml;
  508. if (!CreateProfile(network_properties, kEncryptionTypeAny, &profile_xml)) {
  509. CheckError(ERROR_INVALID_DATA, kErrorWiFiService, error);
  510. return;
  511. }
  512. error_code = SetProfile(shared, profile_xml, false);
  513. if (CheckError(error_code, kErrorWiFiService, error)) {
  514. DVLOG(0) << profile_xml;
  515. return;
  516. }
  517. // WAP and WAP2 networks could use either AES or TKIP encryption type.
  518. // Preserve alternative profile to use in case if connection with default
  519. // encryption type fails.
  520. std::string tkip_profile_xml;
  521. if (!CreateProfile(network_properties,
  522. kEncryptionTypeTKIP,
  523. &tkip_profile_xml)) {
  524. CheckError(ERROR_INVALID_DATA, kErrorWiFiService, error);
  525. return;
  526. }
  527. if (tkip_profile_xml != profile_xml) {
  528. base::Value::Dict tkip_profile;
  529. tkip_profile.Set(kProfileXmlKey, tkip_profile_xml);
  530. tkip_profile.Set(kProfileSharedKey, shared);
  531. created_profiles_.Set(network_properties.guid, std::move(tkip_profile));
  532. }
  533. *network_guid = network_properties.guid;
  534. }
  535. void WiFiServiceImpl::GetVisibleNetworks(const std::string& network_type,
  536. bool include_details,
  537. base::Value::List* network_list) {
  538. if (!network_type.empty() &&
  539. network_type != onc::network_type::kAllTypes &&
  540. network_type != onc::network_type::kWiFi) {
  541. return;
  542. }
  543. DWORD error = EnsureInitialized();
  544. if (error == ERROR_SUCCESS) {
  545. NetworkList networks;
  546. error = GetVisibleNetworkList(&networks);
  547. if (error == ERROR_SUCCESS && !networks.empty()) {
  548. SortNetworks(&networks);
  549. for (NetworkList::const_iterator it = networks.begin();
  550. it != networks.end();
  551. ++it) {
  552. network_list->Append(it->ToValue(/*network_list=*/!include_details));
  553. }
  554. }
  555. }
  556. }
  557. void WiFiServiceImpl::RequestNetworkScan() {
  558. DWORD error = EnsureInitialized();
  559. if (error == ERROR_SUCCESS) {
  560. WlanScan_function_(client_, &interface_guid_, nullptr, nullptr, nullptr);
  561. }
  562. }
  563. void WiFiServiceImpl::StartConnect(const std::string& network_guid,
  564. std::string* error) {
  565. DVLOG(1) << "Start Connect: " << network_guid;
  566. DWORD error_code = EnsureInitialized();
  567. if (CheckError(error_code, kErrorWiFiService, error))
  568. return;
  569. // Check, if the network is already connected on desired frequency.
  570. Frequency frequency = GetFrequencyToConnect(network_guid);
  571. NetworkProperties properties;
  572. GetCurrentProperties(&properties);
  573. bool already_connected =
  574. network_guid == properties.guid &&
  575. properties.connection_state == onc::connection_state::kConnected &&
  576. (frequency == kFrequencyAny || frequency == properties.frequency);
  577. // Connect only if network |network_guid| is not connected already.
  578. if (!already_connected) {
  579. SaveCurrentConnectedNetwork(properties);
  580. error_code = Connect(network_guid, frequency);
  581. }
  582. if (error_code == ERROR_SUCCESS) {
  583. // Notify that previously connected network has changed.
  584. NotifyNetworkChanged(properties.guid);
  585. // Start waiting for network connection state change.
  586. if (networks_changed_observer_) {
  587. DisableNwCategoryWizard();
  588. // Disable automatic network change notifications as they get fired
  589. // when network is just connected, but not yet accessible (doesn't
  590. // have valid IP address).
  591. enable_notify_network_changed_ = false;
  592. WaitForNetworkConnect(network_guid, 0);
  593. return;
  594. }
  595. } else if (error_code == ERROR_ACCESS_DENIED) {
  596. CheckError(error_code, kErrorNotConfigured, error);
  597. } else {
  598. CheckError(error_code, kErrorWiFiService, error);
  599. }
  600. }
  601. void WiFiServiceImpl::StartDisconnect(const std::string& network_guid,
  602. std::string* error) {
  603. DVLOG(1) << "Start Disconnect: " << network_guid;
  604. DWORD error_code = EnsureInitialized();
  605. if (CheckError(error_code, kErrorWiFiService, error))
  606. return;
  607. // Check, if the network is currently connected.
  608. NetworkProperties properties;
  609. GetCurrentProperties(&properties);
  610. if (network_guid == properties.guid) {
  611. if (properties.connection_state == onc::connection_state::kConnected)
  612. SaveCurrentConnectedNetwork(properties);
  613. error_code = Disconnect();
  614. if (error_code == ERROR_SUCCESS) {
  615. NotifyNetworkChanged(network_guid);
  616. return;
  617. }
  618. }
  619. CheckError(error_code, kErrorWiFiService, error);
  620. }
  621. void WiFiServiceImpl::GetKeyFromSystem(const std::string& network_guid,
  622. std::string* key_data,
  623. std::string* error) {
  624. DWORD error_code = EnsureInitialized();
  625. if (CheckError(error_code, kErrorWiFiService, error))
  626. return;
  627. std::string profile_xml;
  628. error_code = GetProfile(network_guid, true, &profile_xml);
  629. if (CheckError(error_code, kErrorWiFiService, error))
  630. return;
  631. const char kSharedKeyElement[] = "sharedKey";
  632. const char kProtectedElement[] = "protected";
  633. const char kKeyMaterialElement[] = "keyMaterial";
  634. // Quick check to verify presence of <sharedKey> element.
  635. if (profile_xml.find(kSharedKeyElement) == std::string::npos) {
  636. *error = kErrorWiFiService;
  637. return;
  638. }
  639. XmlReader reader;
  640. if (reader.Load(profile_xml)) {
  641. while (reader.Read()) {
  642. reader.SkipToElement();
  643. if (reader.NodeName() == kSharedKeyElement) {
  644. while (reader.Read()) {
  645. reader.SkipToElement();
  646. if (reader.NodeName() == kKeyMaterialElement) {
  647. reader.ReadElementContent(key_data);
  648. } else if (reader.NodeName() == kProtectedElement) {
  649. std::string protected_data;
  650. reader.ReadElementContent(&protected_data);
  651. // Without UAC privilege escalation call to |GetProfile| with
  652. // |WLAN_PROFILE_GET_PLAINTEXT_KEY| flag returns success, but has
  653. // protected keyMaterial. Report an error in this case.
  654. if (protected_data != "false") {
  655. *error = kErrorWiFiService;
  656. break;
  657. }
  658. }
  659. }
  660. return;
  661. }
  662. }
  663. }
  664. // Did not find passphrase in the profile.
  665. *error = kErrorWiFiService;
  666. }
  667. void WiFiServiceImpl::SetEventObservers(
  668. scoped_refptr<base::SingleThreadTaskRunner> task_runner,
  669. NetworkGuidListCallback networks_changed_observer,
  670. NetworkGuidListCallback network_list_changed_observer) {
  671. DWORD error_code = EnsureInitialized();
  672. if (error_code != ERROR_SUCCESS)
  673. return;
  674. event_task_runner_.swap(task_runner);
  675. if (networks_changed_observer_ || network_list_changed_observer_) {
  676. // Stop listening to WLAN notifications.
  677. WlanRegisterNotification_function_(client_, WLAN_NOTIFICATION_SOURCE_NONE,
  678. FALSE, OnWlanNotificationCallback, this,
  679. nullptr, nullptr);
  680. }
  681. networks_changed_observer_ = std::move(networks_changed_observer);
  682. network_list_changed_observer_ = std::move(network_list_changed_observer);
  683. if (networks_changed_observer_ || network_list_changed_observer_) {
  684. // Start listening to WLAN notifications.
  685. WlanRegisterNotification_function_(client_, WLAN_NOTIFICATION_SOURCE_ALL,
  686. FALSE, OnWlanNotificationCallback, this,
  687. nullptr, nullptr);
  688. }
  689. }
  690. void WiFiServiceImpl::GetConnectedNetworkSSID(std::string* ssid,
  691. std::string* error) {
  692. DWORD error_code = EnsureInitialized();
  693. if (CheckError(error_code, kErrorWiFiService, error))
  694. return;
  695. std::string current_ssid;
  696. error_code = GetCurrentSSID(&current_ssid);
  697. if (CheckError(error_code, kErrorWiFiService, error))
  698. return;
  699. *ssid = current_ssid;
  700. }
  701. void WiFiServiceImpl::OnWlanNotificationCallback(
  702. PWLAN_NOTIFICATION_DATA wlan_notification_data,
  703. PVOID context) {
  704. WiFiServiceImpl* service = reinterpret_cast<WiFiServiceImpl*>(context);
  705. service->OnWlanNotification(wlan_notification_data);
  706. }
  707. void WiFiServiceImpl::OnWlanNotification(
  708. PWLAN_NOTIFICATION_DATA wlan_notification_data) {
  709. if (!event_task_runner_)
  710. return;
  711. switch (wlan_notification_data->NotificationCode) {
  712. case wlan_notification_acm_disconnected:
  713. case wlan_notification_acm_connection_complete:
  714. case wlan_notification_acm_connection_attempt_fail: {
  715. PWLAN_CONNECTION_NOTIFICATION_DATA wlan_connection_data =
  716. reinterpret_cast<PWLAN_CONNECTION_NOTIFICATION_DATA>(
  717. wlan_notification_data->pData);
  718. event_task_runner_->PostTask(
  719. FROM_HERE,
  720. base::BindOnce(&WiFiServiceImpl::NotifyNetworkChanged,
  721. base::Unretained(this),
  722. GUIDFromSSID(wlan_connection_data->dot11Ssid)));
  723. break;
  724. }
  725. case wlan_notification_acm_scan_complete:
  726. case wlan_notification_acm_interface_removal:
  727. event_task_runner_->PostTask(
  728. FROM_HERE,
  729. base::BindOnce(&WiFiServiceImpl::OnNetworkScanCompleteOnMainThread,
  730. base::Unretained(this)));
  731. break;
  732. }
  733. }
  734. void WiFiServiceImpl::OnNetworkScanCompleteOnMainThread() {
  735. NetworkList networks;
  736. // Get current list of visible networks and notify that network list has
  737. // changed.
  738. DWORD error = GetVisibleNetworkList(&networks);
  739. if (error != ERROR_SUCCESS)
  740. networks.clear();
  741. NotifyNetworkListChanged(networks);
  742. }
  743. void WiFiServiceImpl::WaitForNetworkConnect(const std::string& network_guid,
  744. int attempt) {
  745. // If network didn't get connected in |kMaxAttempts|, then try to connect
  746. // using different profile if it was created recently.
  747. if (attempt > kMaxAttempts) {
  748. LOG(ERROR) << kMaxAttempts << " attempts exceeded waiting for connect to "
  749. << network_guid;
  750. base::Value::Dict* created_profile =
  751. created_profiles_.FindDict(network_guid);
  752. // Check, whether this connection is using newly created profile.
  753. if (created_profile) {
  754. const std::string* tkip_profile_xml =
  755. created_profile->FindString(kProfileXmlKey);
  756. absl::optional<bool> shared =
  757. created_profile->FindBool(kProfileSharedKey);
  758. // Check, if this connection there is alternative TKIP profile xml that
  759. // should be tried. If there is, then set it up and try to connect again.
  760. if (tkip_profile_xml && shared) {
  761. // Remove TKIP profile xml, so it will not be tried again.
  762. created_profile->Remove(kProfileXmlKey);
  763. created_profile->Remove(kProfileSharedKey);
  764. DWORD error_code = SetProfile(*shared, *tkip_profile_xml, true);
  765. if (error_code == ERROR_SUCCESS) {
  766. // Try to connect with new profile.
  767. error_code = Connect(network_guid,
  768. GetFrequencyToConnect(network_guid));
  769. if (error_code == ERROR_SUCCESS) {
  770. // Start waiting again.
  771. WaitForNetworkConnect(network_guid, 0);
  772. return;
  773. } else {
  774. LOG(ERROR) << "Failed to set created profile for " << network_guid
  775. << " error=" << error_code;
  776. }
  777. }
  778. } else {
  779. // Connection has failed, so delete bad created profile.
  780. DWORD error_code = DeleteCreatedProfile(network_guid);
  781. if (error_code != ERROR_SUCCESS) {
  782. LOG(ERROR) << "Failed to delete created profile for " << network_guid
  783. << " error=" << error_code;
  784. }
  785. }
  786. }
  787. // Restore automatic network change notifications and stop waiting.
  788. enable_notify_network_changed_ = true;
  789. RestoreNwCategoryWizard();
  790. return;
  791. }
  792. NetworkProperties current_properties;
  793. DWORD error = GetCurrentProperties(&current_properties);
  794. if (network_guid == current_properties.guid &&
  795. current_properties.connection_state ==
  796. onc::connection_state::kConnected) {
  797. DVLOG(1) << "WiFi Connected, Reset DHCP: " << network_guid;
  798. // Even though wireless network is now connected, it may still be unusable,
  799. // e.g. after Chromecast device reset. Reset DHCP on wireless network to
  800. // work around this issue.
  801. error = ResetDHCP();
  802. if (error != ERROR_SUCCESS)
  803. LOG(ERROR) << error;
  804. // There is no need to keep created profile as network is connected.
  805. created_profiles_.Remove(network_guid);
  806. // Restore previously suppressed notifications.
  807. enable_notify_network_changed_ = true;
  808. RestoreNwCategoryWizard();
  809. NotifyNetworkChanged(network_guid);
  810. } else {
  811. // Continue waiting for network connection state change.
  812. task_runner_->PostDelayedTask(
  813. FROM_HERE,
  814. base::BindOnce(&WiFiServiceImpl::WaitForNetworkConnect,
  815. base::Unretained(this), network_guid, ++attempt),
  816. base::Milliseconds(kAttemptDelayMs));
  817. }
  818. }
  819. bool WiFiServiceImpl::CheckError(DWORD error_code,
  820. const std::string& error_name,
  821. std::string* error) const {
  822. if (error_code != ERROR_SUCCESS) {
  823. DLOG(ERROR) << "WiFiService Error " << error_code << ": " << error_name;
  824. *error = error_name;
  825. return true;
  826. }
  827. return false;
  828. }
  829. NetworkList::iterator WiFiServiceImpl::FindNetwork(
  830. NetworkList& networks,
  831. const std::string& network_guid) {
  832. for (NetworkList::iterator it = networks.begin(); it != networks.end();
  833. ++it) {
  834. if (it->guid == network_guid)
  835. return it;
  836. }
  837. return networks.end();
  838. }
  839. DWORD WiFiServiceImpl::SaveCurrentConnectedNetwork(
  840. const NetworkProperties& current_properties) {
  841. DWORD error = ERROR_SUCCESS;
  842. // Save currently connected network.
  843. if (!current_properties.guid.empty() &&
  844. current_properties.connection_state ==
  845. onc::connection_state::kConnected) {
  846. error = SaveTempProfile(current_properties.guid);
  847. }
  848. return error;
  849. }
  850. void WiFiServiceImpl::SortNetworks(NetworkList* networks) {
  851. networks->sort(NetworkProperties::OrderByType);
  852. }
  853. DWORD WiFiServiceImpl::LoadWlanLibrary() {
  854. // Use an absolute path to load the DLL to avoid DLL preloading attacks.
  855. base::FilePath path;
  856. if (!base::PathService::Get(base::DIR_SYSTEM, &path)) {
  857. LOG(ERROR) << "Unable to get system path.";
  858. return ERROR_NOT_FOUND;
  859. }
  860. wlan_api_library_ = ::LoadLibraryEx(path.Append(kWlanApiDll).value().c_str(),
  861. nullptr, LOAD_WITH_ALTERED_SEARCH_PATH);
  862. if (!wlan_api_library_) {
  863. LOG(ERROR) << "Unable to load WlanApi.dll.";
  864. return ERROR_NOT_FOUND;
  865. }
  866. // Initialize WlanApi function pointers
  867. WlanConnect_function_ =
  868. reinterpret_cast<WlanConnectFunction>(
  869. ::GetProcAddress(wlan_api_library_, kWlanConnect));
  870. WlanCloseHandle_function_ =
  871. reinterpret_cast<WlanCloseHandleFunction>(
  872. ::GetProcAddress(wlan_api_library_, kWlanCloseHandle));
  873. WlanDeleteProfile_function_ =
  874. reinterpret_cast<WlanDeleteProfileFunction>(
  875. ::GetProcAddress(wlan_api_library_, kWlanDeleteProfile));
  876. WlanDisconnect_function_ =
  877. reinterpret_cast<WlanDisconnectFunction>(
  878. ::GetProcAddress(wlan_api_library_, kWlanDisconnect));
  879. WlanEnumInterfaces_function_ =
  880. reinterpret_cast<WlanEnumInterfacesFunction>(
  881. ::GetProcAddress(wlan_api_library_, kWlanEnumInterfaces));
  882. WlanFreeMemory_function_ =
  883. reinterpret_cast<WlanFreeMemoryFunction>(
  884. ::GetProcAddress(wlan_api_library_, kWlanFreeMemory));
  885. WlanGetAvailableNetworkList_function_ =
  886. reinterpret_cast<WlanGetAvailableNetworkListFunction>(
  887. ::GetProcAddress(wlan_api_library_, kWlanGetAvailableNetworkList));
  888. WlanGetNetworkBssList_function_ =
  889. reinterpret_cast<WlanGetNetworkBssListFunction>(
  890. ::GetProcAddress(wlan_api_library_, kWlanGetNetworkBssList));
  891. WlanGetProfile_function_ =
  892. reinterpret_cast<WlanGetProfileFunction>(
  893. ::GetProcAddress(wlan_api_library_, kWlanGetProfile));
  894. WlanOpenHandle_function_ =
  895. reinterpret_cast<WlanOpenHandleFunction>(
  896. ::GetProcAddress(wlan_api_library_, kWlanOpenHandle));
  897. WlanQueryInterface_function_ =
  898. reinterpret_cast<WlanQueryInterfaceFunction>(
  899. ::GetProcAddress(wlan_api_library_, kWlanQueryInterface));
  900. WlanRegisterNotification_function_ =
  901. reinterpret_cast<WlanRegisterNotificationFunction>(
  902. ::GetProcAddress(wlan_api_library_, kWlanRegisterNotification));
  903. WlanSaveTemporaryProfile_function_ =
  904. reinterpret_cast<WlanSaveTemporaryProfileFunction>(
  905. ::GetProcAddress(wlan_api_library_, kWlanSaveTemporaryProfile));
  906. WlanScan_function_ =
  907. reinterpret_cast<WlanScanFunction>(
  908. ::GetProcAddress(wlan_api_library_, kWlanScan));
  909. WlanSetProfile_function_ =
  910. reinterpret_cast<WlanSetProfileFunction>(
  911. ::GetProcAddress(wlan_api_library_, kWlanSetProfile));
  912. if (!WlanConnect_function_ ||
  913. !WlanCloseHandle_function_ ||
  914. !WlanDeleteProfile_function_ ||
  915. !WlanDisconnect_function_ ||
  916. !WlanEnumInterfaces_function_ ||
  917. !WlanFreeMemory_function_ ||
  918. !WlanGetAvailableNetworkList_function_ ||
  919. !WlanGetProfile_function_ ||
  920. !WlanOpenHandle_function_ ||
  921. !WlanQueryInterface_function_ ||
  922. !WlanRegisterNotification_function_ ||
  923. !WlanScan_function_ ||
  924. !WlanSetProfile_function_) {
  925. LOG(ERROR) << "Unable to find required WlanApi function.";
  926. FreeLibrary(wlan_api_library_);
  927. wlan_api_library_ = nullptr;
  928. return ERROR_NOT_FOUND;
  929. }
  930. // Some WlanApi functions may not be available on XP.
  931. if (!WlanGetNetworkBssList_function_ ||
  932. !WlanSaveTemporaryProfile_function_) {
  933. DVLOG(1) << "WlanApi function is not be available on XP.";
  934. }
  935. return ERROR_SUCCESS;
  936. }
  937. DWORD WiFiServiceImpl::OpenClientHandle() {
  938. DWORD error = LoadWlanLibrary();
  939. DWORD service_version = 0;
  940. if (error != ERROR_SUCCESS)
  941. return error;
  942. // Open a handle to the service.
  943. error = WlanOpenHandle_function_(1, nullptr, &service_version, &client_);
  944. PWLAN_INTERFACE_INFO_LIST interface_list = nullptr;
  945. if (error == ERROR_SUCCESS) {
  946. // Enumerate wireless interfaces.
  947. error = WlanEnumInterfaces_function_(client_, nullptr, &interface_list);
  948. if (error == ERROR_SUCCESS) {
  949. if (interface_list && interface_list->dwNumberOfItems != 0) {
  950. // Remember first interface just in case if none are connected.
  951. interface_guid_ = interface_list->InterfaceInfo[0].InterfaceGuid;
  952. // Try to find a connected interface.
  953. for (DWORD itf = 0; itf < interface_list->dwNumberOfItems; ++itf) {
  954. if (interface_list->InterfaceInfo[itf].isState ==
  955. wlan_interface_state_connected) {
  956. // Found connected interface, remember it!
  957. interface_guid_ = interface_list->InterfaceInfo[itf].InterfaceGuid;
  958. break;
  959. }
  960. }
  961. } else {
  962. error = ERROR_NOINTERFACE;
  963. }
  964. }
  965. // Clean up..
  966. if (interface_list)
  967. WlanFreeMemory_function_(interface_list);
  968. }
  969. return error;
  970. }
  971. DWORD WiFiServiceImpl::ResetDHCP() {
  972. IP_ADAPTER_INDEX_MAP adapter_index_map = {0};
  973. DWORD error = FindAdapterIndexMapByGUID(interface_guid_, &adapter_index_map);
  974. if (error != ERROR_SUCCESS) {
  975. LOG(ERROR) << error;
  976. return error;
  977. }
  978. error = ::IpReleaseAddress(&adapter_index_map);
  979. if (error != ERROR_SUCCESS) {
  980. if (error != ERROR_ADDRESS_NOT_ASSOCIATED) {
  981. LOG(ERROR) << error;
  982. return error;
  983. }
  984. DVLOG(1) << "Ignoring IpReleaseAddress Error: " << error;
  985. }
  986. error = ::IpRenewAddress(&adapter_index_map);
  987. if (error != ERROR_SUCCESS)
  988. LOG(ERROR) << error;
  989. return error;
  990. }
  991. DWORD WiFiServiceImpl::FindAdapterIndexMapByGUID(
  992. const GUID& interface_guid,
  993. IP_ADAPTER_INDEX_MAP* adapter_index_map) {
  994. const auto guid_string = base::win::WStringFromGUID(interface_guid);
  995. ULONG buffer_length = 0;
  996. DWORD error = ::GetInterfaceInfo(nullptr, &buffer_length);
  997. if (error == ERROR_INSUFFICIENT_BUFFER) {
  998. std::unique_ptr<unsigned char[]> buffer(new unsigned char[buffer_length]);
  999. IP_INTERFACE_INFO* interface_info =
  1000. reinterpret_cast<IP_INTERFACE_INFO*>(buffer.get());
  1001. error = GetInterfaceInfo(interface_info, &buffer_length);
  1002. if (error == ERROR_SUCCESS) {
  1003. for (int adapter = 0; adapter < interface_info->NumAdapters; ++adapter) {
  1004. if (base::EndsWith(
  1005. interface_info->Adapter[adapter].Name, guid_string,
  1006. base::CompareCase::INSENSITIVE_ASCII)) {
  1007. *adapter_index_map = interface_info->Adapter[adapter];
  1008. break;
  1009. }
  1010. }
  1011. }
  1012. }
  1013. return error;
  1014. }
  1015. DWORD WiFiServiceImpl::DisableNwCategoryWizard() {
  1016. base::win::RegKey nw_category_wizard;
  1017. DWORD error = nw_category_wizard.Open(HKEY_CURRENT_USER,
  1018. kNwCategoryWizardRegKey,
  1019. KEY_READ | KEY_SET_VALUE);
  1020. if (error == ERROR_SUCCESS) {
  1021. // Save current value if present.
  1022. if (nw_category_wizard.HasValue(kNwCategoryWizardRegValue)) {
  1023. DWORD saved = 0u;
  1024. error = nw_category_wizard.ReadValueDW(kNwCategoryWizardRegValue,
  1025. &saved);
  1026. if (error == ERROR_SUCCESS) {
  1027. error = nw_category_wizard.WriteValue(kNwCategoryWizardSavedRegValue,
  1028. saved);
  1029. }
  1030. } else {
  1031. // Mark that temporary value has to be deleted.
  1032. error = nw_category_wizard.WriteValue(kNwCategoryWizardDeleteRegValue,
  1033. 1u);
  1034. }
  1035. // Disable network location wizard.
  1036. error = nw_category_wizard.WriteValue(kNwCategoryWizardRegValue,
  1037. static_cast<DWORD>(0));
  1038. }
  1039. return error;
  1040. }
  1041. DWORD WiFiServiceImpl::RestoreNwCategoryWizard() {
  1042. base::win::RegKey nw_category_wizard;
  1043. DWORD error = nw_category_wizard.Open(HKEY_CURRENT_USER,
  1044. kNwCategoryWizardRegKey,
  1045. KEY_SET_VALUE);
  1046. if (error == ERROR_SUCCESS) {
  1047. // Restore saved value if present.
  1048. if (nw_category_wizard.HasValue(kNwCategoryWizardSavedRegValue)) {
  1049. DWORD saved = 0u;
  1050. error = nw_category_wizard.ReadValueDW(kNwCategoryWizardSavedRegValue,
  1051. &saved);
  1052. if (error == ERROR_SUCCESS) {
  1053. error = nw_category_wizard.WriteValue(kNwCategoryWizardRegValue,
  1054. saved);
  1055. error = nw_category_wizard.DeleteValue(kNwCategoryWizardSavedRegValue);
  1056. }
  1057. } else if (nw_category_wizard.HasValue(kNwCategoryWizardDeleteRegValue)) {
  1058. error = nw_category_wizard.DeleteValue(kNwCategoryWizardRegValue);
  1059. error = nw_category_wizard.DeleteValue(kNwCategoryWizardDeleteRegValue);
  1060. }
  1061. }
  1062. return error;
  1063. }
  1064. DWORD WiFiServiceImpl::EnsureInitialized() {
  1065. if (client_)
  1066. return ERROR_SUCCESS;
  1067. return ERROR_NOINTERFACE;
  1068. }
  1069. DWORD WiFiServiceImpl::CloseClientHandle() {
  1070. DWORD error = ERROR_SUCCESS;
  1071. if (client_) {
  1072. error = WlanCloseHandle_function_(client_, nullptr);
  1073. client_ = nullptr;
  1074. }
  1075. if (wlan_api_library_) {
  1076. WlanConnect_function_ = nullptr;
  1077. WlanCloseHandle_function_ = nullptr;
  1078. WlanDeleteProfile_function_ = nullptr;
  1079. WlanDisconnect_function_ = nullptr;
  1080. WlanEnumInterfaces_function_ = nullptr;
  1081. WlanFreeMemory_function_ = nullptr;
  1082. WlanGetAvailableNetworkList_function_ = nullptr;
  1083. WlanGetNetworkBssList_function_ = nullptr;
  1084. WlanGetProfile_function_ = nullptr;
  1085. WlanOpenHandle_function_ = nullptr;
  1086. WlanRegisterNotification_function_ = nullptr;
  1087. WlanSaveTemporaryProfile_function_ = nullptr;
  1088. WlanScan_function_ = nullptr;
  1089. WlanSetProfile_function_ = nullptr;
  1090. ::FreeLibrary(wlan_api_library_);
  1091. wlan_api_library_ = nullptr;
  1092. }
  1093. return error;
  1094. }
  1095. DOT11_SSID WiFiServiceImpl::SSIDFromGUID(
  1096. const std::string& network_guid) const {
  1097. DOT11_SSID ssid = {0};
  1098. if (network_guid.length() <= DOT11_SSID_MAX_LENGTH) {
  1099. ssid.uSSIDLength = static_cast<ULONG>(network_guid.length());
  1100. strncpy(reinterpret_cast<char*>(ssid.ucSSID),
  1101. network_guid.c_str(),
  1102. ssid.uSSIDLength);
  1103. } else {
  1104. NOTREACHED();
  1105. }
  1106. return ssid;
  1107. }
  1108. std::string WiFiServiceImpl::SecurityFromDot11AuthAlg(
  1109. DOT11_AUTH_ALGORITHM alg) const {
  1110. switch (alg) {
  1111. case DOT11_AUTH_ALGO_RSNA:
  1112. return onc::wifi::kWPA_EAP;
  1113. case DOT11_AUTH_ALGO_RSNA_PSK:
  1114. return onc::wifi::kWPA_PSK;
  1115. case DOT11_AUTH_ALGO_80211_SHARED_KEY:
  1116. return onc::wifi::kWEP_PSK;
  1117. case DOT11_AUTH_ALGO_80211_OPEN:
  1118. return onc::wifi::kSecurityNone;
  1119. default:
  1120. return onc::wifi::kWPA_EAP;
  1121. }
  1122. }
  1123. std::string WiFiServiceImpl::ConnectionStateFromInterfaceState(
  1124. WLAN_INTERFACE_STATE wlan_state) const {
  1125. switch (wlan_state) {
  1126. case wlan_interface_state_connected:
  1127. // TODO(mef): Even if |wlan_state| is connected, the network may still
  1128. // not be reachable, and should be resported as |kConnecting|.
  1129. return onc::connection_state::kConnected;
  1130. case wlan_interface_state_associating:
  1131. case wlan_interface_state_discovering:
  1132. case wlan_interface_state_authenticating:
  1133. return onc::connection_state::kConnecting;
  1134. default:
  1135. return onc::connection_state::kNotConnected;
  1136. }
  1137. }
  1138. void WiFiServiceImpl::NetworkPropertiesFromAvailableNetwork(
  1139. const WLAN_AVAILABLE_NETWORK& wlan,
  1140. NetworkProperties* properties) {
  1141. // TODO(mef): It would be nice for the connection states in
  1142. // getVisibleNetworks and getProperties results to be consistent.
  1143. if (wlan.dwFlags & WLAN_AVAILABLE_NETWORK_CONNECTED) {
  1144. properties->connection_state = onc::connection_state::kConnected;
  1145. } else {
  1146. properties->connection_state = onc::connection_state::kNotConnected;
  1147. }
  1148. properties->ssid = SSIDFromWLAN(wlan);
  1149. properties->name = properties->ssid;
  1150. properties->guid = GUIDFromWLAN(wlan);
  1151. properties->type = onc::network_type::kWiFi;
  1152. properties->security =
  1153. SecurityFromDot11AuthAlg(wlan.dot11DefaultAuthAlgorithm);
  1154. properties->signal_strength = wlan.wlanSignalQuality;
  1155. }
  1156. void WiFiServiceImpl::UpdateNetworkPropertiesFromBssList(
  1157. const std::string& network_guid,
  1158. const WLAN_BSS_LIST& wlan_bss_list,
  1159. NetworkProperties* properties) {
  1160. if (network_guid.empty())
  1161. return;
  1162. DOT11_SSID ssid = SSIDFromGUID(network_guid);
  1163. for (size_t bss = 0; bss < wlan_bss_list.dwNumberOfItems; ++bss) {
  1164. const WLAN_BSS_ENTRY& bss_entry(wlan_bss_list.wlanBssEntries[bss]);
  1165. if (bss_entry.dot11Ssid.uSSIDLength == ssid.uSSIDLength &&
  1166. 0 == memcmp(bss_entry.dot11Ssid.ucSSID,
  1167. ssid.ucSSID,
  1168. bss_entry.dot11Ssid.uSSIDLength)) {
  1169. std::string bssid = NetworkProperties::MacAddressAsString(
  1170. bss_entry.dot11Bssid);
  1171. Frequency frequency = GetNormalizedFrequency(
  1172. bss_entry.ulChCenterFrequency / 1000);
  1173. properties->frequency_set.insert(frequency);
  1174. if (properties->bssid.empty() || properties->bssid == bssid) {
  1175. properties->frequency = frequency;
  1176. properties->bssid = bssid;
  1177. }
  1178. }
  1179. }
  1180. }
  1181. // Get the list of visible wireless networks
  1182. DWORD WiFiServiceImpl::GetVisibleNetworkList(NetworkList* network_list) {
  1183. DCHECK(client_);
  1184. DWORD error = ERROR_SUCCESS;
  1185. PWLAN_AVAILABLE_NETWORK_LIST available_network_list = nullptr;
  1186. PWLAN_BSS_LIST bss_list = nullptr;
  1187. error = WlanGetAvailableNetworkList_function_(
  1188. client_, &interface_guid_,
  1189. WLAN_AVAILABLE_NETWORK_INCLUDE_ALL_MANUAL_HIDDEN_PROFILES, nullptr,
  1190. &available_network_list);
  1191. std::set<std::string> network_guids;
  1192. if (error == ERROR_SUCCESS &&
  1193. available_network_list &&
  1194. WlanGetNetworkBssList_function_) {
  1195. // TODO(mef): WlanGetNetworkBssList is not available on XP. If XP support is
  1196. // needed, then different method of getting BSS (e.g. OID query) will have
  1197. // to be used.
  1198. error = WlanGetNetworkBssList_function_(client_, &interface_guid_, nullptr,
  1199. dot11_BSS_type_any, FALSE, nullptr,
  1200. &bss_list);
  1201. if (error == ERROR_SUCCESS && bss_list) {
  1202. for (DWORD i = 0; i < available_network_list->dwNumberOfItems; ++i) {
  1203. NetworkProperties network_properties;
  1204. NetworkPropertiesFromAvailableNetwork(
  1205. available_network_list->Network[i], &network_properties);
  1206. UpdateNetworkPropertiesFromBssList(network_properties.guid, *bss_list,
  1207. &network_properties);
  1208. // Check for duplicate network guids.
  1209. if (network_guids.count(network_properties.guid)) {
  1210. // There should be no difference between properties except for
  1211. // |connection_state|, so mark it as |kConnected| if either one is.
  1212. if (network_properties.connection_state ==
  1213. onc::connection_state::kConnected) {
  1214. NetworkList::iterator previous_network_properties =
  1215. FindNetwork(*network_list, network_properties.guid);
  1216. DCHECK(previous_network_properties != network_list->end());
  1217. previous_network_properties->connection_state =
  1218. network_properties.connection_state;
  1219. }
  1220. } else {
  1221. network_list->push_back(network_properties);
  1222. }
  1223. network_guids.insert(network_properties.guid);
  1224. }
  1225. }
  1226. }
  1227. // Clean up.
  1228. if (available_network_list) {
  1229. WlanFreeMemory_function_(available_network_list);
  1230. }
  1231. if (bss_list) {
  1232. WlanFreeMemory_function_(bss_list);
  1233. }
  1234. return error;
  1235. }
  1236. DWORD WiFiServiceImpl::GetCurrentProperties(NetworkProperties* properties) {
  1237. DCHECK(client_);
  1238. // TODO(mef): WlanGetNetworkBssList is not available on XP. If XP support is
  1239. // needed, then different method of getting BSS (e.g. OID query) will have
  1240. // to be used.
  1241. if (!WlanGetNetworkBssList_function_)
  1242. return ERROR_NOINTERFACE;
  1243. DWORD error = ERROR_SUCCESS;
  1244. DWORD data_size = 0;
  1245. PWLAN_CONNECTION_ATTRIBUTES wlan_connection_attributes = nullptr;
  1246. PWLAN_BSS_LIST bss_list = nullptr;
  1247. error = WlanQueryInterface_function_(
  1248. client_, &interface_guid_, wlan_intf_opcode_current_connection, nullptr,
  1249. &data_size, reinterpret_cast<PVOID*>(&wlan_connection_attributes),
  1250. nullptr);
  1251. if (error == ERROR_SUCCESS && wlan_connection_attributes != nullptr) {
  1252. WLAN_ASSOCIATION_ATTRIBUTES& connected_wlan =
  1253. wlan_connection_attributes->wlanAssociationAttributes;
  1254. properties->connection_state = ConnectionStateFromInterfaceState(
  1255. wlan_connection_attributes->isState);
  1256. properties->ssid = GUIDFromSSID(connected_wlan.dot11Ssid);
  1257. properties->name = properties->ssid;
  1258. properties->guid = GUIDFromSSID(connected_wlan.dot11Ssid);
  1259. properties->type = onc::network_type::kWiFi;
  1260. properties->bssid = NetworkProperties::MacAddressAsString(
  1261. connected_wlan.dot11Bssid);
  1262. properties->security = SecurityFromDot11AuthAlg(
  1263. wlan_connection_attributes->wlanSecurityAttributes.dot11AuthAlgorithm);
  1264. properties->signal_strength = connected_wlan.wlanSignalQuality;
  1265. error = WlanGetNetworkBssList_function_(
  1266. client_, &interface_guid_, &connected_wlan.dot11Ssid,
  1267. connected_wlan.dot11BssType, FALSE, nullptr, &bss_list);
  1268. if (error == ERROR_SUCCESS && bss_list) {
  1269. UpdateNetworkPropertiesFromBssList(properties->guid, *bss_list,
  1270. properties);
  1271. }
  1272. }
  1273. // Clean up.
  1274. if (wlan_connection_attributes)
  1275. WlanFreeMemory_function_(wlan_connection_attributes);
  1276. if (bss_list)
  1277. WlanFreeMemory_function_(bss_list);
  1278. return error;
  1279. }
  1280. DWORD WiFiServiceImpl::GetCurrentSSID(std::string* ssid) {
  1281. DCHECK(client_);
  1282. DWORD error = ERROR_SUCCESS;
  1283. DWORD data_size = 0;
  1284. PWLAN_CONNECTION_ATTRIBUTES wlan_connection_attributes = nullptr;
  1285. error = WlanQueryInterface_function_(
  1286. client_, &interface_guid_, wlan_intf_opcode_current_connection, nullptr,
  1287. &data_size, reinterpret_cast<PVOID*>(&wlan_connection_attributes),
  1288. nullptr);
  1289. if (error == ERROR_SUCCESS && wlan_connection_attributes) {
  1290. WLAN_ASSOCIATION_ATTRIBUTES& connected_wlan =
  1291. wlan_connection_attributes->wlanAssociationAttributes;
  1292. *ssid = GUIDFromSSID(connected_wlan.dot11Ssid);
  1293. }
  1294. // Clean up.
  1295. if (wlan_connection_attributes)
  1296. WlanFreeMemory_function_(wlan_connection_attributes);
  1297. return error;
  1298. }
  1299. Frequency WiFiServiceImpl::GetFrequencyToConnect(
  1300. const std::string& network_guid) const {
  1301. // Check whether desired frequency is set in |connect_properties_|.
  1302. const base::Value::Dict* properties =
  1303. connect_properties_.FindDict(network_guid);
  1304. if (properties) {
  1305. const base::Value::Dict* wifi =
  1306. properties->FindDict(onc::network_type::kWiFi);
  1307. if (wifi) {
  1308. absl::optional<int> frequency = wifi->FindInt(onc::wifi::kFrequency);
  1309. if (frequency.has_value())
  1310. return GetNormalizedFrequency(*frequency);
  1311. }
  1312. }
  1313. return kFrequencyAny;
  1314. }
  1315. DWORD WiFiServiceImpl::GetDesiredBssList(
  1316. DOT11_SSID& ssid,
  1317. Frequency frequency,
  1318. std::unique_ptr<DOT11_BSSID_LIST>* desired_list) {
  1319. DCHECK(client_);
  1320. desired_list->reset();
  1321. if (frequency == kFrequencyAny)
  1322. return ERROR_SUCCESS;
  1323. // TODO(mef): WlanGetNetworkBssList is not available on XP. If XP support is
  1324. // needed, then different method of getting BSS (e.g. OID query) will have
  1325. // to be used.
  1326. if (!WlanGetNetworkBssList_function_)
  1327. return ERROR_NOT_SUPPORTED;
  1328. DWORD error = ERROR_SUCCESS;
  1329. PWLAN_BSS_LIST bss_list = nullptr;
  1330. error = WlanGetNetworkBssList_function_(client_, &interface_guid_, &ssid,
  1331. dot11_BSS_type_infrastructure, FALSE,
  1332. nullptr, &bss_list);
  1333. if (error == ERROR_SUCCESS && bss_list) {
  1334. unsigned int best_quality = 0u;
  1335. size_t best_index = 0;
  1336. Frequency bss_frequency;
  1337. // Go through bss_list and find best quality BSSID with matching frequency.
  1338. for (size_t bss = 0; bss < bss_list->dwNumberOfItems; ++bss) {
  1339. const WLAN_BSS_ENTRY& bss_entry(bss_list->wlanBssEntries[bss]);
  1340. if (bss_entry.dot11Ssid.uSSIDLength != ssid.uSSIDLength ||
  1341. 0 != memcmp(bss_entry.dot11Ssid.ucSSID,
  1342. ssid.ucSSID,
  1343. bss_entry.dot11Ssid.uSSIDLength))
  1344. continue;
  1345. bss_frequency = GetNormalizedFrequency(
  1346. bss_entry.ulChCenterFrequency / 1000);
  1347. if (bss_frequency == frequency &&
  1348. bss_entry.uLinkQuality > best_quality) {
  1349. best_quality = bss_entry.uLinkQuality;
  1350. best_index = bss;
  1351. }
  1352. }
  1353. // If any matching BSS were found, prepare the header.
  1354. if (best_quality > 0) {
  1355. const WLAN_BSS_ENTRY& bss_entry(bss_list->wlanBssEntries[best_index]);
  1356. std::unique_ptr<DOT11_BSSID_LIST> selected_list(new DOT11_BSSID_LIST);
  1357. selected_list->Header.Revision = DOT11_BSSID_LIST_REVISION_1;
  1358. selected_list->Header.Size = sizeof(DOT11_BSSID_LIST);
  1359. selected_list->Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
  1360. selected_list->uNumOfEntries = 1;
  1361. selected_list->uTotalNumOfEntries = 1;
  1362. std::copy(bss_entry.dot11Bssid,
  1363. bss_entry.dot11Bssid + sizeof(bss_entry.dot11Bssid),
  1364. selected_list->BSSIDs[0]);
  1365. desired_list->swap(selected_list);
  1366. DVLOG(1) << "Quality: " << best_quality << " BSS: "
  1367. << NetworkProperties::MacAddressAsString(bss_entry.dot11Bssid);
  1368. } else {
  1369. error = ERROR_NOT_FOUND;
  1370. }
  1371. }
  1372. // Clean up.
  1373. if (bss_list) {
  1374. WlanFreeMemory_function_(bss_list);
  1375. }
  1376. return error;
  1377. }
  1378. Frequency WiFiServiceImpl::GetNormalizedFrequency(int frequency_in_mhz) const {
  1379. if (frequency_in_mhz == 0)
  1380. return kFrequencyAny;
  1381. if (frequency_in_mhz < 3000)
  1382. return kFrequency2400;
  1383. return kFrequency5000;
  1384. }
  1385. DWORD WiFiServiceImpl::Connect(const std::string& network_guid,
  1386. Frequency frequency) {
  1387. DCHECK(client_);
  1388. DWORD error = ERROR_SUCCESS;
  1389. DOT11_SSID ssid = SSIDFromGUID(network_guid);
  1390. std::unique_ptr<DOT11_BSSID_LIST> desired_bss_list;
  1391. error = GetDesiredBssList(ssid, frequency, &desired_bss_list);
  1392. if (error == ERROR_SUCCESS) {
  1393. if (HaveProfile(network_guid)) {
  1394. std::wstring profile_name = ProfileNameFromGUID(network_guid);
  1395. WLAN_CONNECTION_PARAMETERS wlan_params = {
  1396. wlan_connection_mode_profile, profile_name.c_str(), nullptr,
  1397. desired_bss_list.get(), dot11_BSS_type_any, 0};
  1398. error = WlanConnect_function_(client_, &interface_guid_, &wlan_params,
  1399. nullptr);
  1400. } else {
  1401. // If network is available, but is not open security, then it cannot be
  1402. // connected without profile, so return 'access denied' error.
  1403. base::Value::Dict properties;
  1404. std::string error_string;
  1405. GetProperties(network_guid, &properties, &error_string);
  1406. if (error_string.empty()) {
  1407. const base::Value::Dict* wifi =
  1408. properties.FindDict(onc::network_type::kWiFi);
  1409. if (wifi) {
  1410. const std::string* wifi_security =
  1411. wifi->FindString(onc::wifi::kSecurity);
  1412. if (wifi_security && *wifi_security != onc::wifi::kSecurityNone) {
  1413. error = ERROR_ACCESS_DENIED;
  1414. LOG(ERROR) << error;
  1415. return error;
  1416. }
  1417. }
  1418. }
  1419. WLAN_CONNECTION_PARAMETERS wlan_params = {
  1420. wlan_connection_mode_discovery_unsecure,
  1421. nullptr,
  1422. &ssid,
  1423. desired_bss_list.get(),
  1424. dot11_BSS_type_infrastructure,
  1425. 0};
  1426. error = WlanConnect_function_(client_, &interface_guid_, &wlan_params,
  1427. nullptr);
  1428. }
  1429. }
  1430. return error;
  1431. }
  1432. DWORD WiFiServiceImpl::Disconnect() {
  1433. DCHECK(client_);
  1434. DWORD error = ERROR_SUCCESS;
  1435. error = WlanDisconnect_function_(client_, &interface_guid_, nullptr);
  1436. return error;
  1437. }
  1438. DWORD WiFiServiceImpl::SaveTempProfile(const std::string& network_guid) {
  1439. DCHECK(client_);
  1440. DWORD error = ERROR_SUCCESS;
  1441. std::wstring profile_name = ProfileNameFromGUID(network_guid);
  1442. // TODO(mef): WlanSaveTemporaryProfile is not available on XP. If XP support
  1443. // is needed, then different method of saving network profile will have to be
  1444. // used.
  1445. if (WlanSaveTemporaryProfile_function_) {
  1446. error = WlanSaveTemporaryProfile_function_(
  1447. client_, &interface_guid_, profile_name.c_str(), nullptr,
  1448. WLAN_PROFILE_USER, true, nullptr);
  1449. } else {
  1450. error = ERROR_NOT_SUPPORTED;
  1451. }
  1452. return error;
  1453. }
  1454. DWORD WiFiServiceImpl::GetProfile(const std::string& network_guid,
  1455. bool get_plaintext_key,
  1456. std::string* profile_xml) {
  1457. DCHECK(client_);
  1458. DWORD error = ERROR_SUCCESS;
  1459. std::wstring profile_name = ProfileNameFromGUID(network_guid);
  1460. DWORD flags = get_plaintext_key ? WLAN_PROFILE_GET_PLAINTEXT_KEY : 0;
  1461. LPWSTR str_profile_xml = nullptr;
  1462. error =
  1463. WlanGetProfile_function_(client_, &interface_guid_, profile_name.c_str(),
  1464. nullptr, &str_profile_xml, &flags, nullptr);
  1465. if (error == ERROR_SUCCESS && str_profile_xml) {
  1466. *profile_xml = base::WideToUTF8(str_profile_xml);
  1467. }
  1468. // Clean up.
  1469. if (str_profile_xml) {
  1470. WlanFreeMemory_function_(str_profile_xml);
  1471. }
  1472. return error;
  1473. }
  1474. DWORD WiFiServiceImpl::SetProfile(bool shared,
  1475. const std::string& profile_xml,
  1476. bool overwrite) {
  1477. DWORD error_code = ERROR_SUCCESS;
  1478. std::wstring profile_xml16(base::UTF8ToWide(profile_xml));
  1479. DWORD reason_code = 0u;
  1480. error_code = WlanSetProfile_function_(
  1481. client_, &interface_guid_, shared ? 0 : WLAN_PROFILE_USER,
  1482. profile_xml16.c_str(), nullptr, overwrite, nullptr, &reason_code);
  1483. return error_code;
  1484. }
  1485. bool WiFiServiceImpl::HaveProfile(const std::string& network_guid) {
  1486. std::string profile_xml;
  1487. return GetProfile(network_guid, false, &profile_xml) == ERROR_SUCCESS;
  1488. }
  1489. DWORD WiFiServiceImpl::DeleteCreatedProfile(const std::string& network_guid) {
  1490. DWORD error_code = ERROR_SUCCESS;
  1491. // Check, whether this connection is using new created profile, and remove it.
  1492. if (created_profiles_.contains(network_guid)) {
  1493. // Connection has failed, so delete it.
  1494. std::wstring profile_name = ProfileNameFromGUID(network_guid);
  1495. error_code = WlanDeleteProfile_function_(client_, &interface_guid_,
  1496. profile_name.c_str(), nullptr);
  1497. created_profiles_.Remove(network_guid);
  1498. }
  1499. return error_code;
  1500. }
  1501. std::string WiFiServiceImpl::WpaEncryptionFromEncryptionType(
  1502. EncryptionType encryption_type) const {
  1503. if (encryption_type == kEncryptionTypeTKIP)
  1504. return kEncryptionTKIP;
  1505. return kEncryptionAES;
  1506. }
  1507. bool WiFiServiceImpl::AuthEncryptionFromSecurity(
  1508. const std::string& security,
  1509. EncryptionType encryption_type,
  1510. std::string* authentication,
  1511. std::string* encryption,
  1512. std::string* key_type) const {
  1513. if (security == onc::wifi::kSecurityNone) {
  1514. *authentication = kAuthenticationOpen;
  1515. *encryption = kEncryptionNone;
  1516. } else if (security == onc::wifi::kWEP_PSK) {
  1517. *authentication = kAuthenticationWepPsk;
  1518. *encryption = kEncryptionWEP;
  1519. *key_type = kKeyTypeNetwork;
  1520. } else if (security == onc::wifi::kWPA_PSK) {
  1521. *authentication = kAuthenticationWpaPsk;
  1522. *encryption = WpaEncryptionFromEncryptionType(encryption_type);
  1523. *key_type = kKeyTypePassphrase;
  1524. } else if (security == onc::wifi::kWPA2_PSK) {
  1525. *authentication = kAuthenticationWpa2Psk;
  1526. *encryption = WpaEncryptionFromEncryptionType(encryption_type);
  1527. *key_type = kKeyTypePassphrase;
  1528. } else {
  1529. return false;
  1530. }
  1531. return true;
  1532. }
  1533. bool WiFiServiceImpl::CreateProfile(
  1534. const NetworkProperties& network_properties,
  1535. EncryptionType encryption_type,
  1536. std::string* profile_xml) {
  1537. // Get authentication and encryption values from security.
  1538. std::string authentication;
  1539. std::string encryption;
  1540. std::string key_type;
  1541. bool valid = AuthEncryptionFromSecurity(network_properties.security,
  1542. encryption_type,
  1543. &authentication,
  1544. &encryption,
  1545. &key_type);
  1546. if (!valid)
  1547. return valid;
  1548. // Generate profile XML.
  1549. XmlWriter xml_writer;
  1550. xml_writer.StartWriting();
  1551. xml_writer.StartElement("WLANProfile");
  1552. xml_writer.AddAttribute(
  1553. "xmlns",
  1554. "http://www.microsoft.com/networking/WLAN/profile/v1");
  1555. xml_writer.WriteElement("name", network_properties.guid);
  1556. xml_writer.StartElement("SSIDConfig");
  1557. xml_writer.StartElement("SSID");
  1558. xml_writer.WriteElement("name", network_properties.ssid);
  1559. xml_writer.EndElement(); // Ends "SSID" element.
  1560. xml_writer.EndElement(); // Ends "SSIDConfig" element.
  1561. xml_writer.WriteElement("connectionType", "ESS");
  1562. xml_writer.WriteElement("connectionMode", "manual");
  1563. xml_writer.StartElement("MSM");
  1564. xml_writer.StartElement("security");
  1565. xml_writer.StartElement("authEncryption");
  1566. xml_writer.WriteElement("authentication", authentication);
  1567. xml_writer.WriteElement("encryption", encryption);
  1568. xml_writer.WriteElement("useOneX", "false");
  1569. xml_writer.EndElement(); // Ends "authEncryption" element.
  1570. if (!key_type.empty()) {
  1571. xml_writer.StartElement("sharedKey");
  1572. xml_writer.WriteElement("keyType", key_type);
  1573. xml_writer.WriteElement("protected", "false");
  1574. xml_writer.WriteElement("keyMaterial", network_properties.password);
  1575. xml_writer.EndElement(); // Ends "sharedKey" element.
  1576. }
  1577. xml_writer.EndElement(); // Ends "security" element.
  1578. xml_writer.EndElement(); // Ends "MSM" element.
  1579. xml_writer.EndElement(); // Ends "WLANProfile" element.
  1580. xml_writer.StopWriting();
  1581. *profile_xml = xml_writer.GetWrittenString();
  1582. return true;
  1583. }
  1584. void WiFiServiceImpl::NotifyNetworkListChanged(const NetworkList& networks) {
  1585. if (!network_list_changed_observer_)
  1586. return;
  1587. NetworkGuidList current_networks;
  1588. for (NetworkList::const_iterator it = networks.begin();
  1589. it != networks.end();
  1590. ++it) {
  1591. current_networks.push_back(it->guid);
  1592. }
  1593. event_task_runner_->PostTask(
  1594. FROM_HERE,
  1595. base::BindOnce(network_list_changed_observer_, current_networks));
  1596. }
  1597. void WiFiServiceImpl::NotifyNetworkChanged(const std::string& network_guid) {
  1598. if (enable_notify_network_changed_ && networks_changed_observer_) {
  1599. DVLOG(1) << "NotifyNetworkChanged: " << network_guid;
  1600. NetworkGuidList changed_networks(1, network_guid);
  1601. event_task_runner_->PostTask(
  1602. FROM_HERE,
  1603. base::BindOnce(networks_changed_observer_, changed_networks));
  1604. }
  1605. }
  1606. WiFiService* WiFiService::Create() { return new WiFiServiceImpl(); }
  1607. } // namespace wifi