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 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
77 scoped_ptr
<base::DictionaryValue
> CreateTranslatedONCObject();
80 void TranslateEthernet();
81 void TranslateOpenVPN();
82 void TranslateIPsec();
83 void TranslateThirdPartyVPN();
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
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
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
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
121 void CopyPropertiesAccordingToSignature(
122 const OncValueSignature
* value_signature
);
124 // Applies function CopyProperty to each field of |onc_signature_| and its
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
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_|
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
) {
161 } else if (onc_signature_
== &kVPNSignature
) {
163 } else if (onc_signature_
== &kOpenVPNSignature
) {
165 } else if (onc_signature_
== &kIPsecSignature
) {
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();
177 TranslateCellularWithState();
178 } else if (onc_signature_
== &kIPConfigSignature
) {
180 } else if (onc_signature_
== &kSavedIPConfigSignature
) {
181 TranslateSavedIPConfig();
182 } else if (onc_signature_
== &kStaticIPConfigSignature
) {
183 TranslateStaticIPConfig();
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
,
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.
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
,
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
);
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
,
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
<< ": "
250 onc_object_
->SetWithoutPathExpansion(onc_field_name
,
251 translated
.release());
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
)) {
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
)) {
302 onc_object_
->SetStringWithoutPathExpansion(::onc::vpn::kType
,
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
;
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
,
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
);
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
,
449 // Translate nested Cellular, WiFi, etc. properties.
450 if (!onc_network_type
.empty()) {
451 onc_object_
->SetStringWithoutPathExpansion(::onc::network_config::kType
,
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).
459 shill_dictionary_
->GetStringWithoutPathExpansion(shill::kNameProperty
, &name
);
460 onc_object_
->SetStringWithoutPathExpansion(::onc::network_config::kName
,
463 // Limit ONC state to "NotConnected", "Connected", or "Connecting".
465 if (shill_dictionary_
->GetStringWithoutPathExpansion(shill::kStateProperty
,
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
,
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
;
507 source
= ::onc::network_config::kSourceNone
;
508 onc_object_
->SetStringWithoutPathExpansion(::onc::network_config::kSource
,
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).
516 if (shill_dictionary_
->GetStringWithoutPathExpansion(shill::kAddressProperty
,
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
,
529 TranslateAndAddListOfObjects(::onc::network_config::kIPConfigs
,
533 const base::DictionaryValue
* saved_ipconfig
= nullptr;
534 if (shill_dictionary_
->GetDictionaryWithoutPathExpansion(
535 shill::kSavedIPConfigProperty
, &saved_ipconfig
)) {
536 TranslateAndAddNestedObject(::onc::network_config::kSavedIPConfig
,
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
,
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
,
567 void ShillToONCTranslator::TranslateIPConfig() {
568 CopyPropertiesAccordingToSignature();
569 std::string shill_ip_method
;
570 shill_dictionary_
->GetStringWithoutPathExpansion(shill::kMethodProperty
,
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
;
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
;
619 ShillToONCTranslator
nested_translator(dictionary
, onc_source_
,
620 *field_signature
->value_signature
,
622 scoped_ptr
<base::DictionaryValue
> nested_object
=
623 nested_translator
.CreateTranslatedONCObject();
624 if (nested_object
->empty())
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
,
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();
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();
657 const base::DictionaryValue
* shill_value
= NULL
;
658 if (!(*it
)->GetAsDictionary(&shill_value
))
660 ShillToONCTranslator
nested_translator(
661 *shill_value
, onc_source_
,
662 *field_signature
->value_signature
->onc_array_entry_signature
,
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())
669 result
->Append(nested_object
.release());
671 // If there are no entries in the list, there is no need to expose this field.
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
)
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
,
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
<< ": "
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
,
728 std::string onc_value
;
729 if (TranslateStringToONC(table
, shill_value
, &onc_value
)) {
730 onc_object_
->SetStringWithoutPathExpansion(onc_field_name
, onc_value
);
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_
);
740 shill_dictionary_
->GetStringWithoutPathExpansion(shill::kNameProperty
, &name
);
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
,
755 return translator
.CreateTranslatedONCObject();
759 } // namespace chromeos