OLD | NEW |
(Empty) | |
| 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 |
| 5 #include "chrome/utility/wifi/wifi_service.h" |
| 6 |
| 7 #include <wlanapi.h> |
| 8 #pragma comment(lib, "Wlanapi.lib") |
| 9 |
| 10 #include "base/message_loop/message_loop.h" |
| 11 #include "base/strings/string16.h" |
| 12 #include "base/strings/utf_string_conversions.h" |
| 13 |
| 14 class WiFiServiceImpl : public WiFiService { |
| 15 public: |
| 16 WiFiServiceImpl() : client_(NULL) {} |
| 17 |
| 18 virtual ~WiFiServiceImpl() { CloseClientHandle(); } |
| 19 |
| 20 virtual void GetProperties(const std::string& network_guid, |
| 21 const NetworkPropertiesCallback& callback, |
| 22 const ErrorCallback& error_callback) { |
| 23 DWORD error = OpenClientHandle(); |
| 24 |
| 25 if (error == ERROR_SUCCESS) { |
| 26 NetworkList network_list; |
| 27 error = GetVisibleNetworkList(&network_list); |
| 28 if (error == ERROR_SUCCESS && !network_list.empty()) { |
| 29 NetworkList::iterator it = FindNetwork(network_list, network_guid); |
| 30 if (it != network_list.end()) |
| 31 callback.Run(network_guid, *it); |
| 32 else |
| 33 error = ERROR_NOT_FOUND; |
| 34 } |
| 35 } |
| 36 |
| 37 CheckError(error_callback, "Error.DBusFailed", error); |
| 38 } |
| 39 |
| 40 virtual void GetState(const std::string& network_guid, |
| 41 const NetworkPropertiesCallback& callback, |
| 42 const ErrorCallback& error_callback) OVERRIDE {} |
| 43 |
| 44 virtual void GetManagedProperties( |
| 45 const std::string& network_guid, |
| 46 const DictionaryResultCallback& callback, |
| 47 const ErrorCallback& error_callback) OVERRIDE {} |
| 48 |
| 49 virtual void SetProperties(const std::string& network_guid, |
| 50 const base::DictionaryValue& properties, |
| 51 const StringResultCallback& callback, |
| 52 const ErrorCallback& error_callback) OVERRIDE {} |
| 53 |
| 54 virtual void GetVisibleNetworks( |
| 55 const NetworkListCallback& callback, |
| 56 const ErrorCallback& error_callback) OVERRIDE { |
| 57 DWORD error = OpenClientHandle(); |
| 58 |
| 59 if (error == ERROR_SUCCESS) { |
| 60 NetworkList network_list; |
| 61 error = GetVisibleNetworkList(&network_list); |
| 62 if (error == ERROR_SUCCESS && !network_list.empty()) { |
| 63 SortNetworks(network_list); |
| 64 callback.Run(network_list); |
| 65 } |
| 66 } |
| 67 |
| 68 CheckError(error_callback, "Error.DBusFailed", error); |
| 69 } |
| 70 |
| 71 virtual void RequestNetworkScan() OVERRIDE {} |
| 72 |
| 73 virtual void StartConnect(const std::string& network_guid, |
| 74 const StringResultCallback& callback, |
| 75 const ErrorCallback& error_callback) OVERRIDE { |
| 76 DWORD error = OpenClientHandle(); |
| 77 |
| 78 if (error == ERROR_SUCCESS) { |
| 79 error = Connect(network_guid); |
| 80 if (error == ERROR_SUCCESS) { |
| 81 callback.Run(network_guid); |
| 82 } |
| 83 } |
| 84 |
| 85 CheckError(error_callback, "Error.DBusFailed", error); |
| 86 } |
| 87 |
| 88 virtual void StartDisconnect(const std::string& network_guid, |
| 89 const StringResultCallback& callback, |
| 90 const ErrorCallback& error_callback) OVERRIDE { |
| 91 DWORD error = OpenClientHandle(); |
| 92 |
| 93 if (error == ERROR_SUCCESS) { |
| 94 SaveTempProfile(network_guid); |
| 95 |
| 96 std::string profile_xml; |
| 97 error = GetProfile(network_guid, &profile_xml); |
| 98 if (error == ERROR_SUCCESS) { |
| 99 error = Disconnect(); |
| 100 if (error == ERROR_SUCCESS) { |
| 101 callback.Run(network_guid); |
| 102 } |
| 103 } |
| 104 } |
| 105 |
| 106 CheckError(error_callback, "Error.DBusFailed", error); |
| 107 } |
| 108 |
| 109 private: |
| 110 bool CheckError(const ErrorCallback& error_callback, |
| 111 const std::string& error_name, |
| 112 DWORD error_code) { |
| 113 if (error_code != ERROR_SUCCESS) { |
| 114 scoped_ptr<base::DictionaryValue> error_data(new base::DictionaryValue); |
| 115 error_data->SetInteger("Win32ErrorCode", error_code); |
| 116 error_callback.Run(error_name, error_data.Pass()); |
| 117 return true; |
| 118 } |
| 119 return false; |
| 120 } |
| 121 |
| 122 NetworkList::iterator FindNetwork(NetworkList& networks, |
| 123 const std::string& network_guid) { |
| 124 for (NetworkList::iterator it = networks.begin(); it != networks.end(); |
| 125 ++it) { |
| 126 if (it->guid == network_guid) |
| 127 return it; |
| 128 } |
| 129 return networks.end(); |
| 130 } |
| 131 |
| 132 void SortNetworks(NetworkList& networks) { |
| 133 // Sort networks, so connected/connecting is up front, then by type: |
| 134 // Ethernet, WiFi, Cellular, VPN |
| 135 networks.sort(WiFiService::NetworkProperties::OrderByType); |
| 136 } |
| 137 |
| 138 // open a WLAN client handle |
| 139 DWORD OpenClientHandle() { |
| 140 CloseClientHandle(); |
| 141 |
| 142 DWORD error = ERROR_SUCCESS; |
| 143 DWORD service_version = 0; |
| 144 |
| 145 // open a handle to the service |
| 146 error = WlanOpenHandle(WLAN_API_VERSION, NULL, &service_version, &client_); |
| 147 |
| 148 PWLAN_INTERFACE_INFO_LIST pIntfList = NULL; |
| 149 UINT i = 0; |
| 150 |
| 151 if (error == ERROR_SUCCESS) { |
| 152 // enumerate wireless interfaces |
| 153 error = WlanEnumInterfaces(client_, NULL, &pIntfList); |
| 154 if (error == ERROR_SUCCESS) { |
| 155 if (pIntfList != NULL && pIntfList->dwNumberOfItems != 0) { |
| 156 // Use first interface. |
| 157 interface_guid_ = pIntfList->InterfaceInfo[0].InterfaceGuid; |
| 158 } else { |
| 159 error = ERROR_NOINTERFACE; |
| 160 } |
| 161 } |
| 162 // clean up |
| 163 if (pIntfList != NULL) |
| 164 WlanFreeMemory(pIntfList); |
| 165 } |
| 166 |
| 167 return error; |
| 168 } |
| 169 |
| 170 DWORD CloseClientHandle() { |
| 171 DWORD error = ERROR_SUCCESS; |
| 172 if (client_ != NULL) { |
| 173 WlanCloseHandle(client_, NULL); |
| 174 client_ = NULL; |
| 175 } |
| 176 return error; |
| 177 } |
| 178 |
| 179 |
| 180 base::string16 ProfileNameFromGuid(const std::string& network_guid) const { |
| 181 return base::UTF8ToUTF16(network_guid); |
| 182 } |
| 183 |
| 184 DOT11_SSID SsidFromGuid(const std::string& network_guid) const { |
| 185 DOT11_SSID ssid = {0}; |
| 186 if (network_guid.length() <= DOT11_SSID_MAX_LENGTH) { |
| 187 ssid.uSSIDLength = network_guid.length(); |
| 188 strncpy(reinterpret_cast<char*>(ssid.ucSSID), |
| 189 network_guid.c_str(), |
| 190 ssid.uSSIDLength); |
| 191 } |
| 192 return ssid; |
| 193 } |
| 194 |
| 195 std::string GuidFromProfileAndSsid(const std::string& profile_name, |
| 196 const std::string& ssid) { |
| 197 return ssid; |
| 198 } |
| 199 |
| 200 WiFiService::Security SecurityFromDot11AuthAlg(DOT11_AUTH_ALGORITHM alg) { |
| 201 // TODO(mef): Figure out correct mapping. |
| 202 switch(alg) { |
| 203 case DOT11_AUTH_ALGO_RSNA: |
| 204 return kSecurityWPA; |
| 205 case DOT11_AUTH_ALGO_RSNA_PSK: |
| 206 return kSecurityWPA_PSK; |
| 207 case DOT11_AUTH_ALGO_80211_SHARED_KEY: |
| 208 return kSecurityWEP_PSK; |
| 209 case DOT11_AUTH_ALGO_80211_OPEN: |
| 210 return kSecurityNone; |
| 211 default: |
| 212 return kSecurityUnknown; |
| 213 } |
| 214 return kSecurityUnknown; |
| 215 } |
| 216 |
| 217 void NetworkPropertiesFromAvailableNetwork(const WLAN_AVAILABLE_NETWORK& wlan, |
| 218 const WLAN_BSS_LIST& wlan_bss_list, |
| 219 NetworkProperties* properties) { |
| 220 if (wlan.dwFlags & WLAN_AVAILABLE_NETWORK_CONNECTED) { |
| 221 properties->connection_state = WiFiService::kConnectionStateConnected; |
| 222 } else { |
| 223 properties->connection_state = WiFiService::kConnectionStateNotConnected; |
| 224 } |
| 225 |
| 226 properties->ssid = |
| 227 std::string(reinterpret_cast<const char*>(wlan.dot11Ssid.ucSSID), |
| 228 wlan.dot11Ssid.uSSIDLength); |
| 229 properties->name = properties->ssid; |
| 230 properties->guid = GuidFromProfileAndSsid(properties->name, |
| 231 properties->ssid); |
| 232 properties->type = WiFiService::kNetworkTypeWiFi; |
| 233 |
| 234 for (size_t bss = 0; bss < wlan_bss_list.dwNumberOfItems; ++bss) { |
| 235 const WLAN_BSS_ENTRY& bss_entry(wlan_bss_list.wlanBssEntries[bss]); |
| 236 if (bss_entry.dot11Ssid.uSSIDLength == wlan.dot11Ssid.uSSIDLength |
| 237 && 0 == memcmp(bss_entry.dot11Ssid.ucSSID, wlan.dot11Ssid.ucSSID, |
| 238 bss_entry.dot11Ssid.uSSIDLength)) { |
| 239 if (bss_entry.ulChCenterFrequency < 3000000) |
| 240 properties->frequency = kFrequency2400; |
| 241 else |
| 242 properties->frequency = kFrequency5000; |
| 243 properties->frequency_list.push_back(properties->frequency); |
| 244 properties->bssid = |
| 245 WiFiService::NetworkProperties::MacAddressAsString( |
| 246 bss_entry.dot11Bssid); |
| 247 } |
| 248 } |
| 249 properties->frequency_list.sort(); |
| 250 properties->frequency_list.unique(); |
| 251 |
| 252 properties->security = |
| 253 SecurityFromDot11AuthAlg(wlan.dot11DefaultAuthAlgorithm); |
| 254 |
| 255 properties->signal_strength = wlan.wlanSignalQuality; |
| 256 } |
| 257 |
| 258 // get the list of visible wireless networks |
| 259 DWORD GetVisibleNetworkList(NetworkList* network_list) { |
| 260 DWORD error = ERROR_SUCCESS; |
| 261 |
| 262 if (client_ == NULL) { |
| 263 return ERROR_NOINTERFACE; |
| 264 } |
| 265 |
| 266 PWLAN_AVAILABLE_NETWORK_LIST pVList = NULL; |
| 267 PWLAN_BSS_LIST pWlanBssList = NULL; |
| 268 |
| 269 error = WlanGetAvailableNetworkList( |
| 270 client_, &interface_guid_, 0, NULL, &pVList); |
| 271 |
| 272 if (error == ERROR_SUCCESS && NULL != pVList) { |
| 273 error = WlanGetNetworkBssList( |
| 274 client_, &interface_guid_, NULL, dot11_BSS_type_any, FALSE, NULL, |
| 275 &pWlanBssList); |
| 276 if (error == ERROR_SUCCESS && NULL != pWlanBssList) { |
| 277 for (DWORD i = 0; i < pVList->dwNumberOfItems; ++i) { |
| 278 network_list->push_back(NetworkProperties()); |
| 279 NetworkPropertiesFromAvailableNetwork(pVList->Network[i], |
| 280 *pWlanBssList, |
| 281 &network_list->back()); |
| 282 } |
| 283 } |
| 284 } |
| 285 |
| 286 // clean up |
| 287 if (pVList != NULL) { |
| 288 WlanFreeMemory(pVList); |
| 289 } |
| 290 if (pWlanBssList != NULL) { |
| 291 WlanFreeMemory(pWlanBssList); |
| 292 } |
| 293 |
| 294 return error; |
| 295 } |
| 296 |
| 297 DWORD Connect(const std::string& network_guid) { |
| 298 DWORD error = ERROR_SUCCESS; |
| 299 |
| 300 if (client_ == NULL) { |
| 301 return ERROR_NOINTERFACE; |
| 302 } |
| 303 |
| 304 base::string16 profile_name = ProfileNameFromGuid(network_guid); |
| 305 |
| 306 if(HaveProfile(network_guid)) { |
| 307 WLAN_CONNECTION_PARAMETERS wlan_params = {wlan_connection_mode_profile, |
| 308 profile_name.c_str(), |
| 309 NULL, |
| 310 NULL, |
| 311 dot11_BSS_type_any, |
| 312 0 |
| 313 }; |
| 314 error = ::WlanConnect(client_, &interface_guid_, &wlan_params, NULL); |
| 315 } else { |
| 316 DOT11_SSID ssid = SsidFromGuid(network_guid); |
| 317 WLAN_CONNECTION_PARAMETERS wlan_params = { |
| 318 wlan_connection_mode_discovery_unsecure, |
| 319 NULL, |
| 320 &ssid, |
| 321 NULL, |
| 322 dot11_BSS_type_infrastructure, |
| 323 0 |
| 324 }; |
| 325 error = ::WlanConnect(client_, &interface_guid_, &wlan_params, NULL); |
| 326 } |
| 327 |
| 328 return error; |
| 329 } |
| 330 |
| 331 DWORD Disconnect() { |
| 332 DWORD error = ERROR_SUCCESS; |
| 333 |
| 334 if (client_ == NULL) { |
| 335 return ERROR_NOINTERFACE; |
| 336 } |
| 337 |
| 338 error = ::WlanDisconnect(client_, &interface_guid_, NULL); |
| 339 return error; |
| 340 } |
| 341 |
| 342 DWORD SaveTempProfile(const std::string& network_guid) { |
| 343 DWORD error = ERROR_SUCCESS; |
| 344 |
| 345 if (client_ == NULL) { |
| 346 return ERROR_NOINTERFACE; |
| 347 } |
| 348 |
| 349 base::string16 profile_name = ProfileNameFromGuid(network_guid); |
| 350 |
| 351 error = ::WlanSaveTemporaryProfile(client_, &interface_guid_, |
| 352 profile_name.c_str(), NULL, 0, true, NULL); |
| 353 return error; |
| 354 } |
| 355 |
| 356 DWORD GetProfile(const std::string& network_guid, |
| 357 std::string* profile_xml) { |
| 358 DWORD error = ERROR_SUCCESS; |
| 359 |
| 360 if (client_ == NULL) { |
| 361 return ERROR_NOINTERFACE; |
| 362 } |
| 363 |
| 364 base::string16 profile_name = ProfileNameFromGuid(network_guid); |
| 365 LPWSTR str_profile_xml = NULL; |
| 366 error = ::WlanGetProfile(client_, &interface_guid_, |
| 367 profile_name.c_str(), NULL, &str_profile_xml, NULL, NULL); |
| 368 |
| 369 if (error == ERROR_SUCCESS && str_profile_xml != NULL) { |
| 370 *profile_xml = base::UTF16ToUTF8(str_profile_xml); |
| 371 } |
| 372 // clean up |
| 373 if (str_profile_xml != NULL) { |
| 374 WlanFreeMemory(str_profile_xml); |
| 375 } |
| 376 |
| 377 return error; |
| 378 } |
| 379 |
| 380 bool HaveProfile(const std::string& network_guid) { |
| 381 DWORD error = ERROR_SUCCESS; |
| 382 std::string profile_xml; |
| 383 return GetProfile(network_guid, &profile_xml) == ERROR_SUCCESS; |
| 384 } |
| 385 |
| 386 // Wlan Service Handle. |
| 387 HANDLE client_; |
| 388 // Wlan Interface Guid. |
| 389 GUID interface_guid_; |
| 390 |
| 391 }; |
| 392 |
| 393 WiFiService* WiFiService::CreateService() { return new WiFiServiceImpl(); } |
| 394 |
OLD | NEW |