Supervised user import: Listen for profile creation/deletion
[chromium-blink-merge.git] / chromeos / network / onc / onc_translator_shill_to_onc.cc
blobaca9133531a30036716f94a569eba3aff3c4d008
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/shill_property_util.h"
21 #include "components/onc/onc_constants.h"
22 #include "third_party/cros_system_api/dbus/service_constants.h"
24 namespace chromeos {
25 namespace onc {
27 namespace {
29 // Converts |str| to a base::Value of the given |type|. If the conversion fails,
30 // returns NULL.
31 scoped_ptr<base::Value> ConvertStringToValue(const std::string& str,
32 base::Value::Type type) {
33 base::Value* value;
34 if (type == base::Value::TYPE_STRING) {
35 value = new base::StringValue(str);
36 } else {
37 value = base::JSONReader::Read(str);
40 if (value == NULL || value->GetType() != type) {
41 delete value;
42 value = NULL;
44 return make_scoped_ptr(value);
47 // This class implements the translation of properties from the given
48 // |shill_dictionary| to a new ONC object of signature |onc_signature|. Using
49 // recursive calls to CreateTranslatedONCObject of new instances, nested objects
50 // are translated.
51 class ShillToONCTranslator {
52 public:
53 ShillToONCTranslator(const base::DictionaryValue& shill_dictionary,
54 ::onc::ONCSource onc_source,
55 const OncValueSignature& onc_signature,
56 const NetworkState* network_state)
57 : shill_dictionary_(&shill_dictionary),
58 onc_source_(onc_source),
59 onc_signature_(&onc_signature),
60 network_state_(network_state) {
61 field_translation_table_ = GetFieldTranslationTable(onc_signature);
64 ShillToONCTranslator(const base::DictionaryValue& shill_dictionary,
65 ::onc::ONCSource onc_source,
66 const OncValueSignature& onc_signature,
67 const FieldTranslationEntry* field_translation_table,
68 const NetworkState* network_state)
69 : shill_dictionary_(&shill_dictionary),
70 onc_source_(onc_source),
71 onc_signature_(&onc_signature),
72 field_translation_table_(field_translation_table),
73 network_state_(network_state) {}
75 // Translates the associated Shill dictionary and creates an ONC object of the
76 // given signature.
77 scoped_ptr<base::DictionaryValue> CreateTranslatedONCObject();
79 private:
80 void TranslateEthernet();
81 void TranslateOpenVPN();
82 void TranslateIPsec();
83 void TranslateThirdPartyVPN();
84 void TranslateVPN();
85 void TranslateWiFiWithState();
86 void TranslateWiMAXWithState();
87 void TranslateCellularWithState();
88 void TranslateCellularDevice();
89 void TranslateNetworkWithState();
90 void TranslateIPConfig();
91 void TranslateSavedOrStaticIPConfig();
92 void TranslateSavedIPConfig();
93 void TranslateStaticIPConfig();
95 // Creates an ONC object from |dictionary| according to the signature
96 // associated to |onc_field_name| and adds it to |onc_object_| at
97 // |onc_field_name|.
98 void TranslateAndAddNestedObject(const std::string& onc_field_name,
99 const base::DictionaryValue& dictionary);
101 // Creates an ONC object from |shill_dictionary_| according to the signature
102 // associated to |onc_field_name| and adds it to |onc_object_| at
103 // |onc_field_name|.
104 void TranslateAndAddNestedObject(const std::string& onc_field_name);
106 // Sets |onc_field_name| in dictionary |onc_dictionary_name| in |onc_object_|
107 // to |value| if the dictionary exists.
108 void SetNestedOncValue(const std::string& onc_dictionary_name,
109 const std::string& onc_field_name,
110 const base::Value& value);
112 // Translates a list of nested objects and adds the list to |onc_object_| at
113 // |onc_field_name|. If there are errors while parsing individual objects or
114 // if the resulting list contains no entries, the result will not be added to
115 // |onc_object_|.
116 void TranslateAndAddListOfObjects(const std::string& onc_field_name,
117 const base::ListValue& list);
119 // Applies function CopyProperty to each field of |value_signature| and its
120 // base signatures.
121 void CopyPropertiesAccordingToSignature(
122 const OncValueSignature* value_signature);
124 // Applies function CopyProperty to each field of |onc_signature_| and its
125 // base signatures.
126 void CopyPropertiesAccordingToSignature();
128 // If |shill_property_name| is defined in |field_signature|, copies this
129 // entry from |shill_dictionary_| to |onc_object_| if it exists.
130 void CopyProperty(const OncFieldSignature* field_signature);
132 // If existent, translates the entry at |shill_property_name| in
133 // |shill_dictionary_| using |table|. It is an error if no matching table
134 // entry is found. Writes the result as entry at |onc_field_name| in
135 // |onc_object_|.
136 void TranslateWithTableAndSet(const std::string& shill_property_name,
137 const StringTranslationEntry table[],
138 const std::string& onc_field_name);
140 // Returns the name of the Shill service provided in |shill_dictionary_|
141 // for debugging.
142 std::string GetName();
144 const base::DictionaryValue* shill_dictionary_;
145 ::onc::ONCSource onc_source_;
146 const OncValueSignature* onc_signature_;
147 const FieldTranslationEntry* field_translation_table_;
148 scoped_ptr<base::DictionaryValue> onc_object_;
149 const NetworkState* network_state_;
151 DISALLOW_COPY_AND_ASSIGN(ShillToONCTranslator);
154 scoped_ptr<base::DictionaryValue>
155 ShillToONCTranslator::CreateTranslatedONCObject() {
156 onc_object_.reset(new base::DictionaryValue);
157 if (onc_signature_ == &kNetworkWithStateSignature) {
158 TranslateNetworkWithState();
159 } else if (onc_signature_ == &kEthernetSignature) {
160 TranslateEthernet();
161 } else if (onc_signature_ == &kVPNSignature) {
162 TranslateVPN();
163 } else if (onc_signature_ == &kOpenVPNSignature) {
164 TranslateOpenVPN();
165 } else if (onc_signature_ == &kIPsecSignature) {
166 TranslateIPsec();
167 } else if (onc_signature_ == &kThirdPartyVPNSignature) {
168 TranslateThirdPartyVPN();
169 } else if (onc_signature_ == &kWiFiWithStateSignature) {
170 TranslateWiFiWithState();
171 } else if (onc_signature_ == &kWiMAXWithStateSignature) {
172 TranslateWiMAXWithState();
173 } else if (onc_signature_ == &kCellularWithStateSignature) {
174 if (field_translation_table_ == kCellularDeviceTable)
175 TranslateCellularDevice();
176 else
177 TranslateCellularWithState();
178 } else if (onc_signature_ == &kIPConfigSignature) {
179 TranslateIPConfig();
180 } else if (onc_signature_ == &kSavedIPConfigSignature) {
181 TranslateSavedIPConfig();
182 } else if (onc_signature_ == &kStaticIPConfigSignature) {
183 TranslateStaticIPConfig();
184 } else {
185 CopyPropertiesAccordingToSignature();
187 return onc_object_.Pass();
190 void ShillToONCTranslator::TranslateEthernet() {
191 std::string shill_network_type;
192 shill_dictionary_->GetStringWithoutPathExpansion(shill::kTypeProperty,
193 &shill_network_type);
194 const char* onc_auth = ::onc::ethernet::kAuthenticationNone;
195 if (shill_network_type == shill::kTypeEthernetEap)
196 onc_auth = ::onc::ethernet::k8021X;
197 onc_object_->SetStringWithoutPathExpansion(::onc::ethernet::kAuthentication,
198 onc_auth);
201 void ShillToONCTranslator::TranslateOpenVPN() {
202 if (shill_dictionary_->HasKey(shill::kOpenVPNVerifyX509NameProperty))
203 TranslateAndAddNestedObject(::onc::openvpn::kVerifyX509);
205 // Shill supports only one RemoteCertKU but ONC requires a list. If existing,
206 // wraps the value into a list.
207 std::string certKU;
208 if (shill_dictionary_->GetStringWithoutPathExpansion(
209 shill::kOpenVPNRemoteCertKUProperty, &certKU)) {
210 scoped_ptr<base::ListValue> certKUs(new base::ListValue);
211 certKUs->AppendString(certKU);
212 onc_object_->SetWithoutPathExpansion(::onc::openvpn::kRemoteCertKU,
213 certKUs.release());
216 for (const OncFieldSignature* field_signature = onc_signature_->fields;
217 field_signature->onc_field_name != NULL; ++field_signature) {
218 const std::string& onc_field_name = field_signature->onc_field_name;
219 if (onc_field_name == ::onc::openvpn::kRemoteCertKU ||
220 onc_field_name == ::onc::openvpn::kServerCAPEMs) {
221 CopyProperty(field_signature);
222 continue;
225 std::string shill_property_name;
226 const base::Value* shill_value = NULL;
227 if (!field_translation_table_ ||
228 !GetShillPropertyName(field_signature->onc_field_name,
229 field_translation_table_, &shill_property_name) ||
230 !shill_dictionary_->GetWithoutPathExpansion(shill_property_name,
231 &shill_value)) {
232 continue;
235 scoped_ptr<base::Value> translated;
236 std::string shill_str;
237 if (shill_value->GetAsString(&shill_str)) {
238 // Shill wants all Provider/VPN fields to be strings. Translates these
239 // strings back to the correct ONC type.
240 translated = ConvertStringToValue(
241 shill_str, field_signature->value_signature->onc_type);
243 if (translated.get() == NULL) {
244 LOG(ERROR) << "Shill property '" << shill_property_name
245 << "' with value " << *shill_value
246 << " couldn't be converted to base::Value::Type "
247 << field_signature->value_signature->onc_type << ": "
248 << GetName();
249 } else {
250 onc_object_->SetWithoutPathExpansion(onc_field_name,
251 translated.release());
253 } else {
254 LOG(ERROR) << "Shill property '" << shill_property_name << "' has value "
255 << *shill_value << ", but expected a string: " << GetName();
260 void ShillToONCTranslator::TranslateIPsec() {
261 CopyPropertiesAccordingToSignature();
262 if (shill_dictionary_->HasKey(shill::kL2tpIpsecXauthUserProperty))
263 TranslateAndAddNestedObject(::onc::ipsec::kXAUTH);
264 std::string client_cert_id;
265 shill_dictionary_->GetStringWithoutPathExpansion(
266 shill::kL2tpIpsecClientCertIdProperty, &client_cert_id);
267 std::string authentication_type =
268 client_cert_id.empty() ? ::onc::ipsec::kPSK : ::onc::ipsec::kCert;
269 onc_object_->SetStringWithoutPathExpansion(::onc::ipsec::kAuthenticationType,
270 authentication_type);
273 void ShillToONCTranslator::TranslateThirdPartyVPN() {
274 CopyPropertiesAccordingToSignature();
276 // For third-party VPNs, |shill::kProviderHostProperty| is used to store the
277 // provider's extension ID.
278 std::string shill_extension_id;
279 shill_dictionary_->GetStringWithoutPathExpansion(shill::kHostProperty,
280 &shill_extension_id);
281 onc_object_->SetStringWithoutPathExpansion(
282 ::onc::third_party_vpn::kExtensionID, shill_extension_id);
285 void ShillToONCTranslator::TranslateVPN() {
286 CopyPropertiesAccordingToSignature();
288 // Parse Shill Provider dictionary. Note, this may not exist, e.g. if we are
289 // just translating network state in network_util::TranslateNetworkStateToONC.
290 const base::DictionaryValue* provider = NULL;
291 if (!shill_dictionary_->GetDictionaryWithoutPathExpansion(
292 shill::kProviderProperty, &provider)) {
293 return;
295 std::string shill_provider_type, onc_provider_type;
296 provider->GetStringWithoutPathExpansion(shill::kTypeProperty,
297 &shill_provider_type);
298 if (!TranslateStringToONC(kVPNTypeTable, shill_provider_type,
299 &onc_provider_type)) {
300 return;
302 onc_object_->SetStringWithoutPathExpansion(::onc::vpn::kType,
303 onc_provider_type);
304 std::string shill_provider_host;
305 if (onc_provider_type != ::onc::vpn::kThirdPartyVpn &&
306 provider->GetStringWithoutPathExpansion(shill::kHostProperty,
307 &shill_provider_host)) {
308 onc_object_->SetStringWithoutPathExpansion(::onc::vpn::kHost,
309 shill_provider_host);
312 // Translate the nested dictionary.
313 std::string provider_type_dictionary;
314 if (onc_provider_type == ::onc::vpn::kTypeL2TP_IPsec) {
315 TranslateAndAddNestedObject(::onc::vpn::kIPsec, *provider);
316 TranslateAndAddNestedObject(::onc::vpn::kL2TP, *provider);
317 provider_type_dictionary = ::onc::vpn::kIPsec;
318 } else {
319 TranslateAndAddNestedObject(onc_provider_type, *provider);
320 provider_type_dictionary = onc_provider_type;
323 bool save_credentials;
324 if (onc_provider_type != ::onc::vpn::kThirdPartyVpn &&
325 shill_dictionary_->GetBooleanWithoutPathExpansion(
326 shill::kSaveCredentialsProperty, &save_credentials)) {
327 SetNestedOncValue(provider_type_dictionary, ::onc::vpn::kSaveCredentials,
328 base::FundamentalValue(save_credentials));
332 void ShillToONCTranslator::TranslateWiFiWithState() {
333 TranslateWithTableAndSet(shill::kSecurityClassProperty, kWiFiSecurityTable,
334 ::onc::wifi::kSecurity);
335 bool unknown_encoding = true;
336 std::string ssid = shill_property_util::GetSSIDFromProperties(
337 *shill_dictionary_, false /* verbose_logging */, &unknown_encoding);
338 if (!unknown_encoding && !ssid.empty())
339 onc_object_->SetStringWithoutPathExpansion(::onc::wifi::kSSID, ssid);
341 bool link_monitor_disable;
342 if (shill_dictionary_->GetBooleanWithoutPathExpansion(
343 shill::kLinkMonitorDisableProperty, &link_monitor_disable)) {
344 onc_object_->SetBooleanWithoutPathExpansion(
345 ::onc::wifi::kAllowGatewayARPPolling, !link_monitor_disable);
348 CopyPropertiesAccordingToSignature();
349 TranslateAndAddNestedObject(::onc::wifi::kEAP);
352 void ShillToONCTranslator::TranslateWiMAXWithState() {
353 CopyPropertiesAccordingToSignature();
354 TranslateAndAddNestedObject(::onc::wimax::kEAP);
357 void ShillToONCTranslator::TranslateCellularWithState() {
358 CopyPropertiesAccordingToSignature();
359 TranslateWithTableAndSet(shill::kActivationStateProperty,
360 kActivationStateTable,
361 ::onc::cellular::kActivationState);
362 TranslateWithTableAndSet(shill::kNetworkTechnologyProperty,
363 kNetworkTechnologyTable,
364 ::onc::cellular::kNetworkTechnology);
365 const base::DictionaryValue* dictionary = NULL;
366 if (shill_dictionary_->GetDictionaryWithoutPathExpansion(
367 shill::kServingOperatorProperty, &dictionary)) {
368 TranslateAndAddNestedObject(::onc::cellular::kServingOperator, *dictionary);
370 if (shill_dictionary_->GetDictionaryWithoutPathExpansion(
371 shill::kCellularApnProperty, &dictionary)) {
372 TranslateAndAddNestedObject(::onc::cellular::kAPN, *dictionary);
374 if (shill_dictionary_->GetDictionaryWithoutPathExpansion(
375 shill::kCellularLastGoodApnProperty, &dictionary)) {
376 TranslateAndAddNestedObject(::onc::cellular::kLastGoodAPN, *dictionary);
378 if (shill_dictionary_->GetDictionaryWithoutPathExpansion(
379 shill::kPaymentPortalProperty, &dictionary)) {
380 TranslateAndAddNestedObject(::onc::cellular::kPaymentPortal, *dictionary);
383 const base::DictionaryValue* device_dictionary = NULL;
384 bool requires_roaming = false;
385 shill_dictionary_->GetDictionaryWithoutPathExpansion(shill::kDeviceProperty,
386 &device_dictionary);
387 if (device_dictionary) {
388 // Merge the Device dictionary with this one (Cellular) using the
389 // CellularDevice signature.
390 ShillToONCTranslator nested_translator(
391 *device_dictionary, onc_source_, kCellularWithStateSignature,
392 kCellularDeviceTable, network_state_);
393 scoped_ptr<base::DictionaryValue> nested_object =
394 nested_translator.CreateTranslatedONCObject();
395 onc_object_->MergeDictionary(nested_object.get());
397 /// Get the requires_roaming from the Device dictionary.
398 device_dictionary->GetBooleanWithoutPathExpansion(
399 shill::kProviderRequiresRoamingProperty, &requires_roaming);
401 if (requires_roaming) {
402 onc_object_->SetStringWithoutPathExpansion(
403 ::onc::cellular::kRoamingState, ::onc::cellular::kRoamingRequired);
404 } else {
405 TranslateWithTableAndSet(shill::kRoamingStateProperty, kRoamingStateTable,
406 ::onc::cellular::kRoamingState);
410 void ShillToONCTranslator::TranslateCellularDevice() {
411 CopyPropertiesAccordingToSignature();
412 const base::DictionaryValue* shill_sim_lock_status = NULL;
413 if (shill_dictionary_->GetDictionaryWithoutPathExpansion(
414 shill::kSIMLockStatusProperty, &shill_sim_lock_status)) {
415 TranslateAndAddNestedObject(::onc::cellular::kSIMLockStatus,
416 *shill_sim_lock_status);
418 const base::DictionaryValue* shill_home_provider = NULL;
419 if (shill_dictionary_->GetDictionaryWithoutPathExpansion(
420 shill::kHomeProviderProperty, &shill_home_provider)) {
421 TranslateAndAddNestedObject(::onc::cellular::kHomeProvider,
422 *shill_home_provider);
424 const base::ListValue* shill_apns = NULL;
425 if (shill_dictionary_->GetListWithoutPathExpansion(
426 shill::kCellularApnListProperty, &shill_apns)) {
427 TranslateAndAddListOfObjects(::onc::cellular::kAPNList, *shill_apns);
429 const base::ListValue* shill_found_networks = NULL;
430 if (shill_dictionary_->GetListWithoutPathExpansion(
431 shill::kFoundNetworksProperty, &shill_found_networks)) {
432 TranslateAndAddListOfObjects(::onc::cellular::kFoundNetworks,
433 *shill_found_networks);
437 void ShillToONCTranslator::TranslateNetworkWithState() {
438 CopyPropertiesAccordingToSignature();
440 std::string shill_network_type;
441 shill_dictionary_->GetStringWithoutPathExpansion(shill::kTypeProperty,
442 &shill_network_type);
443 std::string onc_network_type = ::onc::network_type::kEthernet;
444 if (shill_network_type != shill::kTypeEthernet &&
445 shill_network_type != shill::kTypeEthernetEap) {
446 TranslateStringToONC(kNetworkTypeTable, shill_network_type,
447 &onc_network_type);
449 // Translate nested Cellular, WiFi, etc. properties.
450 if (!onc_network_type.empty()) {
451 onc_object_->SetStringWithoutPathExpansion(::onc::network_config::kType,
452 onc_network_type);
453 TranslateAndAddNestedObject(onc_network_type);
456 // Since Name is a read only field in Shill unless it's a VPN, it is copied
457 // here, but not when going the other direction (if it's not a VPN).
458 std::string name;
459 shill_dictionary_->GetStringWithoutPathExpansion(shill::kNameProperty, &name);
460 onc_object_->SetStringWithoutPathExpansion(::onc::network_config::kName,
461 name);
463 // Limit ONC state to "NotConnected", "Connected", or "Connecting".
464 std::string state;
465 if (shill_dictionary_->GetStringWithoutPathExpansion(shill::kStateProperty,
466 &state)) {
467 std::string onc_state = ::onc::connection_state::kNotConnected;
468 if (NetworkState::StateIsConnected(state)) {
469 onc_state = ::onc::connection_state::kConnected;
470 } else if (NetworkState::StateIsConnecting(state)) {
471 onc_state = ::onc::connection_state::kConnecting;
473 onc_object_->SetStringWithoutPathExpansion(
474 ::onc::network_config::kConnectionState, onc_state);
475 // Only set 'RestrictedConnectivity' if captive portal state is true.
476 if (NetworkState::NetworkStateIsCaptivePortal(*shill_dictionary_)) {
477 onc_object_->SetBooleanWithoutPathExpansion(
478 ::onc::network_config::kRestrictedConnectivity, true);
482 // 'ErrorState' reflects the most recent error maintained in NetworkState
483 // (which may not match Shill's Error or PreviousError properties). Non
484 // visible networks (with null network_state_) do not set ErrorState.
485 if (network_state_) {
486 std::string error_state = network_state_->GetErrorState();
487 if (!error_state.empty()) {
488 onc_object_->SetStringWithoutPathExpansion(
489 ::onc::network_config::kErrorState, error_state);
493 std::string profile_path;
494 if (onc_source_ != ::onc::ONC_SOURCE_UNKNOWN &&
495 shill_dictionary_->GetStringWithoutPathExpansion(shill::kProfileProperty,
496 &profile_path)) {
497 std::string source;
498 if (onc_source_ == ::onc::ONC_SOURCE_DEVICE_POLICY)
499 source = ::onc::network_config::kSourceDevicePolicy;
500 else if (onc_source_ == ::onc::ONC_SOURCE_USER_POLICY)
501 source = ::onc::network_config::kSourceUserPolicy;
502 else if (profile_path == NetworkProfileHandler::GetSharedProfilePath())
503 source = ::onc::network_config::kSourceDevice;
504 else if (!profile_path.empty())
505 source = ::onc::network_config::kSourceUser;
506 else
507 source = ::onc::network_config::kSourceNone;
508 onc_object_->SetStringWithoutPathExpansion(::onc::network_config::kSource,
509 source);
512 // Use a human-readable aa:bb format for any hardware MAC address. Note:
513 // this property is provided by the caller but is not part of the Shill
514 // Service properties (it is copied from the Device properties).
515 std::string address;
516 if (shill_dictionary_->GetStringWithoutPathExpansion(shill::kAddressProperty,
517 &address)) {
518 onc_object_->SetStringWithoutPathExpansion(
519 ::onc::network_config::kMacAddress,
520 network_util::FormattedMacAddress(address));
523 // Shill's Service has an IPConfig property (note the singular), not an
524 // IPConfigs property. However, we require the caller of the translation to
525 // patch the Shill dictionary before passing it to the translator.
526 const base::ListValue* shill_ipconfigs = NULL;
527 if (shill_dictionary_->GetListWithoutPathExpansion(shill::kIPConfigsProperty,
528 &shill_ipconfigs)) {
529 TranslateAndAddListOfObjects(::onc::network_config::kIPConfigs,
530 *shill_ipconfigs);
533 const base::DictionaryValue* saved_ipconfig = nullptr;
534 if (shill_dictionary_->GetDictionaryWithoutPathExpansion(
535 shill::kSavedIPConfigProperty, &saved_ipconfig)) {
536 TranslateAndAddNestedObject(::onc::network_config::kSavedIPConfig,
537 *saved_ipconfig);
540 // Translate the StaticIPConfig object and set the IP config types.
541 const base::DictionaryValue* static_ipconfig = nullptr;
542 if (shill_dictionary_->GetDictionaryWithoutPathExpansion(
543 shill::kStaticIPConfigProperty, &static_ipconfig)) {
544 std::string ip_address;
545 if (static_ipconfig->GetStringWithoutPathExpansion(shill::kAddressProperty,
546 &ip_address) &&
547 !ip_address.empty()) {
548 onc_object_->SetStringWithoutPathExpansion(
549 ::onc::network_config::kIPAddressConfigType,
550 ::onc::network_config::kIPConfigTypeStatic);
552 const base::ListValue* name_servers = nullptr;
553 if (static_ipconfig->GetListWithoutPathExpansion(
554 shill::kNameServersProperty, &name_servers) &&
555 !name_servers->empty()) {
556 onc_object_->SetStringWithoutPathExpansion(
557 ::onc::network_config::kNameServersConfigType,
558 ::onc::network_config::kIPConfigTypeStatic);
560 if (!ip_address.empty() || (name_servers && !name_servers->empty())) {
561 TranslateAndAddNestedObject(::onc::network_config::kStaticIPConfig,
562 *static_ipconfig);
567 void ShillToONCTranslator::TranslateIPConfig() {
568 CopyPropertiesAccordingToSignature();
569 std::string shill_ip_method;
570 shill_dictionary_->GetStringWithoutPathExpansion(shill::kMethodProperty,
571 &shill_ip_method);
572 std::string type;
573 if (shill_ip_method == shill::kTypeIPv4 ||
574 shill_ip_method == shill::kTypeDHCP) {
575 type = ::onc::ipconfig::kIPv4;
576 } else if (shill_ip_method == shill::kTypeIPv6 ||
577 shill_ip_method == shill::kTypeDHCP6) {
578 type = ::onc::ipconfig::kIPv6;
579 } else {
580 return; // Ignore unhandled IPConfig types, e.g. bootp, zeroconf, ppp
583 onc_object_->SetStringWithoutPathExpansion(::onc::ipconfig::kType, type);
586 void ShillToONCTranslator::TranslateSavedOrStaticIPConfig() {
587 CopyPropertiesAccordingToSignature();
589 // Static and Saved IPConfig in Shill are always of type IPv4. Set this type
590 // in ONC, but not if the object would be empty except the type.
591 if (!onc_object_->empty()) {
592 onc_object_->SetStringWithoutPathExpansion(::onc::ipconfig::kType,
593 ::onc::ipconfig::kIPv4);
597 void ShillToONCTranslator::TranslateSavedIPConfig() {
598 TranslateSavedOrStaticIPConfig();
601 void ShillToONCTranslator::TranslateStaticIPConfig() {
602 TranslateSavedOrStaticIPConfig();
605 void ShillToONCTranslator::TranslateAndAddNestedObject(
606 const std::string& onc_field_name) {
607 TranslateAndAddNestedObject(onc_field_name, *shill_dictionary_);
610 void ShillToONCTranslator::TranslateAndAddNestedObject(
611 const std::string& onc_field_name,
612 const base::DictionaryValue& dictionary) {
613 const OncFieldSignature* field_signature =
614 GetFieldSignature(*onc_signature_, onc_field_name);
615 if (!field_signature) {
616 NOTREACHED() << "Unable to find signature for field: " << onc_field_name;
617 return;
619 ShillToONCTranslator nested_translator(dictionary, onc_source_,
620 *field_signature->value_signature,
621 network_state_);
622 scoped_ptr<base::DictionaryValue> nested_object =
623 nested_translator.CreateTranslatedONCObject();
624 if (nested_object->empty())
625 return;
626 onc_object_->SetWithoutPathExpansion(onc_field_name, nested_object.release());
629 void ShillToONCTranslator::SetNestedOncValue(
630 const std::string& onc_dictionary_name,
631 const std::string& onc_field_name,
632 const base::Value& value) {
633 base::DictionaryValue* nested;
634 if (!onc_object_->GetDictionaryWithoutPathExpansion(onc_dictionary_name,
635 &nested)) {
636 nested = new base::DictionaryValue;
637 onc_object_->SetWithoutPathExpansion(onc_dictionary_name, nested);
639 nested->SetWithoutPathExpansion(onc_field_name, value.DeepCopy());
642 void ShillToONCTranslator::TranslateAndAddListOfObjects(
643 const std::string& onc_field_name,
644 const base::ListValue& list) {
645 const OncFieldSignature* field_signature =
646 GetFieldSignature(*onc_signature_, onc_field_name);
647 if (field_signature->value_signature->onc_type != base::Value::TYPE_LIST) {
648 LOG(ERROR) << "ONC Field name: '" << onc_field_name << "' has type '"
649 << field_signature->value_signature->onc_type
650 << "', expected: base::Value::TYPE_LIST: " << GetName();
651 return;
653 DCHECK(field_signature->value_signature->onc_array_entry_signature);
654 scoped_ptr<base::ListValue> result(new base::ListValue());
655 for (base::ListValue::const_iterator it = list.begin(); it != list.end();
656 ++it) {
657 const base::DictionaryValue* shill_value = NULL;
658 if (!(*it)->GetAsDictionary(&shill_value))
659 continue;
660 ShillToONCTranslator nested_translator(
661 *shill_value, onc_source_,
662 *field_signature->value_signature->onc_array_entry_signature,
663 network_state_);
664 scoped_ptr<base::DictionaryValue> nested_object =
665 nested_translator.CreateTranslatedONCObject();
666 // If the nested object couldn't be parsed, simply omit it.
667 if (nested_object->empty())
668 continue;
669 result->Append(nested_object.release());
671 // If there are no entries in the list, there is no need to expose this field.
672 if (result->empty())
673 return;
674 onc_object_->SetWithoutPathExpansion(onc_field_name, result.release());
677 void ShillToONCTranslator::CopyPropertiesAccordingToSignature() {
678 CopyPropertiesAccordingToSignature(onc_signature_);
681 void ShillToONCTranslator::CopyPropertiesAccordingToSignature(
682 const OncValueSignature* value_signature) {
683 if (value_signature->base_signature)
684 CopyPropertiesAccordingToSignature(value_signature->base_signature);
685 if (!value_signature->fields)
686 return;
687 for (const OncFieldSignature* field_signature = value_signature->fields;
688 field_signature->onc_field_name != NULL; ++field_signature) {
689 CopyProperty(field_signature);
693 void ShillToONCTranslator::CopyProperty(
694 const OncFieldSignature* field_signature) {
695 std::string shill_property_name;
696 const base::Value* shill_value = NULL;
697 if (!field_translation_table_ ||
698 !GetShillPropertyName(field_signature->onc_field_name,
699 field_translation_table_, &shill_property_name) ||
700 !shill_dictionary_->GetWithoutPathExpansion(shill_property_name,
701 &shill_value)) {
702 return;
705 if (shill_value->GetType() != field_signature->value_signature->onc_type) {
706 LOG(ERROR) << "Shill property '" << shill_property_name << "' with value "
707 << *shill_value << " has base::Value::Type "
708 << shill_value->GetType() << " but ONC field '"
709 << field_signature->onc_field_name << "' requires type "
710 << field_signature->value_signature->onc_type << ": "
711 << GetName();
712 return;
715 onc_object_->SetWithoutPathExpansion(field_signature->onc_field_name,
716 shill_value->DeepCopy());
719 void ShillToONCTranslator::TranslateWithTableAndSet(
720 const std::string& shill_property_name,
721 const StringTranslationEntry table[],
722 const std::string& onc_field_name) {
723 std::string shill_value;
724 if (!shill_dictionary_->GetStringWithoutPathExpansion(shill_property_name,
725 &shill_value)) {
726 return;
728 std::string onc_value;
729 if (TranslateStringToONC(table, shill_value, &onc_value)) {
730 onc_object_->SetStringWithoutPathExpansion(onc_field_name, onc_value);
731 return;
733 LOG(ERROR) << "Shill property '" << shill_property_name << "' with value "
734 << shill_value << " couldn't be translated to ONC: " << GetName();
737 std::string ShillToONCTranslator::GetName() {
738 DCHECK(shill_dictionary_);
739 std::string name;
740 shill_dictionary_->GetStringWithoutPathExpansion(shill::kNameProperty, &name);
741 return name;
744 } // namespace
746 scoped_ptr<base::DictionaryValue> TranslateShillServiceToONCPart(
747 const base::DictionaryValue& shill_dictionary,
748 ::onc::ONCSource onc_source,
749 const OncValueSignature* onc_signature,
750 const NetworkState* network_state) {
751 CHECK(onc_signature != NULL);
753 ShillToONCTranslator translator(shill_dictionary, onc_source, *onc_signature,
754 network_state);
755 return translator.CreateTranslatedONCObject();
758 } // namespace onc
759 } // namespace chromeos