Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chromeos / network / onc / onc_translator_shill_to_onc.cc
blobad20482ace48a8a0b1383e5f8d016ff83e5c6415
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 base::Value* value;
35 if (type == base::Value::TYPE_STRING) {
36 value = new base::StringValue(str);
37 } else {
38 value = base::JSONReader::DeprecatedRead(str);
41 if (value == NULL || value->GetType() != type) {
42 delete value;
43 value = NULL;
45 return make_scoped_ptr(value);
48 // This class implements the translation of properties from the given
49 // |shill_dictionary| to a new ONC object of signature |onc_signature|. Using
50 // recursive calls to CreateTranslatedONCObject of new instances, nested objects
51 // are translated.
52 class ShillToONCTranslator {
53 public:
54 ShillToONCTranslator(const base::DictionaryValue& shill_dictionary,
55 ::onc::ONCSource onc_source,
56 const OncValueSignature& onc_signature,
57 const NetworkState* network_state)
58 : shill_dictionary_(&shill_dictionary),
59 onc_source_(onc_source),
60 onc_signature_(&onc_signature),
61 network_state_(network_state) {
62 field_translation_table_ = GetFieldTranslationTable(onc_signature);
65 ShillToONCTranslator(const base::DictionaryValue& shill_dictionary,
66 ::onc::ONCSource onc_source,
67 const OncValueSignature& onc_signature,
68 const FieldTranslationEntry* field_translation_table,
69 const NetworkState* network_state)
70 : shill_dictionary_(&shill_dictionary),
71 onc_source_(onc_source),
72 onc_signature_(&onc_signature),
73 field_translation_table_(field_translation_table),
74 network_state_(network_state) {}
76 // Translates the associated Shill dictionary and creates an ONC object of the
77 // given signature.
78 scoped_ptr<base::DictionaryValue> CreateTranslatedONCObject();
80 private:
81 void TranslateEthernet();
82 void TranslateOpenVPN();
83 void TranslateIPsec();
84 void TranslateThirdPartyVPN();
85 void TranslateVPN();
86 void TranslateWiFiWithState();
87 void TranslateWiMAXWithState();
88 void TranslateCellularWithState();
89 void TranslateCellularDevice();
90 void TranslateNetworkWithState();
91 void TranslateIPConfig();
92 void TranslateSavedOrStaticIPConfig();
93 void TranslateSavedIPConfig();
94 void TranslateStaticIPConfig();
96 // Creates an ONC object from |dictionary| according to the signature
97 // associated to |onc_field_name| and adds it to |onc_object_| at
98 // |onc_field_name|.
99 void TranslateAndAddNestedObject(const std::string& onc_field_name,
100 const base::DictionaryValue& dictionary);
102 // Creates an ONC object from |shill_dictionary_| according to the signature
103 // associated to |onc_field_name| and adds it to |onc_object_| at
104 // |onc_field_name|.
105 void TranslateAndAddNestedObject(const std::string& onc_field_name);
107 // Sets |onc_field_name| in dictionary |onc_dictionary_name| in |onc_object_|
108 // to |value| if the dictionary exists.
109 void SetNestedOncValue(const std::string& onc_dictionary_name,
110 const std::string& onc_field_name,
111 const base::Value& value);
113 // Translates a list of nested objects and adds the list to |onc_object_| at
114 // |onc_field_name|. If there are errors while parsing individual objects or
115 // if the resulting list contains no entries, the result will not be added to
116 // |onc_object_|.
117 void TranslateAndAddListOfObjects(const std::string& onc_field_name,
118 const base::ListValue& list);
120 // Applies function CopyProperty to each field of |value_signature| and its
121 // base signatures.
122 void CopyPropertiesAccordingToSignature(
123 const OncValueSignature* value_signature);
125 // Applies function CopyProperty to each field of |onc_signature_| and its
126 // base signatures.
127 void CopyPropertiesAccordingToSignature();
129 // If |shill_property_name| is defined in |field_signature|, copies this
130 // entry from |shill_dictionary_| to |onc_object_| if it exists.
131 void CopyProperty(const OncFieldSignature* field_signature);
133 // If existent, translates the entry at |shill_property_name| in
134 // |shill_dictionary_| using |table|. It is an error if no matching table
135 // entry is found. Writes the result as entry at |onc_field_name| in
136 // |onc_object_|.
137 void TranslateWithTableAndSet(const std::string& shill_property_name,
138 const StringTranslationEntry table[],
139 const std::string& onc_field_name);
141 // Returns the name of the Shill service provided in |shill_dictionary_|
142 // for debugging.
143 std::string GetName();
145 const base::DictionaryValue* shill_dictionary_;
146 ::onc::ONCSource onc_source_;
147 const OncValueSignature* onc_signature_;
148 const FieldTranslationEntry* field_translation_table_;
149 scoped_ptr<base::DictionaryValue> onc_object_;
150 const NetworkState* network_state_;
152 DISALLOW_COPY_AND_ASSIGN(ShillToONCTranslator);
155 scoped_ptr<base::DictionaryValue>
156 ShillToONCTranslator::CreateTranslatedONCObject() {
157 onc_object_.reset(new base::DictionaryValue);
158 if (onc_signature_ == &kNetworkWithStateSignature) {
159 TranslateNetworkWithState();
160 } else if (onc_signature_ == &kEthernetSignature) {
161 TranslateEthernet();
162 } else if (onc_signature_ == &kVPNSignature) {
163 TranslateVPN();
164 } else if (onc_signature_ == &kOpenVPNSignature) {
165 TranslateOpenVPN();
166 } else if (onc_signature_ == &kIPsecSignature) {
167 TranslateIPsec();
168 } else if (onc_signature_ == &kThirdPartyVPNSignature) {
169 TranslateThirdPartyVPN();
170 } else if (onc_signature_ == &kWiFiWithStateSignature) {
171 TranslateWiFiWithState();
172 } else if (onc_signature_ == &kWiMAXWithStateSignature) {
173 TranslateWiMAXWithState();
174 } else if (onc_signature_ == &kCellularWithStateSignature) {
175 if (field_translation_table_ == kCellularDeviceTable)
176 TranslateCellularDevice();
177 else
178 TranslateCellularWithState();
179 } else if (onc_signature_ == &kIPConfigSignature) {
180 TranslateIPConfig();
181 } else if (onc_signature_ == &kSavedIPConfigSignature) {
182 TranslateSavedIPConfig();
183 } else if (onc_signature_ == &kStaticIPConfigSignature) {
184 TranslateStaticIPConfig();
185 } else {
186 CopyPropertiesAccordingToSignature();
188 return onc_object_.Pass();
191 void ShillToONCTranslator::TranslateEthernet() {
192 std::string shill_network_type;
193 shill_dictionary_->GetStringWithoutPathExpansion(shill::kTypeProperty,
194 &shill_network_type);
195 const char* onc_auth = ::onc::ethernet::kAuthenticationNone;
196 if (shill_network_type == shill::kTypeEthernetEap)
197 onc_auth = ::onc::ethernet::k8021X;
198 onc_object_->SetStringWithoutPathExpansion(::onc::ethernet::kAuthentication,
199 onc_auth);
202 void ShillToONCTranslator::TranslateOpenVPN() {
203 if (shill_dictionary_->HasKey(shill::kOpenVPNVerifyX509NameProperty))
204 TranslateAndAddNestedObject(::onc::openvpn::kVerifyX509);
206 // Shill supports only one RemoteCertKU but ONC requires a list. If existing,
207 // wraps the value into a list.
208 std::string certKU;
209 if (shill_dictionary_->GetStringWithoutPathExpansion(
210 shill::kOpenVPNRemoteCertKUProperty, &certKU)) {
211 scoped_ptr<base::ListValue> certKUs(new base::ListValue);
212 certKUs->AppendString(certKU);
213 onc_object_->SetWithoutPathExpansion(::onc::openvpn::kRemoteCertKU,
214 certKUs.release());
217 for (const OncFieldSignature* field_signature = onc_signature_->fields;
218 field_signature->onc_field_name != NULL; ++field_signature) {
219 const std::string& onc_field_name = field_signature->onc_field_name;
220 if (onc_field_name == ::onc::openvpn::kRemoteCertKU ||
221 onc_field_name == ::onc::openvpn::kServerCAPEMs) {
222 CopyProperty(field_signature);
223 continue;
226 std::string shill_property_name;
227 const base::Value* shill_value = NULL;
228 if (!field_translation_table_ ||
229 !GetShillPropertyName(field_signature->onc_field_name,
230 field_translation_table_, &shill_property_name) ||
231 !shill_dictionary_->GetWithoutPathExpansion(shill_property_name,
232 &shill_value)) {
233 continue;
236 scoped_ptr<base::Value> translated;
237 std::string shill_str;
238 if (shill_value->GetAsString(&shill_str)) {
239 // Shill wants all Provider/VPN fields to be strings. Translates these
240 // strings back to the correct ONC type.
241 translated = ConvertStringToValue(
242 shill_str, field_signature->value_signature->onc_type);
244 if (translated.get() == NULL) {
245 LOG(ERROR) << "Shill property '" << shill_property_name
246 << "' with value " << *shill_value
247 << " couldn't be converted to base::Value::Type "
248 << field_signature->value_signature->onc_type << ": "
249 << GetName();
250 } else {
251 onc_object_->SetWithoutPathExpansion(onc_field_name,
252 translated.release());
254 } else {
255 LOG(ERROR) << "Shill property '" << shill_property_name << "' has value "
256 << *shill_value << ", but expected a string: " << GetName();
261 void ShillToONCTranslator::TranslateIPsec() {
262 CopyPropertiesAccordingToSignature();
263 if (shill_dictionary_->HasKey(shill::kL2tpIpsecXauthUserProperty))
264 TranslateAndAddNestedObject(::onc::ipsec::kXAUTH);
265 std::string client_cert_id;
266 shill_dictionary_->GetStringWithoutPathExpansion(
267 shill::kL2tpIpsecClientCertIdProperty, &client_cert_id);
268 std::string authentication_type =
269 client_cert_id.empty() ? ::onc::ipsec::kPSK : ::onc::ipsec::kCert;
270 onc_object_->SetStringWithoutPathExpansion(::onc::ipsec::kAuthenticationType,
271 authentication_type);
274 void ShillToONCTranslator::TranslateThirdPartyVPN() {
275 CopyPropertiesAccordingToSignature();
277 // For third-party VPNs, |shill::kProviderHostProperty| is used to store the
278 // provider's extension ID.
279 std::string shill_extension_id;
280 shill_dictionary_->GetStringWithoutPathExpansion(shill::kHostProperty,
281 &shill_extension_id);
282 onc_object_->SetStringWithoutPathExpansion(
283 ::onc::third_party_vpn::kExtensionID, shill_extension_id);
286 void ShillToONCTranslator::TranslateVPN() {
287 CopyPropertiesAccordingToSignature();
289 // Parse Shill Provider dictionary. Note, this may not exist, e.g. if we are
290 // just translating network state in network_util::TranslateNetworkStateToONC.
291 const base::DictionaryValue* provider = NULL;
292 if (!shill_dictionary_->GetDictionaryWithoutPathExpansion(
293 shill::kProviderProperty, &provider)) {
294 return;
296 std::string shill_provider_type, onc_provider_type;
297 provider->GetStringWithoutPathExpansion(shill::kTypeProperty,
298 &shill_provider_type);
299 if (!TranslateStringToONC(kVPNTypeTable, shill_provider_type,
300 &onc_provider_type)) {
301 return;
303 onc_object_->SetStringWithoutPathExpansion(::onc::vpn::kType,
304 onc_provider_type);
305 std::string shill_provider_host;
306 if (onc_provider_type != ::onc::vpn::kThirdPartyVpn &&
307 provider->GetStringWithoutPathExpansion(shill::kHostProperty,
308 &shill_provider_host)) {
309 onc_object_->SetStringWithoutPathExpansion(::onc::vpn::kHost,
310 shill_provider_host);
313 // Translate the nested dictionary.
314 std::string provider_type_dictionary;
315 if (onc_provider_type == ::onc::vpn::kTypeL2TP_IPsec) {
316 TranslateAndAddNestedObject(::onc::vpn::kIPsec, *provider);
317 TranslateAndAddNestedObject(::onc::vpn::kL2TP, *provider);
318 provider_type_dictionary = ::onc::vpn::kIPsec;
319 } else {
320 TranslateAndAddNestedObject(onc_provider_type, *provider);
321 provider_type_dictionary = onc_provider_type;
324 bool save_credentials;
325 if (onc_provider_type != ::onc::vpn::kThirdPartyVpn &&
326 shill_dictionary_->GetBooleanWithoutPathExpansion(
327 shill::kSaveCredentialsProperty, &save_credentials)) {
328 SetNestedOncValue(provider_type_dictionary, ::onc::vpn::kSaveCredentials,
329 base::FundamentalValue(save_credentials));
333 void ShillToONCTranslator::TranslateWiFiWithState() {
334 TranslateWithTableAndSet(shill::kSecurityClassProperty, kWiFiSecurityTable,
335 ::onc::wifi::kSecurity);
336 bool unknown_encoding = true;
337 std::string ssid = shill_property_util::GetSSIDFromProperties(
338 *shill_dictionary_, false /* verbose_logging */, &unknown_encoding);
339 if (!unknown_encoding && !ssid.empty())
340 onc_object_->SetStringWithoutPathExpansion(::onc::wifi::kSSID, ssid);
342 bool link_monitor_disable;
343 if (shill_dictionary_->GetBooleanWithoutPathExpansion(
344 shill::kLinkMonitorDisableProperty, &link_monitor_disable)) {
345 onc_object_->SetBooleanWithoutPathExpansion(
346 ::onc::wifi::kAllowGatewayARPPolling, !link_monitor_disable);
349 CopyPropertiesAccordingToSignature();
350 TranslateAndAddNestedObject(::onc::wifi::kEAP);
353 void ShillToONCTranslator::TranslateWiMAXWithState() {
354 CopyPropertiesAccordingToSignature();
355 TranslateAndAddNestedObject(::onc::wimax::kEAP);
358 void ShillToONCTranslator::TranslateCellularWithState() {
359 CopyPropertiesAccordingToSignature();
360 TranslateWithTableAndSet(shill::kActivationStateProperty,
361 kActivationStateTable,
362 ::onc::cellular::kActivationState);
363 TranslateWithTableAndSet(shill::kNetworkTechnologyProperty,
364 kNetworkTechnologyTable,
365 ::onc::cellular::kNetworkTechnology);
366 const base::DictionaryValue* dictionary = NULL;
367 if (shill_dictionary_->GetDictionaryWithoutPathExpansion(
368 shill::kServingOperatorProperty, &dictionary)) {
369 TranslateAndAddNestedObject(::onc::cellular::kServingOperator, *dictionary);
371 if (shill_dictionary_->GetDictionaryWithoutPathExpansion(
372 shill::kCellularApnProperty, &dictionary)) {
373 TranslateAndAddNestedObject(::onc::cellular::kAPN, *dictionary);
375 if (shill_dictionary_->GetDictionaryWithoutPathExpansion(
376 shill::kCellularLastGoodApnProperty, &dictionary)) {
377 TranslateAndAddNestedObject(::onc::cellular::kLastGoodAPN, *dictionary);
379 if (shill_dictionary_->GetDictionaryWithoutPathExpansion(
380 shill::kPaymentPortalProperty, &dictionary)) {
381 TranslateAndAddNestedObject(::onc::cellular::kPaymentPortal, *dictionary);
384 const base::DictionaryValue* device_dictionary = NULL;
385 bool requires_roaming = false;
386 shill_dictionary_->GetDictionaryWithoutPathExpansion(shill::kDeviceProperty,
387 &device_dictionary);
388 if (device_dictionary) {
389 // Merge the Device dictionary with this one (Cellular) using the
390 // CellularDevice signature.
391 ShillToONCTranslator nested_translator(
392 *device_dictionary, onc_source_, kCellularWithStateSignature,
393 kCellularDeviceTable, network_state_);
394 scoped_ptr<base::DictionaryValue> nested_object =
395 nested_translator.CreateTranslatedONCObject();
396 onc_object_->MergeDictionary(nested_object.get());
398 /// Get the requires_roaming from the Device dictionary.
399 device_dictionary->GetBooleanWithoutPathExpansion(
400 shill::kProviderRequiresRoamingProperty, &requires_roaming);
402 if (requires_roaming) {
403 onc_object_->SetStringWithoutPathExpansion(
404 ::onc::cellular::kRoamingState, ::onc::cellular::kRoamingRequired);
405 } else {
406 TranslateWithTableAndSet(shill::kRoamingStateProperty, kRoamingStateTable,
407 ::onc::cellular::kRoamingState);
411 void ShillToONCTranslator::TranslateCellularDevice() {
412 CopyPropertiesAccordingToSignature();
413 const base::DictionaryValue* shill_sim_lock_status = NULL;
414 if (shill_dictionary_->GetDictionaryWithoutPathExpansion(
415 shill::kSIMLockStatusProperty, &shill_sim_lock_status)) {
416 TranslateAndAddNestedObject(::onc::cellular::kSIMLockStatus,
417 *shill_sim_lock_status);
419 const base::DictionaryValue* shill_home_provider = NULL;
420 if (shill_dictionary_->GetDictionaryWithoutPathExpansion(
421 shill::kHomeProviderProperty, &shill_home_provider)) {
422 TranslateAndAddNestedObject(::onc::cellular::kHomeProvider,
423 *shill_home_provider);
425 const base::ListValue* shill_apns = NULL;
426 if (shill_dictionary_->GetListWithoutPathExpansion(
427 shill::kCellularApnListProperty, &shill_apns)) {
428 TranslateAndAddListOfObjects(::onc::cellular::kAPNList, *shill_apns);
430 const base::ListValue* shill_found_networks = NULL;
431 if (shill_dictionary_->GetListWithoutPathExpansion(
432 shill::kFoundNetworksProperty, &shill_found_networks)) {
433 TranslateAndAddListOfObjects(::onc::cellular::kFoundNetworks,
434 *shill_found_networks);
438 void ShillToONCTranslator::TranslateNetworkWithState() {
439 CopyPropertiesAccordingToSignature();
441 std::string shill_network_type;
442 shill_dictionary_->GetStringWithoutPathExpansion(shill::kTypeProperty,
443 &shill_network_type);
444 std::string onc_network_type = ::onc::network_type::kEthernet;
445 if (shill_network_type != shill::kTypeEthernet &&
446 shill_network_type != shill::kTypeEthernetEap) {
447 TranslateStringToONC(kNetworkTypeTable, shill_network_type,
448 &onc_network_type);
450 // Translate nested Cellular, WiFi, etc. properties.
451 if (!onc_network_type.empty()) {
452 onc_object_->SetStringWithoutPathExpansion(::onc::network_config::kType,
453 onc_network_type);
454 TranslateAndAddNestedObject(onc_network_type);
457 // Since Name is a read only field in Shill unless it's a VPN, it is copied
458 // here, but not when going the other direction (if it's not a VPN).
459 std::string name;
460 shill_dictionary_->GetStringWithoutPathExpansion(shill::kNameProperty, &name);
461 onc_object_->SetStringWithoutPathExpansion(::onc::network_config::kName,
462 name);
464 // Limit ONC state to "NotConnected", "Connected", or "Connecting".
465 std::string state;
466 if (shill_dictionary_->GetStringWithoutPathExpansion(shill::kStateProperty,
467 &state)) {
468 std::string onc_state = ::onc::connection_state::kNotConnected;
469 if (NetworkState::StateIsConnected(state)) {
470 onc_state = ::onc::connection_state::kConnected;
471 } else if (NetworkState::StateIsConnecting(state)) {
472 onc_state = ::onc::connection_state::kConnecting;
474 onc_object_->SetStringWithoutPathExpansion(
475 ::onc::network_config::kConnectionState, onc_state);
476 // Only set 'RestrictedConnectivity' if captive portal state is true.
477 if (NetworkState::NetworkStateIsCaptivePortal(*shill_dictionary_)) {
478 onc_object_->SetBooleanWithoutPathExpansion(
479 ::onc::network_config::kRestrictedConnectivity, true);
483 // 'ErrorState' reflects the most recent error maintained in NetworkState
484 // (which may not match Shill's Error or PreviousError properties). Non
485 // visible networks (with null network_state_) do not set ErrorState.
486 if (network_state_) {
487 std::string error_state = network_state_->GetErrorState();
488 if (!error_state.empty()) {
489 onc_object_->SetStringWithoutPathExpansion(
490 ::onc::network_config::kErrorState, error_state);
494 std::string profile_path;
495 if (onc_source_ != ::onc::ONC_SOURCE_UNKNOWN &&
496 shill_dictionary_->GetStringWithoutPathExpansion(shill::kProfileProperty,
497 &profile_path)) {
498 std::string source;
499 if (onc_source_ == ::onc::ONC_SOURCE_DEVICE_POLICY)
500 source = ::onc::network_config::kSourceDevicePolicy;
501 else if (onc_source_ == ::onc::ONC_SOURCE_USER_POLICY)
502 source = ::onc::network_config::kSourceUserPolicy;
503 else if (profile_path == NetworkProfileHandler::GetSharedProfilePath())
504 source = ::onc::network_config::kSourceDevice;
505 else if (!profile_path.empty())
506 source = ::onc::network_config::kSourceUser;
507 else
508 source = ::onc::network_config::kSourceNone;
509 onc_object_->SetStringWithoutPathExpansion(::onc::network_config::kSource,
510 source);
513 // Use a human-readable aa:bb format for any hardware MAC address. Note:
514 // this property is provided by the caller but is not part of the Shill
515 // Service properties (it is copied from the Device properties).
516 std::string address;
517 if (shill_dictionary_->GetStringWithoutPathExpansion(shill::kAddressProperty,
518 &address)) {
519 onc_object_->SetStringWithoutPathExpansion(
520 ::onc::network_config::kMacAddress,
521 network_util::FormattedMacAddress(address));
524 // Shill's Service has an IPConfig property (note the singular), not an
525 // IPConfigs property. However, we require the caller of the translation to
526 // patch the Shill dictionary before passing it to the translator.
527 const base::ListValue* shill_ipconfigs = NULL;
528 if (shill_dictionary_->GetListWithoutPathExpansion(shill::kIPConfigsProperty,
529 &shill_ipconfigs)) {
530 TranslateAndAddListOfObjects(::onc::network_config::kIPConfigs,
531 *shill_ipconfigs);
534 const base::DictionaryValue* saved_ipconfig = nullptr;
535 if (shill_dictionary_->GetDictionaryWithoutPathExpansion(
536 shill::kSavedIPConfigProperty, &saved_ipconfig)) {
537 TranslateAndAddNestedObject(::onc::network_config::kSavedIPConfig,
538 *saved_ipconfig);
541 // Translate the StaticIPConfig object and set the IP config types.
542 const base::DictionaryValue* static_ipconfig = nullptr;
543 if (shill_dictionary_->GetDictionaryWithoutPathExpansion(
544 shill::kStaticIPConfigProperty, &static_ipconfig)) {
545 std::string ip_address;
546 if (static_ipconfig->GetStringWithoutPathExpansion(shill::kAddressProperty,
547 &ip_address) &&
548 !ip_address.empty()) {
549 onc_object_->SetStringWithoutPathExpansion(
550 ::onc::network_config::kIPAddressConfigType,
551 ::onc::network_config::kIPConfigTypeStatic);
553 const base::ListValue* name_servers = nullptr;
554 if (static_ipconfig->GetListWithoutPathExpansion(
555 shill::kNameServersProperty, &name_servers) &&
556 !name_servers->empty()) {
557 onc_object_->SetStringWithoutPathExpansion(
558 ::onc::network_config::kNameServersConfigType,
559 ::onc::network_config::kIPConfigTypeStatic);
561 if (!ip_address.empty() || (name_servers && !name_servers->empty())) {
562 TranslateAndAddNestedObject(::onc::network_config::kStaticIPConfig,
563 *static_ipconfig);
567 std::string proxy_config_str;
568 if (shill_dictionary_->GetStringWithoutPathExpansion(
569 shill::kProxyConfigProperty, &proxy_config_str) &&
570 !proxy_config_str.empty()) {
571 scoped_ptr<base::DictionaryValue> proxy_config_value(
572 ReadDictionaryFromJson(proxy_config_str));
573 if (proxy_config_value) {
574 scoped_ptr<base::DictionaryValue> proxy_settings =
575 ConvertProxyConfigToOncProxySettings(*proxy_config_value);
576 if (proxy_settings) {
577 onc_object_->SetWithoutPathExpansion(
578 ::onc::network_config::kProxySettings, proxy_settings.release());
584 void ShillToONCTranslator::TranslateIPConfig() {
585 CopyPropertiesAccordingToSignature();
586 std::string shill_ip_method;
587 shill_dictionary_->GetStringWithoutPathExpansion(shill::kMethodProperty,
588 &shill_ip_method);
589 std::string type;
590 if (shill_ip_method == shill::kTypeIPv4 ||
591 shill_ip_method == shill::kTypeDHCP) {
592 type = ::onc::ipconfig::kIPv4;
593 } else if (shill_ip_method == shill::kTypeIPv6 ||
594 shill_ip_method == shill::kTypeDHCP6) {
595 type = ::onc::ipconfig::kIPv6;
596 } else {
597 return; // Ignore unhandled IPConfig types, e.g. bootp, zeroconf, ppp
600 onc_object_->SetStringWithoutPathExpansion(::onc::ipconfig::kType, type);
603 void ShillToONCTranslator::TranslateSavedOrStaticIPConfig() {
604 CopyPropertiesAccordingToSignature();
606 // Static and Saved IPConfig in Shill are always of type IPv4. Set this type
607 // in ONC, but not if the object would be empty except the type.
608 if (!onc_object_->empty()) {
609 onc_object_->SetStringWithoutPathExpansion(::onc::ipconfig::kType,
610 ::onc::ipconfig::kIPv4);
614 void ShillToONCTranslator::TranslateSavedIPConfig() {
615 TranslateSavedOrStaticIPConfig();
618 void ShillToONCTranslator::TranslateStaticIPConfig() {
619 TranslateSavedOrStaticIPConfig();
622 void ShillToONCTranslator::TranslateAndAddNestedObject(
623 const std::string& onc_field_name) {
624 TranslateAndAddNestedObject(onc_field_name, *shill_dictionary_);
627 void ShillToONCTranslator::TranslateAndAddNestedObject(
628 const std::string& onc_field_name,
629 const base::DictionaryValue& dictionary) {
630 const OncFieldSignature* field_signature =
631 GetFieldSignature(*onc_signature_, onc_field_name);
632 if (!field_signature) {
633 NOTREACHED() << "Unable to find signature for field: " << onc_field_name;
634 return;
636 ShillToONCTranslator nested_translator(dictionary, onc_source_,
637 *field_signature->value_signature,
638 network_state_);
639 scoped_ptr<base::DictionaryValue> nested_object =
640 nested_translator.CreateTranslatedONCObject();
641 if (nested_object->empty())
642 return;
643 onc_object_->SetWithoutPathExpansion(onc_field_name, nested_object.release());
646 void ShillToONCTranslator::SetNestedOncValue(
647 const std::string& onc_dictionary_name,
648 const std::string& onc_field_name,
649 const base::Value& value) {
650 base::DictionaryValue* nested;
651 if (!onc_object_->GetDictionaryWithoutPathExpansion(onc_dictionary_name,
652 &nested)) {
653 nested = new base::DictionaryValue;
654 onc_object_->SetWithoutPathExpansion(onc_dictionary_name, nested);
656 nested->SetWithoutPathExpansion(onc_field_name, value.DeepCopy());
659 void ShillToONCTranslator::TranslateAndAddListOfObjects(
660 const std::string& onc_field_name,
661 const base::ListValue& list) {
662 const OncFieldSignature* field_signature =
663 GetFieldSignature(*onc_signature_, onc_field_name);
664 if (field_signature->value_signature->onc_type != base::Value::TYPE_LIST) {
665 LOG(ERROR) << "ONC Field name: '" << onc_field_name << "' has type '"
666 << field_signature->value_signature->onc_type
667 << "', expected: base::Value::TYPE_LIST: " << GetName();
668 return;
670 DCHECK(field_signature->value_signature->onc_array_entry_signature);
671 scoped_ptr<base::ListValue> result(new base::ListValue());
672 for (base::ListValue::const_iterator it = list.begin(); it != list.end();
673 ++it) {
674 const base::DictionaryValue* shill_value = NULL;
675 if (!(*it)->GetAsDictionary(&shill_value))
676 continue;
677 ShillToONCTranslator nested_translator(
678 *shill_value, onc_source_,
679 *field_signature->value_signature->onc_array_entry_signature,
680 network_state_);
681 scoped_ptr<base::DictionaryValue> nested_object =
682 nested_translator.CreateTranslatedONCObject();
683 // If the nested object couldn't be parsed, simply omit it.
684 if (nested_object->empty())
685 continue;
686 result->Append(nested_object.release());
688 // If there are no entries in the list, there is no need to expose this field.
689 if (result->empty())
690 return;
691 onc_object_->SetWithoutPathExpansion(onc_field_name, result.release());
694 void ShillToONCTranslator::CopyPropertiesAccordingToSignature() {
695 CopyPropertiesAccordingToSignature(onc_signature_);
698 void ShillToONCTranslator::CopyPropertiesAccordingToSignature(
699 const OncValueSignature* value_signature) {
700 if (value_signature->base_signature)
701 CopyPropertiesAccordingToSignature(value_signature->base_signature);
702 if (!value_signature->fields)
703 return;
704 for (const OncFieldSignature* field_signature = value_signature->fields;
705 field_signature->onc_field_name != NULL; ++field_signature) {
706 CopyProperty(field_signature);
710 void ShillToONCTranslator::CopyProperty(
711 const OncFieldSignature* field_signature) {
712 std::string shill_property_name;
713 const base::Value* shill_value = NULL;
714 if (!field_translation_table_ ||
715 !GetShillPropertyName(field_signature->onc_field_name,
716 field_translation_table_, &shill_property_name) ||
717 !shill_dictionary_->GetWithoutPathExpansion(shill_property_name,
718 &shill_value)) {
719 return;
722 if (shill_value->GetType() != field_signature->value_signature->onc_type) {
723 LOG(ERROR) << "Shill property '" << shill_property_name << "' with value "
724 << *shill_value << " has base::Value::Type "
725 << shill_value->GetType() << " but ONC field '"
726 << field_signature->onc_field_name << "' requires type "
727 << field_signature->value_signature->onc_type << ": "
728 << GetName();
729 return;
732 onc_object_->SetWithoutPathExpansion(field_signature->onc_field_name,
733 shill_value->DeepCopy());
736 void ShillToONCTranslator::TranslateWithTableAndSet(
737 const std::string& shill_property_name,
738 const StringTranslationEntry table[],
739 const std::string& onc_field_name) {
740 std::string shill_value;
741 if (!shill_dictionary_->GetStringWithoutPathExpansion(shill_property_name,
742 &shill_value)) {
743 return;
745 std::string onc_value;
746 if (TranslateStringToONC(table, shill_value, &onc_value)) {
747 onc_object_->SetStringWithoutPathExpansion(onc_field_name, onc_value);
748 return;
750 LOG(ERROR) << "Shill property '" << shill_property_name << "' with value "
751 << shill_value << " couldn't be translated to ONC: " << GetName();
754 std::string ShillToONCTranslator::GetName() {
755 DCHECK(shill_dictionary_);
756 std::string name;
757 shill_dictionary_->GetStringWithoutPathExpansion(shill::kNameProperty, &name);
758 return name;
761 } // namespace
763 scoped_ptr<base::DictionaryValue> TranslateShillServiceToONCPart(
764 const base::DictionaryValue& shill_dictionary,
765 ::onc::ONCSource onc_source,
766 const OncValueSignature* onc_signature,
767 const NetworkState* network_state) {
768 CHECK(onc_signature != NULL);
770 ShillToONCTranslator translator(shill_dictionary, onc_source, *onc_signature,
771 network_state);
772 return translator.CreateTranslatedONCObject();
775 } // namespace onc
776 } // namespace chromeos