Skip to content

Commit

Permalink
Implement Networking Private API CreateNetwork function on Windows. A…
Browse files Browse the repository at this point in the history
…llows connection to hidden WiFi networks.

Defaults to TKIP encryption for WAPPSK and AES encryption for WAP2PSK. Exact encryption to use will have to be determined during Connect.

TBR=cpu@chromium.org for +third_party/libxml to DEPS.

BUG=267667

Review URL: https://codereview.chromium.org/105153002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@240703 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
mef@chromium.org committed Dec 13, 2013
1 parent 6767530 commit e425d03
Show file tree
Hide file tree
Showing 8 changed files with 210 additions and 20 deletions.
1 change: 1 addition & 0 deletions components/onc/onc_constants.cc
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ const char kWEP_8021X[] = "WEP-8021X";
const char kWEP_PSK[] = "WEP-PSK";
const char kWPA_EAP[] = "WPA-EAP";
const char kWPA_PSK[] = "WPA-PSK";
const char kWPA2_PSK[] = "WPA2-PSK";
} // namespace wifi

namespace certificate {
Expand Down
1 change: 1 addition & 0 deletions components/onc/onc_constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ ONC_EXPORT extern const char kSignalStrength[];
ONC_EXPORT extern const char kWEP_PSK[];
ONC_EXPORT extern const char kWEP_8021X[];
ONC_EXPORT extern const char kWPA_PSK[];
ONC_EXPORT extern const char kWPA2_PSK[];
ONC_EXPORT extern const char kWPA_EAP[];
} // namespace wifi

