Add default implementations for AppWindowRegistry::Observer notifications.
[chromium-blink-merge.git] / chromeos / network / onc / onc_translator_shill_to_onc.cc
blob7716fbf2954d2a49d065b51ce40f0b5ff11d063a
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/values.h"
14 #include "chromeos/network/network_state.h"
15 #include "chromeos/network/onc/onc_signature.h"
16 #include "chromeos/network/onc/onc_translation_tables.h"
17 #include "chromeos/network/shill_property_util.h"
18 #include "components/onc/onc_constants.h"
19 #include "third_party/cros_system_api/dbus/service_constants.h"
21 namespace chromeos {
22 namespace onc {
24 namespace {
26 // Converts |str| to a base::Value of the given |type|. If the conversion fails,
27 // returns NULL.
28 scoped_ptr<base::Value> ConvertStringToValue(const std::string& str,
29 base::Value::Type type) {
30 base::Value* value;
31 if (type == base::Value::TYPE_STRING) {
32 value = base::Value::CreateStringValue(str);
33 } else {
34 value = base::JSONReader::Read(str);
37 if (value == NULL || value->GetType() != type) {
38 delete value;
39 value = NULL;
41 return make_scoped_ptr(value);
44 // This class implements the translation of properties from the given
45 // |shill_dictionary| to a new ONC object of signature |onc_signature|. Using
46 // recursive calls to CreateTranslatedONCObject of new instances, nested objects
47 // are translated.
48 class ShillToONCTranslator {
49 public:
50 ShillToONCTranslator(const base::DictionaryValue& shill_dictionary,
51 const OncValueSignature& onc_signature)
52 : shill_dictionary_(&shill_dictionary),
53 onc_signature_(&onc_signature) {
54 field_translation_table_ = GetFieldTranslationTable(onc_signature);
57 // Translates the associated Shill dictionary and creates an ONC object of the
58 // given signature.
59 scoped_ptr<base::DictionaryValue> CreateTranslatedONCObject();
61 private:
62 void TranslateEthernet();
63 void TranslateOpenVPN();
64 void TranslateIPsec();
65 void TranslateVPN();
66 void TranslateWiFiWithState();
67 void TranslateCellularWithState();
68 void TranslateNetworkWithState();
69 void TranslateIPConfig();
71 // Creates an ONC object from |dictionary| according to the signature
72 // associated to |onc_field_name| and adds it to |onc_object_| at
73 // |onc_field_name|.
74 void TranslateAndAddNestedObject(const std::string& onc_field_name,
75 const base::DictionaryValue& dictionary);
77 // Creates an ONC object from |shill_dictionary_| according to the signature
78 // associated to |onc_field_name| and adds it to |onc_object_| at
79 // |onc_field_name|.
80 void TranslateAndAddNestedObject(const std::string& onc_field_name);
82 // Translates a list of nested objects and adds the list to |onc_object_| at
83 // |onc_field_name|. If there are errors while parsing individual objects or
84 // if the resulting list contains no entries, the result will not be added to
85 // |onc_object_|.
86 void TranslateAndAddListOfObjects(const std::string& onc_field_name,
87 const base::ListValue& list);
89 // Applies function CopyProperty to each field of |value_signature| and its
90 // base signatures.
91 void CopyPropertiesAccordingToSignature(
92 const OncValueSignature* value_signature);
94 // Applies function CopyProperty to each field of |onc_signature_| and its
95 // base signatures.
96 void CopyPropertiesAccordingToSignature();
98 // If |shill_property_name| is defined in |field_signature|, copies this
99 // entry from |shill_dictionary_| to |onc_object_| if it exists.
100 void CopyProperty(const OncFieldSignature* field_signature);
102 // If existent, translates the entry at |shill_property_name| in
103 // |shill_dictionary_| using |table|. It is an error if no matching table
104 // entry is found. Writes the result as entry at |onc_field_name| in
105 // |onc_object_|.
106 void TranslateWithTableAndSet(const std::string& shill_property_name,
107 const StringTranslationEntry table[],
108 const std::string& onc_field_name);
110 const base::DictionaryValue* shill_dictionary_;
111 const OncValueSignature* onc_signature_;
112 const FieldTranslationEntry* field_translation_table_;
113 scoped_ptr<base::DictionaryValue> onc_object_;
115 DISALLOW_COPY_AND_ASSIGN(ShillToONCTranslator);
118 scoped_ptr<base::DictionaryValue>
119 ShillToONCTranslator::CreateTranslatedONCObject() {
120 onc_object_.reset(new base::DictionaryValue);
121 if (onc_signature_ == &kNetworkWithStateSignature) {
122 TranslateNetworkWithState();
123 } else if (onc_signature_ == &kEthernetSignature) {
124 TranslateEthernet();
125 } else if (onc_signature_ == &kVPNSignature) {
126 TranslateVPN();
127 } else if (onc_signature_ == &kOpenVPNSignature) {
128 TranslateOpenVPN();
129 } else if (onc_signature_ == &kIPsecSignature) {
130 TranslateIPsec();
131 } else if (onc_signature_ == &kWiFiWithStateSignature) {
132 TranslateWiFiWithState();
133 } else if (onc_signature_ == &kCellularWithStateSignature) {
134 TranslateCellularWithState();
135 } else if (onc_signature_ == &kIPConfigSignature) {
136 TranslateIPConfig();
137 } else {
138 CopyPropertiesAccordingToSignature();
140 return onc_object_.Pass();
143 void ShillToONCTranslator::TranslateEthernet() {
144 std::string shill_network_type;
145 shill_dictionary_->GetStringWithoutPathExpansion(shill::kTypeProperty,
146 &shill_network_type);
147 const char* onc_auth = ::onc::ethernet::kNone;
148 if (shill_network_type == shill::kTypeEthernetEap)
149 onc_auth = ::onc::ethernet::k8021X;
150 onc_object_->SetStringWithoutPathExpansion(::onc::ethernet::kAuthentication,
151 onc_auth);
154 void ShillToONCTranslator::TranslateOpenVPN() {
155 if (shill_dictionary_->HasKey(shill::kOpenVPNVerifyX509NameProperty))
156 TranslateAndAddNestedObject(::onc::openvpn::kVerifyX509);
158 // Shill supports only one RemoteCertKU but ONC requires a list. If existing,
159 // wraps the value into a list.
160 std::string certKU;
161 if (shill_dictionary_->GetStringWithoutPathExpansion(
162 shill::kOpenVPNRemoteCertKUProperty, &certKU)) {
163 scoped_ptr<base::ListValue> certKUs(new base::ListValue);
164 certKUs->AppendString(certKU);
165 onc_object_->SetWithoutPathExpansion(::onc::openvpn::kRemoteCertKU,
166 certKUs.release());
169 for (const OncFieldSignature* field_signature = onc_signature_->fields;
170 field_signature->onc_field_name != NULL; ++field_signature) {
171 const std::string& onc_field_name = field_signature->onc_field_name;
172 if (onc_field_name == ::onc::vpn::kSaveCredentials ||
173 onc_field_name == ::onc::openvpn::kRemoteCertKU ||
174 onc_field_name == ::onc::openvpn::kServerCAPEMs) {
175 CopyProperty(field_signature);
176 continue;
179 std::string shill_property_name;
180 const base::Value* shill_value = NULL;
181 if (!field_translation_table_ ||
182 !GetShillPropertyName(field_signature->onc_field_name,
183 field_translation_table_,
184 &shill_property_name) ||
185 !shill_dictionary_->GetWithoutPathExpansion(shill_property_name,
186 &shill_value)) {
187 continue;
190 scoped_ptr<base::Value> translated;
191 std::string shill_str;
192 if (shill_value->GetAsString(&shill_str)) {
193 // Shill wants all Provider/VPN fields to be strings. Translates these
194 // strings back to the correct ONC type.
195 translated = ConvertStringToValue(
196 shill_str,
197 field_signature->value_signature->onc_type);
199 if (translated.get() == NULL) {
200 LOG(ERROR) << "Shill property '" << shill_property_name
201 << "' with value " << *shill_value
202 << " couldn't be converted to base::Value::Type "
203 << field_signature->value_signature->onc_type;
204 } else {
205 onc_object_->SetWithoutPathExpansion(onc_field_name,
206 translated.release());
208 } else {
209 LOG(ERROR) << "Shill property '" << shill_property_name
210 << "' has value " << *shill_value
211 << ", but expected a string";
216 void ShillToONCTranslator::TranslateIPsec() {
217 CopyPropertiesAccordingToSignature();
218 if (shill_dictionary_->HasKey(shill::kL2tpIpsecXauthUserProperty))
219 TranslateAndAddNestedObject(::onc::ipsec::kXAUTH);
222 void ShillToONCTranslator::TranslateVPN() {
223 TranslateWithTableAndSet(
224 shill::kProviderTypeProperty, kVPNTypeTable, ::onc::vpn::kType);
225 CopyPropertiesAccordingToSignature();
227 std::string vpn_type;
228 if (onc_object_->GetStringWithoutPathExpansion(::onc::vpn::kType,
229 &vpn_type)) {
230 if (vpn_type == ::onc::vpn::kTypeL2TP_IPsec) {
231 TranslateAndAddNestedObject(::onc::vpn::kIPsec);
232 TranslateAndAddNestedObject(::onc::vpn::kL2TP);
233 } else {
234 TranslateAndAddNestedObject(vpn_type);
239 void ShillToONCTranslator::TranslateWiFiWithState() {
240 TranslateWithTableAndSet(
241 shill::kSecurityProperty, kWiFiSecurityTable, ::onc::wifi::kSecurity);
242 std::string ssid = shill_property_util::GetSSIDFromProperties(
243 *shill_dictionary_, NULL /* ignore unknown encoding */);
244 if (!ssid.empty())
245 onc_object_->SetStringWithoutPathExpansion(::onc::wifi::kSSID, ssid);
246 CopyPropertiesAccordingToSignature();
249 void ShillToONCTranslator::TranslateCellularWithState() {
250 CopyPropertiesAccordingToSignature();
251 const base::DictionaryValue* dictionary = NULL;
252 if (shill_dictionary_->GetDictionaryWithoutPathExpansion(
253 shill::kServingOperatorProperty, &dictionary)) {
254 TranslateAndAddNestedObject(::onc::cellular::kServingOperator, *dictionary);
256 if (shill_dictionary_->GetDictionaryWithoutPathExpansion(
257 shill::kCellularApnProperty, &dictionary)) {
258 TranslateAndAddNestedObject(::onc::cellular::kAPN, *dictionary);
260 const base::ListValue* shill_apns = NULL;
261 if (shill_dictionary_->GetListWithoutPathExpansion(
262 shill::kCellularApnListProperty, &shill_apns)) {
263 TranslateAndAddListOfObjects(::onc::cellular::kAPNList, *shill_apns);
267 void ShillToONCTranslator::TranslateNetworkWithState() {
268 CopyPropertiesAccordingToSignature();
270 std::string shill_network_type;
271 shill_dictionary_->GetStringWithoutPathExpansion(shill::kTypeProperty,
272 &shill_network_type);
273 std::string onc_network_type = ::onc::network_type::kEthernet;
274 if (shill_network_type != shill::kTypeEthernet &&
275 shill_network_type != shill::kTypeEthernetEap) {
276 TranslateStringToONC(
277 kNetworkTypeTable, shill_network_type, &onc_network_type);
279 if (!onc_network_type.empty()) {
280 onc_object_->SetStringWithoutPathExpansion(::onc::network_config::kType,
281 onc_network_type);
282 TranslateAndAddNestedObject(onc_network_type);
285 // Since Name is a read only field in Shill unless it's a VPN, it is copied
286 // here, but not when going the other direction (if it's not a VPN).
287 std::string name;
288 shill_dictionary_->GetStringWithoutPathExpansion(shill::kNameProperty,
289 &name);
290 onc_object_->SetStringWithoutPathExpansion(::onc::network_config::kName,
291 name);
293 std::string state;
294 if (shill_dictionary_->GetStringWithoutPathExpansion(shill::kStateProperty,
295 &state)) {
296 std::string onc_state = ::onc::connection_state::kNotConnected;
297 if (NetworkState::StateIsConnected(state)) {
298 onc_state = ::onc::connection_state::kConnected;
299 } else if (NetworkState::StateIsConnecting(state)) {
300 onc_state = ::onc::connection_state::kConnecting;
302 onc_object_->SetStringWithoutPathExpansion(
303 ::onc::network_config::kConnectionState, onc_state);
306 // Shill's Service has an IPConfig property (note the singular, and not a
307 // IPConfigs property). However, we require the caller of the translation to
308 // patch the Shill dictionary before passing it to the translator.
309 const base::ListValue* shill_ipconfigs = NULL;
310 if (shill_dictionary_->GetListWithoutPathExpansion(shill::kIPConfigsProperty,
311 &shill_ipconfigs)) {
312 TranslateAndAddListOfObjects(::onc::network_config::kIPConfigs,
313 *shill_ipconfigs);
317 void ShillToONCTranslator::TranslateIPConfig() {
318 CopyPropertiesAccordingToSignature();
319 std::string shill_ip_method;
320 shill_dictionary_->GetStringWithoutPathExpansion(shill::kMethodProperty,
321 &shill_ip_method);
322 if (shill_ip_method != shill::kTypeIPv4 &&
323 shill_ip_method != shill::kTypeIPv6) {
324 LOG(ERROR) << "Unhandled IPConfig Method value " << shill_ip_method;
325 return;
328 std::string type = ::onc::ipconfig::kIPv4;
329 if (shill_ip_method == shill::kTypeIPv6)
330 type = ::onc::ipconfig::kIPv6;
331 onc_object_->SetStringWithoutPathExpansion(::onc::ipconfig::kType, type);
334 void ShillToONCTranslator::TranslateAndAddNestedObject(
335 const std::string& onc_field_name) {
336 TranslateAndAddNestedObject(onc_field_name, *shill_dictionary_);
339 void ShillToONCTranslator::TranslateAndAddNestedObject(
340 const std::string& onc_field_name,
341 const base::DictionaryValue& dictionary) {
342 const OncFieldSignature* field_signature =
343 GetFieldSignature(*onc_signature_, onc_field_name);
344 DCHECK(field_signature) << "Unable to find signature for field "
345 << onc_field_name << ".";
346 ShillToONCTranslator nested_translator(dictionary,
347 *field_signature->value_signature);
348 scoped_ptr<base::DictionaryValue> nested_object =
349 nested_translator.CreateTranslatedONCObject();
350 if (nested_object->empty())
351 return;
352 onc_object_->SetWithoutPathExpansion(onc_field_name, nested_object.release());
355 void ShillToONCTranslator::TranslateAndAddListOfObjects(
356 const std::string& onc_field_name,
357 const base::ListValue& list) {
358 const OncFieldSignature* field_signature =
359 GetFieldSignature(*onc_signature_, onc_field_name);
360 if (field_signature->value_signature->onc_type != base::Value::TYPE_LIST) {
361 LOG(ERROR) << "ONC Field name: '" << onc_field_name << "' has type '"
362 << field_signature->value_signature->onc_type
363 << "', expected: base::Value::TYPE_LIST.";
364 return;
366 DCHECK(field_signature->value_signature->onc_array_entry_signature);
367 scoped_ptr<base::ListValue> result(new base::ListValue());
368 for (base::ListValue::const_iterator it = list.begin();
369 it != list.end(); ++it) {
370 const base::DictionaryValue* shill_value = NULL;
371 if (!(*it)->GetAsDictionary(&shill_value))
372 continue;
373 ShillToONCTranslator nested_translator(
374 *shill_value,
375 *field_signature->value_signature->onc_array_entry_signature);
376 scoped_ptr<base::DictionaryValue> nested_object =
377 nested_translator.CreateTranslatedONCObject();
378 // If the nested object couldn't be parsed, simply omit it.
379 if (nested_object->empty())
380 continue;
381 result->Append(nested_object.release());
383 // If there are no entries in the list, there is no need to expose this field.
384 if (result->empty())
385 return;
386 onc_object_->SetWithoutPathExpansion(onc_field_name, result.release());
389 void ShillToONCTranslator::CopyPropertiesAccordingToSignature() {
390 CopyPropertiesAccordingToSignature(onc_signature_);
393 void ShillToONCTranslator::CopyPropertiesAccordingToSignature(
394 const OncValueSignature* value_signature) {
395 if (value_signature->base_signature)
396 CopyPropertiesAccordingToSignature(value_signature->base_signature);
397 for (const OncFieldSignature* field_signature = value_signature->fields;
398 field_signature->onc_field_name != NULL; ++field_signature) {
399 CopyProperty(field_signature);
403 void ShillToONCTranslator::CopyProperty(
404 const OncFieldSignature* field_signature) {
405 std::string shill_property_name;
406 const base::Value* shill_value = NULL;
407 if (!field_translation_table_ ||
408 !GetShillPropertyName(field_signature->onc_field_name,
409 field_translation_table_,
410 &shill_property_name) ||
411 !shill_dictionary_->GetWithoutPathExpansion(shill_property_name,
412 &shill_value)) {
413 return;
416 if (shill_value->GetType() != field_signature->value_signature->onc_type) {
417 LOG(ERROR) << "Shill property '" << shill_property_name
418 << "' with value " << *shill_value
419 << " has base::Value::Type " << shill_value->GetType()
420 << " but ONC field '" << field_signature->onc_field_name
421 << "' requires type "
422 << field_signature->value_signature->onc_type << ".";
423 return;
426 onc_object_->SetWithoutPathExpansion(field_signature->onc_field_name,
427 shill_value->DeepCopy());
430 void ShillToONCTranslator::TranslateWithTableAndSet(
431 const std::string& shill_property_name,
432 const StringTranslationEntry table[],
433 const std::string& onc_field_name) {
434 std::string shill_value;
435 if (!shill_dictionary_->GetStringWithoutPathExpansion(shill_property_name,
436 &shill_value)) {
437 return;
439 std::string onc_value;
440 if (TranslateStringToONC(table, shill_value, &onc_value)) {
441 onc_object_->SetStringWithoutPathExpansion(onc_field_name, onc_value);
442 return;
444 LOG(ERROR) << "Shill property '" << shill_property_name << "' with value "
445 << shill_value << " couldn't be translated to ONC";
448 } // namespace
450 scoped_ptr<base::DictionaryValue> TranslateShillServiceToONCPart(
451 const base::DictionaryValue& shill_dictionary,
452 const OncValueSignature* onc_signature) {
453 CHECK(onc_signature != NULL);
455 ShillToONCTranslator translator(shill_dictionary, *onc_signature);
456 return translator.CreateTranslatedONCObject();
459 } // namespace onc
460 } // namespace chromeos