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"
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"
29 // Converts |str| to a base::Value of the given |type|. If the conversion fails,
31 scoped_ptr
<base::Value
> ConvertStringToValue(const std::string
& str
,
32 base::Value::Type type
) {
34 if (type
== base::Value::TYPE_STRING
) {
35 value
= new base::StringValue(str
);
37 value
= base::JSONReader::Read(str
);
40 if (value
== NULL
|| value
->GetType() != type
) {
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
51 class ShillToONCTranslator
{
53 ShillToONCTranslator(const base::DictionaryValue
& shill_dictionary
,
54 ::onc::ONCSource onc_source
,
55 const OncValueSignature
& onc_signature
)
56 : shill_dictionary_(&shill_dictionary
),
57 onc_source_(onc_source
),
58 onc_signature_(&onc_signature
) {
59 field_translation_table_
= GetFieldTranslationTable(onc_signature
);
62 ShillToONCTranslator(const base::DictionaryValue
& shill_dictionary
,
63 ::onc::ONCSource onc_source
,
64 const OncValueSignature
& onc_signature
,
65 const FieldTranslationEntry
* field_translation_table
)
66 : shill_dictionary_(&shill_dictionary
),
67 onc_source_(onc_source
),
68 onc_signature_(&onc_signature
),
69 field_translation_table_(field_translation_table
) {}
71 // Translates the associated Shill dictionary and creates an ONC object of the
73 scoped_ptr
<base::DictionaryValue
> CreateTranslatedONCObject();
76 void TranslateEthernet();
77 void TranslateOpenVPN();
78 void TranslateIPsec();
79 void TranslateThirdPartyVPN();
81 void TranslateWiFiWithState();
82 void TranslateWiMAXWithState();
83 void TranslateCellularWithState();
84 void TranslateCellularDevice();
85 void TranslateNetworkWithState();
86 void TranslateIPConfig();
87 void TranslateSavedOrStaticIPConfig();
88 void TranslateSavedIPConfig();
89 void TranslateStaticIPConfig();
91 // Creates an ONC object from |dictionary| according to the signature
92 // associated to |onc_field_name| and adds it to |onc_object_| at
94 void TranslateAndAddNestedObject(const std::string
& onc_field_name
,
95 const base::DictionaryValue
& dictionary
);
97 // Creates an ONC object from |shill_dictionary_| according to the signature
98 // associated to |onc_field_name| and adds it to |onc_object_| at
100 void TranslateAndAddNestedObject(const std::string
& onc_field_name
);
102 // Sets |onc_field_name| in dictionary |onc_dictionary_name| in |onc_object_|
103 // to |value| if the dictionary exists.
104 void SetNestedOncValue(const std::string
& onc_dictionary_name
,
105 const std::string
& onc_field_name
,
106 const base::Value
& value
);
108 // Translates a list of nested objects and adds the list to |onc_object_| at
109 // |onc_field_name|. If there are errors while parsing individual objects or
110 // if the resulting list contains no entries, the result will not be added to
112 void TranslateAndAddListOfObjects(const std::string
& onc_field_name
,
113 const base::ListValue
& list
);
115 // Applies function CopyProperty to each field of |value_signature| and its
117 void CopyPropertiesAccordingToSignature(
118 const OncValueSignature
* value_signature
);
120 // Applies function CopyProperty to each field of |onc_signature_| and its
122 void CopyPropertiesAccordingToSignature();
124 // If |shill_property_name| is defined in |field_signature|, copies this
125 // entry from |shill_dictionary_| to |onc_object_| if it exists.
126 void CopyProperty(const OncFieldSignature
* field_signature
);
128 // If existent, translates the entry at |shill_property_name| in
129 // |shill_dictionary_| using |table|. It is an error if no matching table
130 // entry is found. Writes the result as entry at |onc_field_name| in
132 void TranslateWithTableAndSet(const std::string
& shill_property_name
,
133 const StringTranslationEntry table
[],
134 const std::string
& onc_field_name
);
136 // Returns the name of the Shill service provided in |shill_dictionary_|
138 std::string
GetName();
140 const base::DictionaryValue
* shill_dictionary_
;
141 ::onc::ONCSource onc_source_
;
142 const OncValueSignature
* onc_signature_
;
143 const FieldTranslationEntry
* field_translation_table_
;
144 scoped_ptr
<base::DictionaryValue
> onc_object_
;
146 DISALLOW_COPY_AND_ASSIGN(ShillToONCTranslator
);
149 scoped_ptr
<base::DictionaryValue
>
150 ShillToONCTranslator::CreateTranslatedONCObject() {
151 onc_object_
.reset(new base::DictionaryValue
);
152 if (onc_signature_
== &kNetworkWithStateSignature
) {
153 TranslateNetworkWithState();
154 } else if (onc_signature_
== &kEthernetSignature
) {
156 } else if (onc_signature_
== &kVPNSignature
) {
158 } else if (onc_signature_
== &kOpenVPNSignature
) {
160 } else if (onc_signature_
== &kIPsecSignature
) {
162 } else if (onc_signature_
== &kThirdPartyVPNSignature
) {
163 TranslateThirdPartyVPN();
164 } else if (onc_signature_
== &kWiFiWithStateSignature
) {
165 TranslateWiFiWithState();
166 } else if (onc_signature_
== &kWiMAXWithStateSignature
) {
167 TranslateWiMAXWithState();
168 } else if (onc_signature_
== &kCellularWithStateSignature
) {
169 if (field_translation_table_
== kCellularDeviceTable
)
170 TranslateCellularDevice();
172 TranslateCellularWithState();
173 } else if (onc_signature_
== &kIPConfigSignature
) {
175 } else if (onc_signature_
== &kSavedIPConfigSignature
) {
176 TranslateSavedIPConfig();
177 } else if (onc_signature_
== &kStaticIPConfigSignature
) {
178 TranslateStaticIPConfig();
180 CopyPropertiesAccordingToSignature();
182 return onc_object_
.Pass();
185 void ShillToONCTranslator::TranslateEthernet() {
186 std::string shill_network_type
;
187 shill_dictionary_
->GetStringWithoutPathExpansion(shill::kTypeProperty
,
188 &shill_network_type
);
189 const char* onc_auth
= ::onc::ethernet::kAuthenticationNone
;
190 if (shill_network_type
== shill::kTypeEthernetEap
)
191 onc_auth
= ::onc::ethernet::k8021X
;
192 onc_object_
->SetStringWithoutPathExpansion(::onc::ethernet::kAuthentication
,
196 void ShillToONCTranslator::TranslateOpenVPN() {
197 if (shill_dictionary_
->HasKey(shill::kOpenVPNVerifyX509NameProperty
))
198 TranslateAndAddNestedObject(::onc::openvpn::kVerifyX509
);
200 // Shill supports only one RemoteCertKU but ONC requires a list. If existing,
201 // wraps the value into a list.
203 if (shill_dictionary_
->GetStringWithoutPathExpansion(
204 shill::kOpenVPNRemoteCertKUProperty
, &certKU
)) {
205 scoped_ptr
<base::ListValue
> certKUs(new base::ListValue
);
206 certKUs
->AppendString(certKU
);
207 onc_object_
->SetWithoutPathExpansion(::onc::openvpn::kRemoteCertKU
,
211 for (const OncFieldSignature
* field_signature
= onc_signature_
->fields
;
212 field_signature
->onc_field_name
!= NULL
; ++field_signature
) {
213 const std::string
& onc_field_name
= field_signature
->onc_field_name
;
214 if (onc_field_name
== ::onc::openvpn::kRemoteCertKU
||
215 onc_field_name
== ::onc::openvpn::kServerCAPEMs
) {
216 CopyProperty(field_signature
);
220 std::string shill_property_name
;
221 const base::Value
* shill_value
= NULL
;
222 if (!field_translation_table_
||
223 !GetShillPropertyName(field_signature
->onc_field_name
,
224 field_translation_table_
, &shill_property_name
) ||
225 !shill_dictionary_
->GetWithoutPathExpansion(shill_property_name
,
230 scoped_ptr
<base::Value
> translated
;
231 std::string shill_str
;
232 if (shill_value
->GetAsString(&shill_str
)) {
233 // Shill wants all Provider/VPN fields to be strings. Translates these
234 // strings back to the correct ONC type.
235 translated
= ConvertStringToValue(
236 shill_str
, field_signature
->value_signature
->onc_type
);
238 if (translated
.get() == NULL
) {
239 LOG(ERROR
) << "Shill property '" << shill_property_name
240 << "' with value " << *shill_value
241 << " couldn't be converted to base::Value::Type "
242 << field_signature
->value_signature
->onc_type
<< ": "
245 onc_object_
->SetWithoutPathExpansion(onc_field_name
,
246 translated
.release());
249 LOG(ERROR
) << "Shill property '" << shill_property_name
<< "' has value "
250 << *shill_value
<< ", but expected a string: " << GetName();
255 void ShillToONCTranslator::TranslateIPsec() {
256 CopyPropertiesAccordingToSignature();
257 if (shill_dictionary_
->HasKey(shill::kL2tpIpsecXauthUserProperty
))
258 TranslateAndAddNestedObject(::onc::ipsec::kXAUTH
);
259 std::string client_cert_id
;
260 shill_dictionary_
->GetStringWithoutPathExpansion(
261 shill::kL2tpIpsecClientCertIdProperty
, &client_cert_id
);
262 std::string authentication_type
=
263 client_cert_id
.empty() ? ::onc::ipsec::kPSK
: ::onc::ipsec::kCert
;
264 onc_object_
->SetStringWithoutPathExpansion(::onc::ipsec::kAuthenticationType
,
265 authentication_type
);
268 void ShillToONCTranslator::TranslateThirdPartyVPN() {
269 CopyPropertiesAccordingToSignature();
271 // For third-party VPNs, |shill::kProviderHostProperty| is used to store the
272 // provider's extension ID.
273 std::string shill_extension_id
;
274 shill_dictionary_
->GetStringWithoutPathExpansion(shill::kHostProperty
,
275 &shill_extension_id
);
276 onc_object_
->SetStringWithoutPathExpansion(
277 ::onc::third_party_vpn::kExtensionID
, shill_extension_id
);
280 void ShillToONCTranslator::TranslateVPN() {
281 CopyPropertiesAccordingToSignature();
283 // Parse Shill Provider dictionary. Note, this may not exist, e.g. if we are
284 // just translating network state in network_util::TranslateNetworkStateToONC.
285 const base::DictionaryValue
* provider
= NULL
;
286 if (!shill_dictionary_
->GetDictionaryWithoutPathExpansion(
287 shill::kProviderProperty
, &provider
)) {
290 std::string shill_provider_type
, onc_provider_type
;
291 provider
->GetStringWithoutPathExpansion(shill::kTypeProperty
,
292 &shill_provider_type
);
293 if (!TranslateStringToONC(kVPNTypeTable
, shill_provider_type
,
294 &onc_provider_type
)) {
297 onc_object_
->SetStringWithoutPathExpansion(::onc::vpn::kType
,
299 std::string shill_provider_host
;
300 if (onc_provider_type
!= ::onc::vpn::kThirdPartyVpn
&&
301 provider
->GetStringWithoutPathExpansion(shill::kHostProperty
,
302 &shill_provider_host
)) {
303 onc_object_
->SetStringWithoutPathExpansion(::onc::vpn::kHost
,
304 shill_provider_host
);
307 // Translate the nested dictionary.
308 std::string provider_type_dictionary
;
309 if (onc_provider_type
== ::onc::vpn::kTypeL2TP_IPsec
) {
310 TranslateAndAddNestedObject(::onc::vpn::kIPsec
, *provider
);
311 TranslateAndAddNestedObject(::onc::vpn::kL2TP
, *provider
);
312 provider_type_dictionary
= ::onc::vpn::kIPsec
;
314 TranslateAndAddNestedObject(onc_provider_type
, *provider
);
315 provider_type_dictionary
= onc_provider_type
;
318 bool save_credentials
;
319 if (onc_provider_type
!= ::onc::vpn::kThirdPartyVpn
&&
320 shill_dictionary_
->GetBooleanWithoutPathExpansion(
321 shill::kSaveCredentialsProperty
, &save_credentials
)) {
322 SetNestedOncValue(provider_type_dictionary
, ::onc::vpn::kSaveCredentials
,
323 base::FundamentalValue(save_credentials
));
327 void ShillToONCTranslator::TranslateWiFiWithState() {
328 TranslateWithTableAndSet(shill::kSecurityClassProperty
, kWiFiSecurityTable
,
329 ::onc::wifi::kSecurity
);
330 bool unknown_encoding
= true;
331 std::string ssid
= shill_property_util::GetSSIDFromProperties(
332 *shill_dictionary_
, false /* verbose_logging */, &unknown_encoding
);
333 if (!unknown_encoding
&& !ssid
.empty())
334 onc_object_
->SetStringWithoutPathExpansion(::onc::wifi::kSSID
, ssid
);
336 bool link_monitor_disable
;
337 if (shill_dictionary_
->GetBooleanWithoutPathExpansion(
338 shill::kLinkMonitorDisableProperty
, &link_monitor_disable
)) {
339 onc_object_
->SetBooleanWithoutPathExpansion(
340 ::onc::wifi::kAllowGatewayARPPolling
, !link_monitor_disable
);
343 CopyPropertiesAccordingToSignature();
344 TranslateAndAddNestedObject(::onc::wifi::kEAP
);
347 void ShillToONCTranslator::TranslateWiMAXWithState() {
348 CopyPropertiesAccordingToSignature();
349 TranslateAndAddNestedObject(::onc::wimax::kEAP
);
352 void ShillToONCTranslator::TranslateCellularWithState() {
353 CopyPropertiesAccordingToSignature();
354 TranslateWithTableAndSet(shill::kActivationStateProperty
,
355 kActivationStateTable
,
356 ::onc::cellular::kActivationState
);
357 TranslateWithTableAndSet(shill::kNetworkTechnologyProperty
,
358 kNetworkTechnologyTable
,
359 ::onc::cellular::kNetworkTechnology
);
360 const base::DictionaryValue
* dictionary
= NULL
;
361 if (shill_dictionary_
->GetDictionaryWithoutPathExpansion(
362 shill::kServingOperatorProperty
, &dictionary
)) {
363 TranslateAndAddNestedObject(::onc::cellular::kServingOperator
, *dictionary
);
365 if (shill_dictionary_
->GetDictionaryWithoutPathExpansion(
366 shill::kCellularApnProperty
, &dictionary
)) {
367 TranslateAndAddNestedObject(::onc::cellular::kAPN
, *dictionary
);
369 if (shill_dictionary_
->GetDictionaryWithoutPathExpansion(
370 shill::kCellularLastGoodApnProperty
, &dictionary
)) {
371 TranslateAndAddNestedObject(::onc::cellular::kLastGoodAPN
, *dictionary
);
373 const base::DictionaryValue
* device_dictionary
= NULL
;
374 bool requires_roaming
= false;
375 shill_dictionary_
->GetDictionaryWithoutPathExpansion(shill::kDeviceProperty
,
377 if (device_dictionary
) {
378 // Merge the Device dictionary with this one (Cellular) using the
379 // CellularDevice signature.
380 ShillToONCTranslator
nested_translator(*device_dictionary
, onc_source_
,
381 kCellularWithStateSignature
,
382 kCellularDeviceTable
);
383 scoped_ptr
<base::DictionaryValue
> nested_object
=
384 nested_translator
.CreateTranslatedONCObject();
385 onc_object_
->MergeDictionary(nested_object
.get());
387 /// Get the requires_roaming from the Device dictionary.
388 device_dictionary
->GetBooleanWithoutPathExpansion(
389 shill::kProviderRequiresRoamingProperty
, &requires_roaming
);
391 if (requires_roaming
) {
392 onc_object_
->SetStringWithoutPathExpansion(
393 ::onc::cellular::kRoamingState
, ::onc::cellular::kRoamingRequired
);
395 TranslateWithTableAndSet(shill::kRoamingStateProperty
, kRoamingStateTable
,
396 ::onc::cellular::kRoamingState
);
400 void ShillToONCTranslator::TranslateCellularDevice() {
401 CopyPropertiesAccordingToSignature();
402 const base::DictionaryValue
* shill_sim_lock_status
= NULL
;
403 if (shill_dictionary_
->GetDictionaryWithoutPathExpansion(
404 shill::kSIMLockStatusProperty
, &shill_sim_lock_status
)) {
405 TranslateAndAddNestedObject(::onc::cellular::kSIMLockStatus
,
406 *shill_sim_lock_status
);
408 const base::DictionaryValue
* shill_home_provider
= NULL
;
409 if (shill_dictionary_
->GetDictionaryWithoutPathExpansion(
410 shill::kHomeProviderProperty
, &shill_home_provider
)) {
411 TranslateAndAddNestedObject(::onc::cellular::kHomeProvider
,
412 *shill_home_provider
);
414 const base::ListValue
* shill_apns
= NULL
;
415 if (shill_dictionary_
->GetListWithoutPathExpansion(
416 shill::kCellularApnListProperty
, &shill_apns
)) {
417 TranslateAndAddListOfObjects(::onc::cellular::kAPNList
, *shill_apns
);
419 const base::ListValue
* shill_found_networks
= NULL
;
420 if (shill_dictionary_
->GetListWithoutPathExpansion(
421 shill::kFoundNetworksProperty
, &shill_found_networks
)) {
422 TranslateAndAddListOfObjects(::onc::cellular::kFoundNetworks
,
423 *shill_found_networks
);
427 void ShillToONCTranslator::TranslateNetworkWithState() {
428 CopyPropertiesAccordingToSignature();
430 std::string shill_network_type
;
431 shill_dictionary_
->GetStringWithoutPathExpansion(shill::kTypeProperty
,
432 &shill_network_type
);
433 std::string onc_network_type
= ::onc::network_type::kEthernet
;
434 if (shill_network_type
!= shill::kTypeEthernet
&&
435 shill_network_type
!= shill::kTypeEthernetEap
) {
436 TranslateStringToONC(kNetworkTypeTable
, shill_network_type
,
439 // Translate nested Cellular, WiFi, etc. properties.
440 if (!onc_network_type
.empty()) {
441 onc_object_
->SetStringWithoutPathExpansion(::onc::network_config::kType
,
443 TranslateAndAddNestedObject(onc_network_type
);
446 // Since Name is a read only field in Shill unless it's a VPN, it is copied
447 // here, but not when going the other direction (if it's not a VPN).
449 shill_dictionary_
->GetStringWithoutPathExpansion(shill::kNameProperty
, &name
);
450 onc_object_
->SetStringWithoutPathExpansion(::onc::network_config::kName
,
453 // Limit ONC state to "NotConnected", "Connected", or "Connecting".
455 if (shill_dictionary_
->GetStringWithoutPathExpansion(shill::kStateProperty
,
457 std::string onc_state
= ::onc::connection_state::kNotConnected
;
458 if (NetworkState::StateIsConnected(state
)) {
459 onc_state
= ::onc::connection_state::kConnected
;
460 } else if (NetworkState::StateIsConnecting(state
)) {
461 onc_state
= ::onc::connection_state::kConnecting
;
463 onc_object_
->SetStringWithoutPathExpansion(
464 ::onc::network_config::kConnectionState
, onc_state
);
465 // Only set 'RestrictedConnectivity' if captive portal state is true.
466 if (NetworkState::NetworkStateIsCaptivePortal(*shill_dictionary_
)) {
467 onc_object_
->SetBooleanWithoutPathExpansion(
468 ::onc::network_config::kRestrictedConnectivity
, true);
472 std::string profile_path
;
473 if (onc_source_
!= ::onc::ONC_SOURCE_UNKNOWN
&&
474 shill_dictionary_
->GetStringWithoutPathExpansion(shill::kProfileProperty
,
477 if (onc_source_
== ::onc::ONC_SOURCE_DEVICE_POLICY
)
478 source
= ::onc::network_config::kSourceDevicePolicy
;
479 else if (onc_source_
== ::onc::ONC_SOURCE_USER_POLICY
)
480 source
= ::onc::network_config::kSourceUserPolicy
;
481 else if (profile_path
== NetworkProfileHandler::GetSharedProfilePath())
482 source
= ::onc::network_config::kSourceDevice
;
483 else if (!profile_path
.empty())
484 source
= ::onc::network_config::kSourceUser
;
486 source
= ::onc::network_config::kSourceNone
;
487 onc_object_
->SetStringWithoutPathExpansion(::onc::network_config::kSource
,
491 // Use a human-readable aa:bb format for any hardware MAC address. Note:
492 // this property is provided by the caller but is not part of the Shill
493 // Service properties (it is copied from the Device properties).
495 if (shill_dictionary_
->GetStringWithoutPathExpansion(shill::kAddressProperty
,
497 onc_object_
->SetStringWithoutPathExpansion(
498 ::onc::network_config::kMacAddress
,
499 network_util::FormattedMacAddress(address
));
502 // Shill's Service has an IPConfig property (note the singular), not an
503 // IPConfigs property. However, we require the caller of the translation to
504 // patch the Shill dictionary before passing it to the translator.
505 const base::ListValue
* shill_ipconfigs
= NULL
;
506 if (shill_dictionary_
->GetListWithoutPathExpansion(shill::kIPConfigsProperty
,
508 TranslateAndAddListOfObjects(::onc::network_config::kIPConfigs
,
512 const base::DictionaryValue
* saved_ipconfig
= nullptr;
513 if (shill_dictionary_
->GetDictionaryWithoutPathExpansion(
514 shill::kSavedIPConfigProperty
, &saved_ipconfig
)) {
515 TranslateAndAddNestedObject(::onc::network_config::kSavedIPConfig
,
519 // Translate the StaticIPConfig object and set the IP config types.
520 const base::DictionaryValue
* static_ipconfig
= nullptr;
521 if (shill_dictionary_
->GetDictionaryWithoutPathExpansion(
522 shill::kStaticIPConfigProperty
, &static_ipconfig
)) {
523 std::string ip_address
;
524 if (static_ipconfig
->GetStringWithoutPathExpansion(shill::kAddressProperty
,
526 !ip_address
.empty()) {
527 onc_object_
->SetStringWithoutPathExpansion(
528 ::onc::network_config::kIPAddressConfigType
,
529 ::onc::network_config::kIPConfigTypeStatic
);
531 const base::ListValue
* name_servers
= nullptr;
532 if (static_ipconfig
->GetListWithoutPathExpansion(
533 shill::kNameServersProperty
, &name_servers
) &&
534 !name_servers
->empty()) {
535 onc_object_
->SetStringWithoutPathExpansion(
536 ::onc::network_config::kNameServersConfigType
,
537 ::onc::network_config::kIPConfigTypeStatic
);
539 if (!ip_address
.empty() || (name_servers
&& !name_servers
->empty())) {
540 TranslateAndAddNestedObject(::onc::network_config::kStaticIPConfig
,
546 void ShillToONCTranslator::TranslateIPConfig() {
547 CopyPropertiesAccordingToSignature();
548 std::string shill_ip_method
;
549 shill_dictionary_
->GetStringWithoutPathExpansion(shill::kMethodProperty
,
552 if (shill_ip_method
== shill::kTypeIPv4
||
553 shill_ip_method
== shill::kTypeDHCP
) {
554 type
= ::onc::ipconfig::kIPv4
;
555 } else if (shill_ip_method
== shill::kTypeIPv6
||
556 shill_ip_method
== shill::kTypeDHCP6
) {
557 type
= ::onc::ipconfig::kIPv6
;
559 return; // Ignore unhandled IPConfig types, e.g. bootp, zeroconf, ppp
562 onc_object_
->SetStringWithoutPathExpansion(::onc::ipconfig::kType
, type
);
565 void ShillToONCTranslator::TranslateSavedOrStaticIPConfig() {
566 CopyPropertiesAccordingToSignature();
568 // Static and Saved IPConfig in Shill are always of type IPv4. Set this type
569 // in ONC, but not if the object would be empty except the type.
570 if (!onc_object_
->empty()) {
571 onc_object_
->SetStringWithoutPathExpansion(::onc::ipconfig::kType
,
572 ::onc::ipconfig::kIPv4
);
576 void ShillToONCTranslator::TranslateSavedIPConfig() {
577 TranslateSavedOrStaticIPConfig();
580 void ShillToONCTranslator::TranslateStaticIPConfig() {
581 TranslateSavedOrStaticIPConfig();
584 void ShillToONCTranslator::TranslateAndAddNestedObject(
585 const std::string
& onc_field_name
) {
586 TranslateAndAddNestedObject(onc_field_name
, *shill_dictionary_
);
589 void ShillToONCTranslator::TranslateAndAddNestedObject(
590 const std::string
& onc_field_name
,
591 const base::DictionaryValue
& dictionary
) {
592 const OncFieldSignature
* field_signature
=
593 GetFieldSignature(*onc_signature_
, onc_field_name
);
594 if (!field_signature
) {
595 NOTREACHED() << "Unable to find signature for field: " << onc_field_name
;
598 ShillToONCTranslator
nested_translator(dictionary
, onc_source_
,
599 *field_signature
->value_signature
);
600 scoped_ptr
<base::DictionaryValue
> nested_object
=
601 nested_translator
.CreateTranslatedONCObject();
602 if (nested_object
->empty())
604 onc_object_
->SetWithoutPathExpansion(onc_field_name
, nested_object
.release());
607 void ShillToONCTranslator::SetNestedOncValue(
608 const std::string
& onc_dictionary_name
,
609 const std::string
& onc_field_name
,
610 const base::Value
& value
) {
611 base::DictionaryValue
* nested
;
612 if (!onc_object_
->GetDictionaryWithoutPathExpansion(onc_dictionary_name
,
614 nested
= new base::DictionaryValue
;
615 onc_object_
->SetWithoutPathExpansion(onc_dictionary_name
, nested
);
617 nested
->SetWithoutPathExpansion(onc_field_name
, value
.DeepCopy());
620 void ShillToONCTranslator::TranslateAndAddListOfObjects(
621 const std::string
& onc_field_name
,
622 const base::ListValue
& list
) {
623 const OncFieldSignature
* field_signature
=
624 GetFieldSignature(*onc_signature_
, onc_field_name
);
625 if (field_signature
->value_signature
->onc_type
!= base::Value::TYPE_LIST
) {
626 LOG(ERROR
) << "ONC Field name: '" << onc_field_name
<< "' has type '"
627 << field_signature
->value_signature
->onc_type
628 << "', expected: base::Value::TYPE_LIST: " << GetName();
631 DCHECK(field_signature
->value_signature
->onc_array_entry_signature
);
632 scoped_ptr
<base::ListValue
> result(new base::ListValue());
633 for (base::ListValue::const_iterator it
= list
.begin(); it
!= list
.end();
635 const base::DictionaryValue
* shill_value
= NULL
;
636 if (!(*it
)->GetAsDictionary(&shill_value
))
638 ShillToONCTranslator
nested_translator(
639 *shill_value
, onc_source_
,
640 *field_signature
->value_signature
->onc_array_entry_signature
);
641 scoped_ptr
<base::DictionaryValue
> nested_object
=
642 nested_translator
.CreateTranslatedONCObject();
643 // If the nested object couldn't be parsed, simply omit it.
644 if (nested_object
->empty())
646 result
->Append(nested_object
.release());
648 // If there are no entries in the list, there is no need to expose this field.
651 onc_object_
->SetWithoutPathExpansion(onc_field_name
, result
.release());
654 void ShillToONCTranslator::CopyPropertiesAccordingToSignature() {
655 CopyPropertiesAccordingToSignature(onc_signature_
);
658 void ShillToONCTranslator::CopyPropertiesAccordingToSignature(
659 const OncValueSignature
* value_signature
) {
660 if (value_signature
->base_signature
)
661 CopyPropertiesAccordingToSignature(value_signature
->base_signature
);
662 if (!value_signature
->fields
)
664 for (const OncFieldSignature
* field_signature
= value_signature
->fields
;
665 field_signature
->onc_field_name
!= NULL
; ++field_signature
) {
666 CopyProperty(field_signature
);
670 void ShillToONCTranslator::CopyProperty(
671 const OncFieldSignature
* field_signature
) {
672 std::string shill_property_name
;
673 const base::Value
* shill_value
= NULL
;
674 if (!field_translation_table_
||
675 !GetShillPropertyName(field_signature
->onc_field_name
,
676 field_translation_table_
, &shill_property_name
) ||
677 !shill_dictionary_
->GetWithoutPathExpansion(shill_property_name
,
682 if (shill_value
->GetType() != field_signature
->value_signature
->onc_type
) {
683 LOG(ERROR
) << "Shill property '" << shill_property_name
<< "' with value "
684 << *shill_value
<< " has base::Value::Type "
685 << shill_value
->GetType() << " but ONC field '"
686 << field_signature
->onc_field_name
<< "' requires type "
687 << field_signature
->value_signature
->onc_type
<< ": "
692 onc_object_
->SetWithoutPathExpansion(field_signature
->onc_field_name
,
693 shill_value
->DeepCopy());
696 void ShillToONCTranslator::TranslateWithTableAndSet(
697 const std::string
& shill_property_name
,
698 const StringTranslationEntry table
[],
699 const std::string
& onc_field_name
) {
700 std::string shill_value
;
701 if (!shill_dictionary_
->GetStringWithoutPathExpansion(shill_property_name
,
705 std::string onc_value
;
706 if (TranslateStringToONC(table
, shill_value
, &onc_value
)) {
707 onc_object_
->SetStringWithoutPathExpansion(onc_field_name
, onc_value
);
710 LOG(ERROR
) << "Shill property '" << shill_property_name
<< "' with value "
711 << shill_value
<< " couldn't be translated to ONC: " << GetName();
714 std::string
ShillToONCTranslator::GetName() {
715 DCHECK(shill_dictionary_
);
717 shill_dictionary_
->GetStringWithoutPathExpansion(shill::kNameProperty
, &name
);
723 scoped_ptr
<base::DictionaryValue
> TranslateShillServiceToONCPart(
724 const base::DictionaryValue
& shill_dictionary
,
725 ::onc::ONCSource onc_source
,
726 const OncValueSignature
* onc_signature
) {
727 CHECK(onc_signature
!= NULL
);
729 ShillToONCTranslator
translator(shill_dictionary
, onc_source
, *onc_signature
);
730 return translator
.CreateTranslatedONCObject();
734 } // namespace chromeos