Expand Down
3 changes: 2 additions & 1 deletion components/wifi.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
'type': '<(component)',
'dependencies': [
'../base/base.gyp:base',
'../components/components.gyp:onc_component',
'../components/components.gyp:onc_component',
'../third_party/libxml/libxml.gyp:libxml',
],
'include_dirs': [
'..',
Expand Down
1 change: 1 addition & 0 deletions components/wifi/DEPS
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
include_rules = [
"+components/onc",
"+third_party/libxml",
]
10 changes: 4 additions & 6 deletions components/wifi/wifi_service.cc
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,10 @@ bool WiFiService::NetworkProperties::UpdateFromValue(
type = network_type;
}
if (value.GetDictionary(onc::network_type::kWiFi, &wifi)) {
std::string wifi_security;
if (wifi->GetString(onc::wifi::kSecurity, &wifi_security))
security = wifi_security;
std::string wifi_ssid;
if (wifi->GetString(onc::wifi::kSSID, &wifi_ssid))
ssid = wifi_ssid;
wifi->GetString(onc::wifi::kSecurity, &security);
wifi->GetString(onc::wifi::kSSID, &ssid);
wifi->GetString(onc::wifi::kPassphrase, &password);
wifi->GetBoolean(onc::wifi::kAutoConnect, &auto_connect);
return true;
}
return false;
Expand Down
5 changes: 5 additions & 0 deletions components/wifi/wifi_service.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@ class WIFI_EXPORT WiFiService {
std::string bssid;
std::string type;
std::string security;
// |password| field is used to pass wifi password for network creation via
// |CreateNetwork| or connection via |StartConnect|. It does not persist
// once operation is completed.
std::string password;
// WiFi Signal Strength. 0..100
uint32 signal_strength;
bool auto_connect;
Expand All @@ -139,6 +143,7 @@ class WIFI_EXPORT WiFiService {
std::string json_extra; // Extra JSON properties for unit tests

scoped_ptr<base::DictionaryValue> ToValue(bool network_list) const;
// Updates only properties set in |value|.
bool UpdateFromValue(const base::DictionaryValue& value);
static std::string MacAddressAsString(const uint8 mac_as_int[6]);
static bool OrderByType(const NetworkProperties& l,
Expand Down
161 changes: 159 additions & 2 deletions components/wifi/wifi_service_win.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/win/registry.h"
#include "components/onc/onc_constants.h"
#include "third_party/libxml/chromium/libxml_utils.h"

namespace {
const char kWiFiServiceError[] = "Error.WiFiService";
Expand All @@ -46,6 +47,7 @@ const char kWlanQueryInterface[] = "WlanQueryInterface";
const char kWlanRegisterNotification[] = "WlanRegisterNotification";
const char kWlanSaveTemporaryProfile[] = "WlanSaveTemporaryProfile";
const char kWlanScan[] = "WlanScan";
const char kWlanSetProfile[] = "WlanSetProfile";

// WlanApi function definitions
typedef DWORD (WINAPI* WlanConnectFunction)(
Expand Down Expand Up @@ -136,6 +138,28 @@ typedef DWORD (WINAPI* WlanScanFunction)(
CONST PWLAN_RAW_DATA pIeData,
PVOID pReserved);

typedef DWORD (WINAPI* WlanSetProfileFunction)(
HANDLE hClientHandle,
const GUID *pInterfaceGuid,
DWORD dwFlags,
LPCWSTR strProfileXml,
LPCWSTR strAllUserProfileSecurity,
BOOL bOverwrite,
PVOID pReserved,
DWORD* pdwReasonCode);

// Values for WLANProfile XML.
const char kAuthenticationOpen[] = "open";
const char kAuthenticationWepPsk[] = "WEP";
const char kAuthenticationWpaPsk[] = "WPAPSK";
const char kAuthenticationWpa2Psk[] = "WPA2PSK";
const char kEncryptionAES[] = "AES";
const char kEncryptionNone[] = "none";
const char kEncryptionTKIP[] = "TKIP";
const char kEncryptionWEP[] = "WEP";
const char kKeyTypeNetwork[] = "networkKey";
const char kKeyTypePassphrase[] = "passPhrase";

} // namespace

namespace wifi {
Expand Down Expand Up @@ -281,6 +305,12 @@ class WiFiServiceImpl : public WiFiService, base::NonThreadSafe {
// Deduce |onc::wifi| security from |alg|.
std::string SecurityFromDot11AuthAlg(DOT11_AUTH_ALGORITHM alg) const;

// Deduce WLANProfile |authEncryption| values from |onc::wifi| security.
bool AuthEncryptionFromSecurity(const std::string& security,
std::string* authentication,
std::string* encryption,
std::string* key_type) const;

// Populate |properties| based on |wlan| and its corresponding bss info from
// |wlan_bss_list|.
void NetworkPropertiesFromAvailableNetwork(const WLAN_AVAILABLE_NETWORK& wlan,
Expand Down Expand Up @@ -321,6 +351,10 @@ class WiFiServiceImpl : public WiFiService, base::NonThreadSafe {
// Normalizes |frequency_in_mhz| into one of |Frequency| values.
Frequency GetNormalizedFrequency(int frequency_in_mhz) const;

// Create |profile_xml| based on |network_properties|.
bool CreateProfile(const NetworkProperties& network_properties,
std::string* profile_xml);

// Save temporary wireless profile for |network_guid|.
DWORD SaveTempProfile(const std::string& network_guid);

Expand Down Expand Up @@ -356,6 +390,7 @@ class WiFiServiceImpl : public WiFiService, base::NonThreadSafe {
WlanQueryInterfaceFunction WlanQueryInterface_function_;
WlanRegisterNotificationFunction WlanRegisterNotification_function_;
WlanScanFunction WlanScan_function_;
WlanSetProfileFunction WlanSetProfile_function_;
// WlanSaveTemporaryProfile function may not be avaiable on Windows XP.
WlanSaveTemporaryProfileFunction WlanSaveTemporaryProfile_function_;

Expand Down Expand Up @@ -402,6 +437,7 @@ WiFiServiceImpl::WiFiServiceImpl()
WlanRegisterNotification_function_(NULL),
WlanSaveTemporaryProfile_function_(NULL),
WlanScan_function_(NULL),
WlanSetProfile_function_(NULL),
client_(NULL),
enable_notify_network_changed_(true) {}

Expand Down Expand Up @@ -476,7 +512,41 @@ void WiFiServiceImpl::CreateNetwork(
scoped_ptr<base::DictionaryValue> properties,
std::string* network_guid,
std::string* error) {
CheckError(ERROR_CALL_NOT_IMPLEMENTED, kWiFiServiceError, error);
DWORD error_code = EnsureInitialized();
if (CheckError(error_code, kWiFiServiceError, error))
return;

WiFiService::NetworkProperties network_properties;
if (!network_properties.UpdateFromValue(*properties)) {
CheckError(ERROR_INVALID_DATA, kWiFiServiceError, error);
return;
}

network_properties.guid = network_properties.ssid;
std::string profile_xml;
if (!CreateProfile(network_properties, &profile_xml)) {
CheckError(ERROR_INVALID_DATA, kWiFiServiceError, error);
return;
}

string16 profile_xml16(UTF8ToUTF16(profile_xml));
DWORD reason_code = 0u;

error_code = WlanSetProfile_function_(client_,
&interface_guid_,
shared ? 0 : WLAN_PROFILE_USER,
profile_xml16.c_str(),
NULL,
FALSE,
NULL,
&reason_code);
if (CheckError(error_code, kWiFiServiceError, error)) {
DVLOG(0) << profile_xml;
DVLOG(0) << "SetProfile Reason Code:" << reason_code;
return;
}

*network_guid = network_properties.guid;
}

void WiFiServiceImpl::GetVisibleNetworks(const std::string& network_type,
Expand Down Expand Up @@ -751,6 +821,9 @@ DWORD WiFiServiceImpl::LoadWlanLibrary() {
WlanScan_function_ =
reinterpret_cast<WlanScanFunction>(
::GetProcAddress(wlan_api_library_, kWlanScan));
WlanSetProfile_function_ =
reinterpret_cast<WlanSetProfileFunction>(
::GetProcAddress(wlan_api_library_, kWlanSetProfile));

if (!WlanConnect_function_ ||
!WlanCloseHandle_function_ ||
Expand All @@ -762,7 +835,8 @@ DWORD WiFiServiceImpl::LoadWlanLibrary() {
!WlanOpenHandle_function_ ||
!WlanQueryInterface_function_ ||
!WlanRegisterNotification_function_ ||
!WlanScan_function_) {
!WlanScan_function_ ||
!WlanSetProfile_function_) {
DLOG(ERROR) << "Unable to find required WlanApi function.";
FreeLibrary(wlan_api_library_);
wlan_api_library_ = NULL;
Expand Down Expand Up @@ -942,6 +1016,7 @@ DWORD WiFiServiceImpl::CloseClientHandle() {
WlanRegisterNotification_function_ = NULL;
WlanSaveTemporaryProfile_function_ = NULL;
WlanScan_function_ = NULL;
WlanSetProfile_function_ = NULL;
::FreeLibrary(wlan_api_library_);
wlan_api_library_ = NULL;
}
Expand Down Expand Up @@ -1401,6 +1476,88 @@ bool WiFiServiceImpl::HaveProfile(const std::string& network_guid) {
return GetProfile(network_guid, &profile_xml) == ERROR_SUCCESS;
}

bool WiFiServiceImpl::AuthEncryptionFromSecurity(
const std::string& security,
std::string* authentication,
std::string* encryption,
std::string* key_type) const {
if (security == onc::wifi::kNone) {
*authentication = kAuthenticationOpen;
*encryption = kEncryptionNone;
} else if (security == onc::wifi::kWEP_PSK) {
*authentication = kAuthenticationOpen;
*encryption = kEncryptionWEP;
*key_type = kKeyTypeNetwork;
} else if (security == onc::wifi::kWPA_PSK) {
*authentication = kAuthenticationWpaPsk;
// TODO(mef): WAP |encryption| could be either |AES| or |TKIP|. It has to be
// determined and adjusted properly during |Connect|.
*encryption = kEncryptionAES;
*key_type = kKeyTypePassphrase;
} else if (security == onc::wifi::kWPA2_PSK) {
*authentication = kAuthenticationWpa2Psk;
// TODO(mef): WAP |encryption| could be either |AES| or |TKIP|. It has to be
// determined and adjusted properly during |Connect|.
*encryption = kEncryptionAES;
*key_type = kKeyTypePassphrase;
} else {
return false;
}
return true;
}

bool WiFiServiceImpl::CreateProfile(
const NetworkProperties& network_properties,
std::string* profile_xml) {
// Get authentication and encryption values from security.
std::string authentication;
std::string encryption;
std::string key_type;
bool valid = AuthEncryptionFromSecurity(network_properties.security,
&authentication,
&encryption,
&key_type);
if (!valid)
return valid;

// Generate profile XML.
XmlWriter xml_writer;
xml_writer.StartWriting();
xml_writer.StartElement("WLANProfile");
xml_writer.AddAttribute(
"xmlns",
"http://www.microsoft.com/networking/WLAN/profile/v1");
xml_writer.WriteElement("name", network_properties.guid);
xml_writer.StartElement("SSIDConfig");
xml_writer.StartElement("SSID");
xml_writer.WriteElement("name", network_properties.ssid);
xml_writer.EndElement(); // Ends "SSID" element.
xml_writer.EndElement(); // Ends "SSIDConfig" element.
xml_writer.WriteElement("connectionType", "ESS");
xml_writer.WriteElement("connectionMode", "manual");
xml_writer.StartElement("MSM");
xml_writer.StartElement("security");
xml_writer.StartElement("authEncryption");
xml_writer.WriteElement("authentication", authentication);
xml_writer.WriteElement("encryption", encryption);
xml_writer.WriteElement("useOneX", "false");
xml_writer.EndElement(); // Ends "authEncryption" element.
if (!key_type.empty()) {
xml_writer.StartElement("sharedKey");
xml_writer.WriteElement("keyType", key_type);
xml_writer.WriteElement("protected", "false");
xml_writer.WriteElement("keyMaterial", network_properties.password);
xml_writer.EndElement(); // Ends "sharedKey" element.
}
xml_writer.EndElement(); // Ends "security" element.
xml_writer.EndElement(); // Ends "MSM" element.
xml_writer.EndElement(); // Ends "WLANProfile" element.
xml_writer.StopWriting();
*profile_xml = xml_writer.GetWrittenString();

return true;
}

void WiFiServiceImpl::NotifyNetworkListChanged(const NetworkList& networks) {
if (network_list_changed_observer_.is_null())
return;
Expand Down
48 changes: 37 additions & 11 deletions components/wifi/wifi_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,13 @@ WiFiTest::Result WiFiTest::Main(int argc, const char* argv[]) {
VLOG(0) << "Usage: " << argv[0] <<
" [--list]"
" [--get_properties]"
" [--create]"
" [--connect]"
" [--disconnect]"
" [--network_guid=<network_guid>]"
" [--frequency=0|2400|5000]"
" [--security=none|WEP-PSK|WPA-PSK|WPA2-PSK]"
" [--password=<wifi password>]"
" [<network_guid>]\n";
return RESULT_WRONG_USAGE;
}
Expand All @@ -88,6 +91,10 @@ bool WiFiTest::ParseCommandLine(int argc, const char* argv[]) {
parsed_command_line.GetSwitchValueASCII("network_guid");
std::string frequency =
parsed_command_line.GetSwitchValueASCII("frequency");
std::string password =
parsed_command_line.GetSwitchValueASCII("password");
std::string security =
parsed_command_line.GetSwitchValueASCII("security");

if (parsed_command_line.GetArgs().size() == 1) {
#if defined(OS_WIN)
Expand Down Expand Up @@ -127,26 +134,45 @@ bool WiFiTest::ParseCommandLine(int argc, const char* argv[]) {
}
}

// Optional properties (frequency, password) to use for connect.
scoped_ptr<DictionaryValue> connect_properties(new DictionaryValue());
// Optional properties (frequency, password) to use for connect or create.
scoped_ptr<DictionaryValue> properties(new DictionaryValue());

if (parsed_command_line.HasSwitch("frequency")) {
if (!frequency.empty()) {
int value = 0;
if (!network_guid.empty() &&
!frequency.empty() &&
base::StringToInt(frequency, &value)) {
connect_properties->SetInteger("WiFi.Frequency", value);
if (base::StringToInt(frequency, &value)) {
properties->SetInteger("WiFi.Frequency", value);
// fall through to connect.
}
}

if (!password.empty())
properties->SetString("WiFi.Passphrase", password);

if (!security.empty())
properties->SetString("WiFi.Security", security);

if (parsed_command_line.HasSwitch("create")) {
if (!network_guid.empty()) {
std::string error;
std::string new_network_guid;
properties->SetString("WiFi.SSID", network_guid);
VLOG(0) << "Creating Network: " << *properties;
wifi_service->CreateNetwork(false,
properties.Pass(),
&new_network_guid,
&error);
VLOG(0) << error << ":\n" << new_network_guid;
return true;
}
}

if (parsed_command_line.HasSwitch("connect")) {
if (network_guid.length() > 0) {
if (!network_guid.empty()) {
std::string error;
if (!connect_properties->empty()) {
VLOG(0) << "Using connect properties: " << *connect_properties;
if (!properties->empty()) {
VLOG(0) << "Using connect properties: " << *properties;
wifi_service->SetProperties(network_guid,
connect_properties.Pass(),
properties.Pass(),
&error);
}
wifi_service->StartConnect(network_guid, &error);
Expand Down

0 comments on commit e425d03

Please sign in to comment.