Ramove use of JSONReader::DeprecatedRead from chromeos/
[chromium-blink-merge.git] / chromeos / network / onc / onc_translator_shill_to_onc.cc
blobf91950f534e12ab10524246e4ade547b386b820f
1 // Copyright (c) 2012 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/onc/onc_translator.h"
7 #include <string>
9 #include "base/basictypes.h"
10 #include "base/json/json_reader.h"
11 #include "base/json/json_writer.h"
12 #include "base/logging.h"
13 #include "base/strings/string_util.h"
14 #include "base/values.h"
15 #include "chromeos/network/network_profile_handler.h"
16 #include "chromeos/network/network_state.h"
17 #include "chromeos/network/network_util.h"
18 #include "chromeos/network/onc/onc_signature.h"
19 #include "chromeos/network/onc/onc_translation_tables.h"
20 #include "chromeos/network/onc/onc_utils.h"
21 #include "chromeos/network/shill_property_util.h"
22 #include "components/onc/onc_constants.h"
23 #include "third_party/cros_system_api/dbus/service_constants.h"
25 namespace chromeos {
26 namespace onc {
28 namespace {
30 // Converts |str| to a base::Value of the given |type|. If the conversion fails,
31 // returns NULL.
32 scoped_ptr<base::Value> ConvertStringToValue(const std::string& str,
33 base::Value::Type type) {
34 scoped_ptr<base::Value> value;
35 if (type == base::Value::TYPE_STRING) {
36 value.reset(new base::StringValue(str));
37 } else {
38 value = base::JSONReader::Read(str);
40 if (value && value->GetType() != type)
41 return nullptr;
43 return value;
46 // This class implements the translation of properties from the given
47 // |shill_dictionary| to a new ONC object of signature |onc_signature|. Using
48 // recursive calls to CreateTranslatedONCObject of new instances, nested objects
49 // are translated.
50 class ShillToONCTranslator {
51 public:
52 ShillToONCTranslator(const base::DictionaryValue& shill_dictionary,
53 ::onc::ONCSource onc_source,
54 const OncValueSignature& onc_signature,
55 const NetworkState* network_state)
56 : shill_dictionary_(&shill_dictionary),
57 onc_source_(onc_source),
58 onc_signature_(&onc_signature),
59 network_state_(network_state) {
60 field_translation_table_ = GetFieldTranslationTable(onc_signature);
63 ShillToONCTranslator(const base::DictionaryValue& shill_dictionary,
64 ::onc::ONCSource onc_source,
65 const OncValueSignature& onc_signature,
66 const FieldTranslationEntry* field_translation_table,
67 const NetworkState* network_state)
68 : shill_dictionary_(&shill_dictionary),
69 onc_source_(onc_source),
70 onc_signature_(&onc_signature),
71 field_translation_table_(field_translation_table),
72 network_state_(network_state) {}
74 // Translates the associated Shill dictionary and creates an ONC object of the
75 // given signature.
76 scoped_ptr<base::DictionaryValue> CreateTranslatedONCObject();
78 private:
79 void TranslateEthernet();
80 void TranslateOpenVPN();
81 void TranslateIPsec();
82 void TranslateThirdPartyVPN();
83 void TranslateVPN();
84 void TranslateWiFiWithState();
85 void TranslateWiMAXWithState();
86 void TranslateCellularWithState();
87 void TranslateCellularDevice();
88 void TranslateNetworkWithState();
89 void TranslateIPConfig();
90 void TranslateSavedOrStaticIPConfig();
91 void TranslateSavedIPConfig();
92 void TranslateStaticIPConfig();
94 // Creates an ONC object from |dictionary| according to the signature
95 // associated to |onc_field_name| and adds it to |onc_object_| at
96 // |onc_field_name|.
97 void TranslateAndAddNestedObject(const std::string& onc_field_name,
98 const base::DictionaryValue& dictionary);
100 // Creates an ONC object from |shill_dictionary_| according to the signature
101 // associated to |onc_field_name| and adds it to |onc_object_| at
102 // |onc_field_name|.
103 void TranslateAndAddNestedObject(const std::string& onc_field_name);
105 // Sets |onc_field_name| in dictionary |onc_dictionary_name| in |onc_object_|
106 // to |value| if the dictionary exists.
107 void SetNestedOncValue(const std::string& onc_dictionary_name,
108 const std::string& onc_field_name,
109 const base::Value& value);
111 // Translates a list of nested objects and adds the list to |onc_object_| at
112 // |onc_field_name|. If there are errors while parsing individual objects or
113 // if the resulting list contains no entries, the result will not be added to
114 // |onc_object_|.
115 void TranslateAndAddListOfObjects(const std::string& onc_field_name,
116 const base::ListValue& list);
118 // Applies function CopyProperty to each field of |value_signature| and its
119 // base signatures.
120 void CopyPropertiesAccordingToSignature(
121 const OncValueSignature* value_signature);
123 // Applies function CopyProperty to each field of |onc_signature_| and its
124 // base signatures.
125 void CopyPropertiesAccordingToSignature();
127 // If |shill_property_name| is defined in |field_signature|, copies this
128 // entry from |shill_dictionary_| to |onc_object_| if it exists.
129 void CopyProperty(const OncFieldSignature* field_signature);
131 // If existent, translates the entry at |shill_property_name| in
132 // |shill_dictionary_| using |table|. It is an error if no matching table
133 // entry is found. Writes the result as entry at |onc_field_name| in
134 // |onc_object_|.
135 void TranslateWithTableAndSet(const std::string& shill_property_name,
136 const StringTranslationEntry table[],
137 const std::string& onc_field_name);
139 // Returns the name of the Shill service provided in |shill_dictionary_|
140 // for debugging.
141 std::string GetName();
143 const base::DictionaryValue* shill_dictionary_;
144 ::onc::ONCSource onc_source_;
145 const OncValueSignature* onc_signature_;
146 const FieldTranslationEntry* field_translation_table_;
147 scoped_ptr<base::DictionaryValue> onc_object_;
148 const NetworkState* network_state_;
150 DISALLOW_COPY_AND_ASSIGN(ShillToONCTranslator);
153 scoped_ptr<base::DictionaryValue>
154 ShillToONCTranslator::CreateTranslatedONCObject() {
155 onc_object_.reset(new base::DictionaryValue);
156 if (onc_signature_ == &kNetworkWithStateSignature) {
157 TranslateNetworkWithState();
158 } else if (onc_signature_ == &kEthernetSignature) {
159 TranslateEthernet();
160 } else if (onc_signature_ == &kVPNSignature) {
161 TranslateVPN();
162 } else if (onc_signature_ == &kOpenVPNSignature) {
163 TranslateOpenVPN();
164 } else if (onc_signature_ == &kIPsecSignature) {
165 TranslateIPsec();
166 } else if (onc_signature_ == &kThirdPartyVPNSignature) {
167 TranslateThirdPartyVPN();
168 } else if (onc_signature_ == &kWiFiWithStateSignature) {
169 TranslateWiFiWithState();
170 } else if (onc_signature_ == &kWiMAXWithStateSignature) {
171 TranslateWiMAXWithState();
172 } else if (onc_signature_ == &kCellularWithStateSignature) {
173 if (field_translation_table_ == kCellularDeviceTable)
174 TranslateCellularDevice();
175 else
176 TranslateCellularWithState();
177 } else if (onc_signature_ == &kIPConfigSignature) {
178 TranslateIPConfig();
179 } else if (onc_signature_ == &kSavedIPConfigSignature) {
180 TranslateSavedIPConfig();
181 } else if (onc_signature_ == &kStaticIPConfigSignature) {
182 TranslateStaticIPConfig();
183 } else {
184 CopyPropertiesAccordingToSignature();
186 return onc_object_.Pass();
189 void ShillToONCTranslator::TranslateEthernet() {
190 std::string shill_network_type;
191 shill_dictionary_->GetStringWithoutPathExpansion(shill::kTypeProperty,
192 &shill_network_type);
193 const char* onc_auth = ::onc::ethernet::kAuthenticationNone;
194 if (shill_network_type == shill::kTypeEthernetEap)
195 onc_auth = ::onc::ethernet::k8021X;
196 onc_object_->SetStringWithoutPathExpansion(::onc::ethernet::kAuthentication,
197 onc_auth);
200 void ShillToONCTranslator::TranslateOpenVPN() {
201 if (shill_dictionary_->HasKey(shill::kOpenVPNVerifyX509NameProperty))
202 TranslateAndAddNestedObject(::onc::openvpn::kVerifyX509);
204 // Shill supports only one RemoteCertKU but ONC requires a list. If existing,
205 // wraps the value into a list.
206 std::string certKU;
207 if (shill_dictionary_->GetStringWithoutPathExpansion(
208 shill::kOpenVPNRemoteCertKUProperty, &certKU)) {
209 scoped_ptr<base::ListValue> certKUs(new base::ListValue);
210 certKUs->AppendString(certKU);
211 onc_object_->SetWithoutPathExpansion(::onc::openvpn::kRemoteCertKU,
212 certKUs.release());
215 for (const OncFieldSignature* field_signature = onc_signature_->fields;
216 field_signature->onc_field_name != NULL; ++field_signature) {
217 const std::string& onc_field_name = field_signature->onc_field_name;
218 if (onc_field_name == ::onc::openvpn::kRemoteCertKU ||
219 onc_field_name == ::onc::openvpn::kServerCAPEMs) {
220 CopyProperty(field_signature);
221 continue;
224 std::string shill_property_name;
225 const base::Value* shill_value = NULL;
226 if (!field_translation_table_ ||
227 !GetShillPropertyName(field_signature->onc_field_name,
228 field_translation_table_, &shill_property_name) ||
229 !shill_dictionary_->GetWithoutPathExpansion(shill_property_name,
230 &shill_value)) {
231 continue;
234 scoped_ptr<base::Value> translated;
235 std::string shill_str;
236 if (shill_value->GetAsString(&shill_str)) {
237 // Shill wants all Provider/VPN fields to be strings. Translates these
238 // strings back to the correct ONC type.
239 translated = ConvertStringToValue(
240 shill_str, field_signature->value_signature->onc_type);
242 if (translated.get() == NULL) {
243 LOG(ERROR) << "Shill property '" << shill_property_name
244 << "' with value " << *shill_value
245 << " couldn't be converted to base::Value::Type "
246 << field_signature->value_signature->onc_type << ": "
247 << GetName();
248 } else {
249 onc_object_->SetWithoutPathExpansion(onc_field_name,
250 translated.release());
252 } else {
253 LOG(ERROR) << "Shill property '" << shill_property_name << "' has value "
254 << *shill_value << ", but expected a string: " << GetName();
259 void ShillToONCTranslator::TranslateIPsec() {
260 CopyPropertiesAccordingToSignature();
261 if (shill_dictionary_->HasKey(shill::kL2tpIpsecXauthUserProperty))
262 TranslateAndAddNestedObject(::onc::ipsec::kXAUTH);
263 std::string client_cert_id;
264 shill_dictionary_->GetStringWithoutPathExpansion(
265 shill::kL2tpIpsecClientCertIdProperty, &client_cert_id);
266 std::string authentication_type =
267 client_cert_id.empty() ? ::onc::ipsec::kPSK : ::onc::ipsec::kCert;
268 onc_object_->SetStringWithoutPathExpansion(::onc::ipsec::kAuthenticationType,
269 authentication_type);
272 void ShillToONCTranslator::TranslateThirdPartyVPN() {
273 CopyPropertiesAccordingToSignature();
275 // For third-party VPNs, |shill::kProviderHostProperty| is used to store the
276 // provider's extension ID.
277 std::string shill_extension_id;
278 shill_dictionary_->GetStringWithoutPathExpansion(shill::kHostProperty,
279 &shill_extension_id);
280 onc_object_->SetStringWithoutPathExpansion(
281 ::onc::third_party_vpn::kExtensionID, shill_extension_id);
284 void ShillToONCTranslator::TranslateVPN() {
285 CopyPropertiesAccordingToSignature();
287 // Parse Shill Provider dictionary. Note, this may not exist, e.g. if we are
288 // just translating network state in network_util::TranslateNetworkStateToONC.
289 const base::DictionaryValue* provider = NULL;
290 if (!shill_dictionary_->GetDictionaryWithoutPathExpansion(
291 shill::kProviderProperty, &provider)) {
292 return;
294 std::string shill_provider_type, onc_provider_type;
295 provider->GetStringWithoutPathExpansion(shill::kTypeProperty,
296 &shill_provider_type);
297 if (!TranslateStringToONC(kVPNTypeTable, shill_provider_type,
298 &onc_provider_type)) {
299 return;
301 onc_object_->SetStringWithoutPathExpansion(::onc::vpn::kType,
302 onc_provider_type);
303 std::string shill_provider_host;
304 if (onc_provider_type != ::onc::vpn::kThirdPartyVpn &&
305 provider->GetStringWithoutPathExpansion(shill::kHostProperty,
306 &shill_provider_host)) {
307 onc_object_->SetStringWithoutPathExpansion(::onc::vpn::kHost,
308 shill_provider_host);
311 // Translate the nested dictionary.
312 std::string provider_type_dictionary;
313 if (onc_provider_type == ::onc::vpn::kTypeL2TP_IPsec) {
314 TranslateAndAddNestedObject(::onc::vpn::kIPsec, *provider);
315 TranslateAndAddNestedObject(::onc::vpn::kL2TP, *provider);
316 provider_type_dictionary = ::onc::vpn::kIPsec;
317 } else {
318 TranslateAndAddNestedObject(onc_provider_type, *provider);
319 provider_type_dictionary = onc_provider_type;
322 bool save_credentials;
323 if (onc_provider_type != ::onc::vpn::kThirdPartyVpn &&
324 shill_dictionary_->GetBooleanWithoutPathExpansion(
325 shill::kSaveCredentialsProperty, &save_credentials)) {
326 SetNestedOncValue(provider_type_dictionary, ::onc::vpn::kSaveCredentials,
327 base::FundamentalValue(save_credentials));
331 void ShillToONCTranslator::TranslateWiFiWithState() {
332 TranslateWithTableAndSet(shill::kSecurityClassProperty, kWiFiSecurityTable,
333 ::onc::wifi::kSecurity);
334 bool unknown_encoding = true;
335 std::string ssid = shill_property_util::GetSSIDFromProperties(
336 *shill_dictionary_, false /* verbose_logging */, &unknown_encoding);
337 if (!unknown_encoding && !ssid.empty())
338 onc_object_->SetStringWithoutPathExpansion(::onc::wifi::kSSID, ssid);
340 bool link_monitor_disable;
341 if (shill_dictionary_->GetBooleanWithoutPathExpansion(
342 shill::kLinkMonitorDisableProperty, &link_monitor_disable)) {
343 onc_object_->SetBooleanWithoutPathExpansion(
344 ::onc::wifi::kAllowGatewayARPPolling, !link_monitor_disable);
347 CopyPropertiesAccordingToSignature();
348 TranslateAndAddNestedObject(::onc::wifi::kEAP);
351 void ShillToONCTranslator::TranslateWiMAXWithState() {
352 CopyPropertiesAccordingToSignature();
353 TranslateAndAddNestedObject(::onc::wimax::kEAP);
356 void ShillToONCTranslator::TranslateCellularWithState() {
357 CopyPropertiesAccordingToSignature();
358 TranslateWithTableAndSet(shill::kActivationStateProperty,
359 kActivationStateTable,
360 ::onc::cellular::kActivationState);
361 TranslateWithTableAndSet(shill::kNetworkTechnologyProperty,
362 kNetworkTechnologyTable,
363 ::onc::cellular::kNetworkTechnology);
364 const base::DictionaryValue* dictionary = NULL;
365 if (shill_dictionary_->GetDictionaryWithoutPathExpansion(
366 shill::kServingOperatorProperty, &dictionary)) {
367 TranslateAndAddNestedObject(::onc::cellular::kServingOperator, *dictionary);
369 if (shill_dictionary_->GetDictionaryWithoutPathExpansion(
370 shill::kCellularApnProperty, &dictionary)) {
371 TranslateAndAddNestedObject(::onc::cellular::kAPN, *dictionary);
373 if (shill_dictionary_->GetDictionaryWithoutPathExpansion(
374 shill::kCellularLastGoodApnProperty, &dictionary)) {
375 TranslateAndAddNestedObject(::onc::cellular::kLastGoodAPN, *dictionary);
377 if (shill_dictionary_->GetDictionaryWithoutPathExpansion(
378 shill::kPaymentPortalProperty, &dictionary)) {
379 TranslateAndAddNestedObject(::onc::cellular::kPaymentPortal, *dictionary);
382 const base::DictionaryValue* device_dictionary = NULL;
383 bool requires_roaming = false;
384 shill_dictionary_->GetDictionaryWithoutPathExpansion(shill::kDeviceProperty,
385 &device_dictionary);
386 if (device_dictionary) {
387 // Merge the Device dictionary with this one (Cellular) using the
388 // CellularDevice signature.
389 ShillToONCTranslator nested_translator(
390 *device_dictionary, onc_source_, kCellularWithStateSignature,
391 kCellularDeviceTable, network_state_);
392 scoped_ptr<base::DictionaryValue> nested_object =
393 nested_translator.CreateTranslatedONCObject();
394 onc_object_->MergeDictionary(nested_object.get());
396 /// Get the requires_roaming from the Device dictionary.
397 device_dictionary->GetBooleanWithoutPathExpansion(
398 shill::kProviderRequiresRoamingProperty, &requires_roaming);
400 if (requires_roaming) {
401 onc_object_->SetStringWithoutPathExpansion(
402 ::onc::cellular::kRoamingState, ::onc::cellular::kRoamingRequired);
403 } else {
404 TranslateWithTableAndSet(shill::kRoamingStateProperty, kRoamingStateTable,
405 ::onc::cellular::kRoamingState);
409 void ShillToONCTranslator::TranslateCellularDevice() {
410 CopyPropertiesAccordingToSignature();
411 const base::DictionaryValue* shill_sim_lock_status = NULL;
412 if (shill_dictionary_->GetDictionaryWithoutPathExpansion(
413 shill::kSIMLockStatusProperty, &shill_sim_lock_status)) {
414 TranslateAndAddNestedObject(::onc::cellular::kSIMLockStatus,
415 *shill_sim_lock_status);
417 const base::DictionaryValue* shill_home_provider = NULL;
418 if (shill_dictionary_->GetDictionaryWithoutPathExpansion(
419 shill::kHomeProviderProperty, &shill_home_provider)) {
420 TranslateAndAddNestedObject(::onc::cellular::kHomeProvider,
421 *shill_home_provider);
423 const base::ListValue* shill_apns = NULL;
424 if (shill_dictionary_->GetListWithoutPathExpansion(
425 shill::kCellularApnListProperty, &shill_apns)) {
426 TranslateAndAddListOfObjects(::onc::cellular::kAPNList, *shill_apns);
428 const base::ListValue* shill_found_networks = NULL;
429 if (shill_dictionary_->GetListWithoutPathExpansion(
430 shill::kFoundNetworksProperty, &shill_found_networks)) {
431 TranslateAndAddListOfObjects(::onc::cellular::kFoundNetworks,
432 *shill_found_networks);
436 void ShillToONCTranslator::TranslateNetworkWithState() {
437 CopyPropertiesAccordingToSignature();
439 std::string shill_network_type;
440 shill_dictionary_->GetStringWithoutPathExpansion(shill::kTypeProperty,
441 &shill_network_type);
442 std::string onc_network_type = ::onc::network_type::kEthernet;
443 if (shill_network_type != shill::kTypeEthernet &&
444 shill_network_type != shill::kTypeEthernetEap) {
445 TranslateStringToONC(kNetworkTypeTable, shill_network_type,
446 &onc_network_type);
448 // Translate nested Cellular, WiFi, etc. properties.
449 if (!onc_network_type.empty()) {
450 onc_object_->SetStringWithoutPathExpansion(::onc::network_config::kType,
451 onc_network_type);
452 TranslateAndAddNestedObject(onc_network_type);
455 // Since Name is a read only field in Shill unless it's a VPN, it is copied
456 // here, but not when going the other direction (if it's not a VPN).
457 std::string name;
458 shill_dictionary_->GetStringWithoutPathExpansion(shill::kNameProperty, &name);
459 onc_object_->SetStringWithoutPathExpansion(::onc::network_config::kName,
460 name);
462 // Limit ONC state to "NotConnected", "Connected", or "Connecting".
463 std::string state;
464 if (shill_dictionary_->GetStringWithoutPathExpansion(shill::kStateProperty,
465 &state)) {
466 std::string onc_state = ::onc::connection_state::kNotConnected;
467 if (NetworkState::StateIsConnected(state)) {
468 onc_state = ::onc::connection_state::kConnected;
469 } else if (NetworkState::StateIsConnecting(state)) {
470 onc_state = ::onc::connection_state::kConnecting;
472 onc_object_->SetStringWithoutPathExpansion(
473 ::onc::network_config::kConnectionState, onc_state);
474 // Only set 'RestrictedConnectivity' if captive portal state is true.
475 if (NetworkState::NetworkStateIsCaptivePortal(*shill_dictionary_)) {
476 onc_object_->SetBooleanWithoutPathExpansion(
477 ::onc::network_config::kRestrictedConnectivity, true);
481 // 'ErrorState' reflects the most recent error maintained in NetworkState
482 // (which may not match Shill's Error or PreviousError properties). Non
483 // visible networks (with null network_state_) do not set ErrorState.
484 if (network_state_) {
485 std::string error_state = network_state_->GetErrorState();
486 if (!error_state.empty()) {
487 onc_object_->SetStringWithoutPathExpansion(
488 ::onc::network_config::kErrorState, error_state);
492 std::string profile_path;
493 if (onc_source_ != ::onc::ONC_SOURCE_UNKNOWN &&
494 shill_dictionary_->GetStringWithoutPathExpansion(shill::kProfileProperty,
495 &profile_path)) {
496 std::string source;
497 if (onc_source_ == ::onc::ONC_SOURCE_DEVICE_POLICY)
498 source = ::onc::network_config::kSourceDevicePolicy;
499 else if (onc_source_ == ::onc::ONC_SOURCE_USER_POLICY)
500 source = ::onc::network_config::kSourceUserPolicy;
501 else if (profile_path == NetworkProfileHandler::GetSharedProfilePath())
502 source = ::onc::network_config::kSourceDevice;
503 else if (!profile_path.empty())
504 source = ::onc::network_config::kSourceUser;
505 else
506 source = ::onc::network_config::kSourceNone;
507 onc_object_->SetStringWithoutPathExpansion(::onc::network_config::kSource,
508 source);
511 // Use a human-readable aa:bb format for any hardware MAC address. Note:
512 // this property is provided by the caller but is not part of the Shill
513 // Service properties (it is copied from the Device properties).
514 std::string address;
515 if (shill_dictionary_->GetStringWithoutPathExpansion(shill::kAddressProperty,
516 &address)) {
517 onc_object_->SetStringWithoutPathExpansion(
518 ::onc::network_config::kMacAddress,
519 network_util::FormattedMacAddress(address));
522 // Shill's Service has an IPConfig property (note the singular), not an
523 // IPConfigs property. However, we require the caller of the translation to
524 // patch the Shill dictionary before passing it to the translator.
525 const base::ListValue* shill_ipconfigs = NULL;
526 if (shill_dictionary_->GetListWithoutPathExpansion(shill::kIPConfigsProperty,
527 &shill_ipconfigs)) {
528 TranslateAndAddListOfObjects(::onc::network_config::kIPConfigs,
529 *shill_ipconfigs);
532 const base::DictionaryValue* saved_ipconfig = nullptr;
533 if (shill_dictionary_->GetDictionaryWithoutPathExpansion(
534 shill::kSavedIPConfigProperty, &saved_ipconfig)) {
535 TranslateAndAddNestedObject(::onc::network_config::kSavedIPConfig,
536 *saved_ipconfig);
539 // Translate the StaticIPConfig object and set the IP config types.
540 const base::DictionaryValue* static_ipconfig = nullptr;
541 if (shill_dictionary_->GetDictionaryWithoutPathExpansion(
542 shill::kStaticIPConfigProperty, &static_ipconfig)) {
543 std::string ip_address;
544 if (static_ipconfig->GetStringWithoutPathExpansion(shill::kAddressProperty,
545 &ip_address) &&
546 !ip_address.empty()) {
547 onc_object_->SetStringWithoutPathExpansion(
548 ::onc::network_config::kIPAddressConfigType,
549 ::onc::network_config::kIPConfigTypeStatic);
551 const base::ListValue* name_servers = nullptr;
552 if (static_ipconfig->GetListWithoutPathExpansion(
553 shill::kNameServersProperty, &name_servers) &&
554 !name_servers->empty()) {
555 onc_object_->SetStringWithoutPathExpansion(
556 ::onc::network_config::kNameServersConfigType,
557 ::onc::network_config::kIPConfigTypeStatic);
559 if (!ip_address.empty() || (name_servers && !name_servers->empty())) {
560 TranslateAndAddNestedObject(::onc::network_config::kStaticIPConfig,
561 *static_ipconfig);
565 std::string proxy_config_str;
566 if (shill_dictionary_->GetStringWithoutPathExpansion(
567 shill::kProxyConfigProperty, &proxy_config_str) &&
568 !proxy_config_str.empty()) {
569 scoped_ptr<base::DictionaryValue> proxy_config_value(
570 ReadDictionaryFromJson(proxy_config_str));
571 if (proxy_config_value) {
572 scoped_ptr<base::DictionaryValue> proxy_settings =
573 ConvertProxyConfigToOncProxySettings(*proxy_config_value);
574 if (proxy_settings) {
575 onc_object_->SetWithoutPathExpansion(
576 ::onc::network_config::kProxySettings, proxy_settings.release());
582 void ShillToONCTranslator::TranslateIPConfig() {
583 CopyPropertiesAccordingToSignature();
584 std::string shill_ip_method;
585 shill_dictionary_->GetStringWithoutPathExpansion(shill::kMethodProperty,
586 &shill_ip_method);
587 std::string type;
588 if (shill_ip_method == shill::kTypeIPv4 ||
589 shill_ip_method == shill::kTypeDHCP) {
590 type = ::onc::ipconfig::kIPv4;
591 } else if (shill_ip_method == shill::kTypeIPv6 ||
592 shill_ip_method == shill::kTypeDHCP6) {
593 type = ::onc::ipconfig::kIPv6;
594 } else {
595 return; // Ignore unhandled IPConfig types, e.g. bootp, zeroconf, ppp
598 onc_object_->SetStringWithoutPathExpansion(::onc::ipconfig::kType, type);
601 void ShillToONCTranslator::TranslateSavedOrStaticIPConfig() {
602 CopyPropertiesAccordingToSignature();
604 // Static and Saved IPConfig in Shill are always of type IPv4. Set this type
605 // in ONC, but not if the object would be empty except the type.
606 if (!onc_object_->empty()) {
607 onc_object_->SetStringWithoutPathExpansion(::onc::ipconfig::kType,
608 ::onc::ipconfig::kIPv4);
612 void ShillToONCTranslator::TranslateSavedIPConfig() {
613 TranslateSavedOrStaticIPConfig();
616 void ShillToONCTranslator::TranslateStaticIPConfig() {
617 TranslateSavedOrStaticIPConfig();
620 void ShillToONCTranslator::TranslateAndAddNestedObject(
621 const std::string& onc_field_name) {
622 TranslateAndAddNestedObject(onc_field_name, *shill_dictionary_);
625 void ShillToONCTranslator::TranslateAndAddNestedObject(
626 const std::string& onc_field_name,
627 const base::DictionaryValue& dictionary) {
628 const OncFieldSignature* field_signature =
629 GetFieldSignature(*onc_signature_, onc_field_name);
630 if (!field_signature) {
631 NOTREACHED() << "Unable to find signature for field: " << onc_field_name;
632 return;
634 ShillToONCTranslator nested_translator(dictionary, onc_source_,
635 *field_signature->value_signature,
636 network_state_);
637 scoped_ptr<base::DictionaryValue> nested_object =
638 nested_translator.CreateTranslatedONCObject();
639 if (nested_object->empty())
640 return;
641 onc_object_->SetWithoutPathExpansion(onc_field_name, nested_object.release());
644 void ShillToONCTranslator::SetNestedOncValue(
645 const std::string& onc_dictionary_name,
646 const std::string& onc_field_name,
647 const base::Value& value) {
648 base::DictionaryValue* nested;
649 if (!onc_object_->GetDictionaryWithoutPathExpansion(onc_dictionary_name,
650 &nested)) {
651 nested = new base::DictionaryValue;
652 onc_object_->SetWithoutPathExpansion(onc_dictionary_name, nested);
654 nested->SetWithoutPathExpansion(onc_field_name, value.DeepCopy());
657 void ShillToONCTranslator::TranslateAndAddListOfObjects(
658 const std::string& onc_field_name,
659 const base::ListValue& list) {
660 const OncFieldSignature* field_signature =
661 GetFieldSignature(*onc_signature_, onc_field_name);
662 if (field_signature->value_signature->onc_type != base::Value::TYPE_LIST) {
663 LOG(ERROR) << "ONC Field name: '" << onc_field_name << "' has type '"
664 << field_signature->value_signature->onc_type
665 << "', expected: base::Value::TYPE_LIST: " << GetName();
666 return;
668 DCHECK(field_signature->value_signature->onc_array_entry_signature);
669 scoped_ptr<base::ListValue> result(new base::ListValue());
670 for (base::ListValue::const_iterator it = list.begin(); it != list.end();
671 ++it) {
672 const base::DictionaryValue* shill_value = NULL;
673 if (!(*it)->GetAsDictionary(&shill_value))
674 continue;
675 ShillToONCTranslator nested_translator(
676 *shill_value, onc_source_,
677 *field_signature->value_signature->onc_array_entry_signature,
678 network_state_);
679 scoped_ptr<base::DictionaryValue> nested_object =
680 nested_translator.CreateTranslatedONCObject();
681 // If the nested object couldn't be parsed, simply omit it.
682 if (nested_object->empty())
683 continue;
684 result->Append(nested_object.release());
686 // If there are no entries in the list, there is no need to expose this field.
687 if (result->empty())
688 return;
689 onc_object_->SetWithoutPathExpansion(onc_field_name, result.release());
692 void ShillToONCTranslator::CopyPropertiesAccordingToSignature() {
693 CopyPropertiesAccordingToSignature(onc_signature_);
696 void ShillToONCTranslator::CopyPropertiesAccordingToSignature(
697 const OncValueSignature* value_signature) {
698 if (value_signature->base_signature)
699 CopyPropertiesAccordingToSignature(value_signature->base_signature);
700 if (!value_signature->fields)
701 return;
702 for (const OncFieldSignature* field_signature = value_signature->fields;
703 field_signature->onc_field_name != NULL; ++field_signature) {
704 CopyProperty(field_signature);
708 void ShillToONCTranslator::CopyProperty(
709 const OncFieldSignature* field_signature) {
710 std::string shill_property_name;
711 const base::Value* shill_value = NULL;
712 if (!field_translation_table_ ||
713 !GetShillPropertyName(field_signature->onc_field_name,
714 field_translation_table_, &shill_property_name) ||
715 !shill_dictionary_->GetWithoutPathExpansion(shill_property_name,
716 &shill_value)) {
717 return;
720 if (shill_value->GetType() != field_signature->value_signature->onc_type) {
721 LOG(ERROR) << "Shill property '" << shill_property_name << "' with value "
722 << *shill_value << " has base::Value::Type "
723 << shill_value->GetType() << " but ONC field '"
724 << field_signature->onc_field_name << "' requires type "
725 << field_signature->value_signature->onc_type << ": "
726 << GetName();
727 return;
730 onc_object_->SetWithoutPathExpansion(field_signature->onc_field_name,
731 shill_value->DeepCopy());
734 void ShillToONCTranslator::TranslateWithTableAndSet(
735 const std::string& shill_property_name,
736 const StringTranslationEntry table[],
737 const std::string& onc_field_name) {
738 std::string shill_value;
739 if (!shill_dictionary_->GetStringWithoutPathExpansion(shill_property_name,
740 &shill_value)) {
741 return;
743 std::string onc_value;
744 if (TranslateStringToONC(table, shill_value, &onc_value)) {
745 onc_object_->SetStringWithoutPathExpansion(onc_field_name, onc_value);
746 return;
748 LOG(ERROR) << "Shill property '" << shill_property_name << "' with value "
749 << shill_value << " couldn't be translated to ONC: " << GetName();
752 std::string ShillToONCTranslator::GetName() {
753 DCHECK(shill_dictionary_);
754 std::string name;
755 shill_dictionary_->GetStringWithoutPathExpansion(shill::kNameProperty, &name);
756 return name;
759 } // namespace
761 scoped_ptr<base::DictionaryValue> TranslateShillServiceToONCPart(
762 const base::DictionaryValue& shill_dictionary,
763 ::onc::ONCSource onc_source,
764 const OncValueSignature* onc_signature,
765 const NetworkState* network_state) {
766 CHECK(onc_signature != NULL);
768 ShillToONCTranslator translator(shill_dictionary, onc_source, *onc_signature,
769 network_state);
770 return translator.CreateTranslatedONCObject();
773 } // namespace onc
774 } // namespace chromeos