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.
5 #include "chromeos/network/shill_property_util.h"
7 #include "base/i18n/icu_encoding_detection.h"
8 #include "base/i18n/icu_string_conversions.h"
9 #include "base/json/json_writer.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/strings/utf_string_conversion_utils.h"
14 #include "base/values.h"
15 #include "chromeos/network/network_event_log.h"
16 #include "chromeos/network/network_ui_data.h"
17 #include "chromeos/network/onc/onc_utils.h"
18 #include "third_party/cros_system_api/dbus/service_constants.h"
22 namespace shill_property_util {
26 // Replace non UTF8 characters in |str| with a replacement character.
27 std::string ValidateUTF8(const std::string& str) {
29 for (int32 index = 0; index < static_cast<int32>(str.size()); ++index) {
30 uint32 code_point_out;
31 bool is_unicode_char = base::ReadUnicodeCharacter(
32 str.c_str(), str.size(), &index, &code_point_out);
33 const uint32 kFirstNonControlChar = 0x20;
34 if (is_unicode_char && (code_point_out >= kFirstNonControlChar)) {
35 base::WriteUnicodeCharacter(code_point_out, &result);
37 const uint32 kReplacementChar = 0xFFFD;
38 // Puts kReplacementChar if character is a control character [0,0x20)
39 // or is not readable UTF8.
40 base::WriteUnicodeCharacter(kReplacementChar, &result);
46 // If existent and non-empty, copies the string at |key| from |source| to
47 // |dest|. Returns true if the string was copied.
48 bool CopyStringFromDictionary(const base::DictionaryValue& source,
49 const std::string& key,
50 base::DictionaryValue* dest) {
51 std::string string_value;
52 if (!source.GetStringWithoutPathExpansion(key, &string_value) ||
55 dest->SetStringWithoutPathExpansion(key, string_value);
61 void SetSSID(const std::string ssid, base::DictionaryValue* properties) {
62 std::string hex_ssid = base::HexEncode(ssid.c_str(), ssid.size());
63 properties->SetStringWithoutPathExpansion(shill::kWifiHexSsid, hex_ssid);
66 std::string GetSSIDFromProperties(const base::DictionaryValue& properties,
67 bool* unknown_encoding) {
69 *unknown_encoding = false;
71 properties.GetStringWithoutPathExpansion(shill::kWifiHexSsid, &hex_ssid);
73 if (hex_ssid.empty()) {
74 NET_LOG_ERROR("GetSSIDFromProperties", "No HexSSID set.");
79 std::vector<uint8> raw_ssid_bytes;
80 if (base::HexStringToBytes(hex_ssid, &raw_ssid_bytes)) {
81 ssid = std::string(raw_ssid_bytes.begin(), raw_ssid_bytes.end());
83 "GetSSIDFromProperties",
84 base::StringPrintf("%s, SSID: %s", hex_ssid.c_str(), ssid.c_str()));
86 NET_LOG_ERROR("GetSSIDFromProperties",
87 base::StringPrintf("Error processing: %s", hex_ssid.c_str()));
91 if (IsStringUTF8(ssid))
94 // Detect encoding and convert to UTF-8.
96 if (!base::DetectEncoding(ssid, &encoding)) {
97 // TODO(stevenjb): This is currently experimental. If we find a case where
98 // base::DetectEncoding() fails, we need to figure out whether we can use
99 // country_code with ConvertToUtf8(). crbug.com/233267.
100 properties.GetStringWithoutPathExpansion(shill::kCountryProperty,
103 std::string utf8_ssid;
104 if (!encoding.empty() &&
105 base::ConvertToUtf8AndNormalize(ssid, encoding, &utf8_ssid)) {
106 if (utf8_ssid != ssid) {
108 "GetSSIDFromProperties",
110 "Encoding=%s: %s", encoding.c_str(), utf8_ssid.c_str()));
115 if (unknown_encoding)
116 *unknown_encoding = true;
118 "GetSSIDFromProperties",
119 base::StringPrintf("Unrecognized Encoding=%s", encoding.c_str()));
123 std::string GetNameFromProperties(const std::string& service_path,
124 const base::DictionaryValue& properties) {
126 properties.GetStringWithoutPathExpansion(shill::kNameProperty, &name);
128 std::string validated_name = ValidateUTF8(name);
129 if (validated_name != name) {
130 NET_LOG_DEBUG("GetNameFromProperties",
131 base::StringPrintf("Validated name %s: UTF8: %s",
132 service_path.c_str(),
133 validated_name.c_str()));
137 properties.GetStringWithoutPathExpansion(shill::kTypeProperty, &type);
138 if (!NetworkTypePattern::WiFi().MatchesType(type))
139 return validated_name;
141 bool unknown_ssid_encoding = false;
142 std::string ssid = GetSSIDFromProperties(properties, &unknown_ssid_encoding);
144 NET_LOG_ERROR("GetNameFromProperties", "No SSID set: " + service_path);
146 // Use |validated_name| if |ssid| is empty.
147 // And if the encoding of the SSID is unknown, use |ssid|, which contains raw
148 // bytes in that case, only if |validated_name| is empty.
149 if (ssid.empty() || (unknown_ssid_encoding && !validated_name.empty()))
150 return validated_name;
152 if (ssid != validated_name) {
153 NET_LOG_DEBUG("GetNameFromProperties",
154 base::StringPrintf("%s: SSID: %s, Name: %s",
155 service_path.c_str(),
157 validated_name.c_str()));
162 scoped_ptr<NetworkUIData> GetUIDataFromValue(const base::Value& ui_data_value) {
163 std::string ui_data_str;
164 if (!ui_data_value.GetAsString(&ui_data_str))
165 return scoped_ptr<NetworkUIData>();
166 if (ui_data_str.empty())
167 return make_scoped_ptr(new NetworkUIData());
168 scoped_ptr<base::DictionaryValue> ui_data_dict(
169 chromeos::onc::ReadDictionaryFromJson(ui_data_str));
171 return scoped_ptr<NetworkUIData>();
172 return make_scoped_ptr(new NetworkUIData(*ui_data_dict));
175 scoped_ptr<NetworkUIData> GetUIDataFromProperties(
176 const base::DictionaryValue& shill_dictionary) {
177 const base::Value* ui_data_value = NULL;
178 shill_dictionary.GetWithoutPathExpansion(shill::kUIDataProperty,
180 if (!ui_data_value) {
181 VLOG(2) << "Dictionary has no UIData entry.";
182 return scoped_ptr<NetworkUIData>();
184 scoped_ptr<NetworkUIData> ui_data = GetUIDataFromValue(*ui_data_value);
186 LOG(ERROR) << "UIData is not a valid JSON dictionary.";
187 return ui_data.Pass();
190 void SetUIData(const NetworkUIData& ui_data,
191 base::DictionaryValue* shill_dictionary) {
192 base::DictionaryValue ui_data_dict;
193 ui_data.FillDictionary(&ui_data_dict);
194 std::string ui_data_blob;
195 base::JSONWriter::Write(&ui_data_dict, &ui_data_blob);
196 shill_dictionary->SetStringWithoutPathExpansion(shill::kUIDataProperty,
200 bool CopyIdentifyingProperties(const base::DictionaryValue& service_properties,
201 base::DictionaryValue* dest) {
205 CopyStringFromDictionary(service_properties, shill::kGuidProperty, dest);
208 service_properties.GetStringWithoutPathExpansion(shill::kTypeProperty, &type);
209 success &= !type.empty();
210 dest->SetStringWithoutPathExpansion(shill::kTypeProperty, type);
211 if (type == shill::kTypeWifi) {
212 success &= CopyStringFromDictionary(
213 service_properties, shill::kSecurityProperty, dest);
215 CopyStringFromDictionary(service_properties, shill::kWifiHexSsid, dest);
216 success &= CopyStringFromDictionary(
217 service_properties, shill::kModeProperty, dest);
218 } else if (type == shill::kTypeVPN) {
219 success &= CopyStringFromDictionary(
220 service_properties, shill::kNameProperty, dest);
221 // VPN Provider values are read from the "Provider" dictionary, but written
222 // with the keys "Provider.Type" and "Provider.Host".
223 const base::DictionaryValue* provider_properties = NULL;
224 if (!service_properties.GetDictionaryWithoutPathExpansion(
225 shill::kProviderProperty, &provider_properties)) {
226 NET_LOG_ERROR("CopyIdentifyingProperties", "Missing VPN provider dict");
229 std::string vpn_provider_type;
230 provider_properties->GetStringWithoutPathExpansion(shill::kTypeProperty,
232 success &= !vpn_provider_type.empty();
233 dest->SetStringWithoutPathExpansion(shill::kProviderTypeProperty,
236 std::string vpn_provider_host;
237 provider_properties->GetStringWithoutPathExpansion(shill::kHostProperty,
239 success &= !vpn_provider_host.empty();
240 dest->SetStringWithoutPathExpansion(shill::kProviderHostProperty,
242 } else if (type == shill::kTypeEthernet || type == shill::kTypeEthernetEap) {
243 // Ethernet and EthernetEAP don't have any additional identifying
246 NOTREACHED() << "Unsupported network type " << type;
250 NET_LOG_ERROR("CopyIdentifyingProperties", "Missing required properties");
254 } // namespace shill_property_util
258 const char kPatternDefault[] = "PatternDefault";
259 const char kPatternEthernet[] = "PatternEthernet";
260 const char kPatternWireless[] = "PatternWireless";
261 const char kPatternMobile[] = "PatternMobile";
262 const char kPatternNonVirtual[] = "PatternNonVirtual";
264 enum NetworkTypeBitFlag {
265 kNetworkTypeNone = 0,
266 kNetworkTypeEthernet = 1 << 0,
267 kNetworkTypeWifi = 1 << 1,
268 kNetworkTypeWimax = 1 << 2,
269 kNetworkTypeCellular = 1 << 3,
270 kNetworkTypeVPN = 1 << 4,
271 kNetworkTypeEthernetEap = 1 << 5
274 struct ShillToBitFlagEntry {
275 const char* shill_network_type;
276 NetworkTypeBitFlag bit_flag;
277 } shill_type_to_flag[] = {
278 { shill::kTypeEthernet, kNetworkTypeEthernet },
279 { shill::kTypeEthernetEap, kNetworkTypeEthernetEap },
280 { shill::kTypeWifi, kNetworkTypeWifi },
281 { shill::kTypeWimax, kNetworkTypeWimax },
282 { shill::kTypeCellular, kNetworkTypeCellular },
283 { shill::kTypeVPN, kNetworkTypeVPN }
286 NetworkTypeBitFlag ShillNetworkTypeToFlag(const std::string& shill_type) {
287 for (size_t i = 0; i < arraysize(shill_type_to_flag); ++i) {
288 if (shill_type_to_flag[i].shill_network_type == shill_type)
289 return shill_type_to_flag[i].bit_flag;
291 NET_LOG_ERROR("ShillNetworkTypeToFlag", "Unknown type: " + shill_type);
292 return kNetworkTypeNone;
298 NetworkTypePattern NetworkTypePattern::Default() {
299 return NetworkTypePattern(~0);
303 NetworkTypePattern NetworkTypePattern::Wireless() {
304 return NetworkTypePattern(kNetworkTypeWifi | kNetworkTypeWimax |
305 kNetworkTypeCellular);
309 NetworkTypePattern NetworkTypePattern::Mobile() {
310 return NetworkTypePattern(kNetworkTypeCellular | kNetworkTypeWimax);
314 NetworkTypePattern NetworkTypePattern::NonVirtual() {
315 return NetworkTypePattern(~kNetworkTypeVPN);
319 NetworkTypePattern NetworkTypePattern::Ethernet() {
320 return NetworkTypePattern(kNetworkTypeEthernet);
324 NetworkTypePattern NetworkTypePattern::WiFi() {
325 return NetworkTypePattern(kNetworkTypeWifi);
329 NetworkTypePattern NetworkTypePattern::Cellular() {
330 return NetworkTypePattern(kNetworkTypeCellular);
334 NetworkTypePattern NetworkTypePattern::VPN() {
335 return NetworkTypePattern(kNetworkTypeVPN);
339 NetworkTypePattern NetworkTypePattern::Wimax() {
340 return NetworkTypePattern(kNetworkTypeWimax);
344 NetworkTypePattern NetworkTypePattern::Primitive(
345 const std::string& shill_network_type) {
346 return NetworkTypePattern(ShillNetworkTypeToFlag(shill_network_type));
349 bool NetworkTypePattern::Equals(const NetworkTypePattern& other) const {
350 return pattern_ == other.pattern_;
353 bool NetworkTypePattern::MatchesType(
354 const std::string& shill_network_type) const {
355 return MatchesPattern(Primitive(shill_network_type));
358 bool NetworkTypePattern::MatchesPattern(
359 const NetworkTypePattern& other_pattern) const {
360 if (Equals(other_pattern))
363 return pattern_ & other_pattern.pattern_;
366 std::string NetworkTypePattern::ToDebugString() const {
367 if (Equals(Default()))
368 return kPatternDefault;
369 if (Equals(Ethernet()))
370 return kPatternEthernet;
371 if (Equals(Wireless()))
372 return kPatternWireless;
373 if (Equals(Mobile()))
374 return kPatternMobile;
375 if (Equals(NonVirtual()))
376 return kPatternNonVirtual;
379 for (size_t i = 0; i < arraysize(shill_type_to_flag); ++i) {
380 if (!(pattern_ & shill_type_to_flag[i].bit_flag))
384 str += shill_type_to_flag[i].shill_network_type;
389 NetworkTypePattern::NetworkTypePattern(int pattern) : pattern_(pattern) {}
391 } // namespace chromeos