onc_translator_shill_to_onc.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chromeos/network/onc/onc_translator.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/json/json_reader.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/json/json_writer.h"
120f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "base/logging.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h"
144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chromeos/network/network_state.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chromeos/network/network_util.h"
16a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "chromeos/network/onc/onc_signature.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chromeos/network/onc/onc_translation_tables.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chromeos/network/shill_property_util.h"
194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "components/onc/onc_constants.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/cros_system_api/dbus/service_constants.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace chromeos {
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace onc {
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Converts |str| to a base::Value of the given |type|. If the conversion fails,
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// returns NULL.
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)scoped_ptr<base::Value> ConvertStringToValue(const std::string& str,
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             base::Value::Type type) {
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::Value* value;
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (type == base::Value::TYPE_STRING) {
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    value = new base::StringValue(str);
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    value = base::JSONReader::Read(str);
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
38f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (value == NULL || value->GetType() != type) {
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete value;
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    value = NULL;
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return make_scoped_ptr(value);
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This class implements the translation of properties from the given
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |shill_dictionary| to a new ONC object of signature |onc_signature|. Using
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// recursive calls to CreateTranslatedONCObject of new instances, nested objects
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// are translated.
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ShillToONCTranslator {
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ShillToONCTranslator(const base::DictionaryValue& shill_dictionary,
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       const OncValueSignature& onc_signature)
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      : shill_dictionary_(&shill_dictionary),
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        onc_signature_(&onc_signature) {
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    field_translation_table_ = GetFieldTranslationTable(onc_signature);
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ShillToONCTranslator(const base::DictionaryValue& shill_dictionary,
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       const OncValueSignature& onc_signature,
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       const FieldTranslationEntry* field_translation_table)
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      : shill_dictionary_(&shill_dictionary),
62f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        onc_signature_(&onc_signature),
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        field_translation_table_(field_translation_table) {
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Translates the associated Shill dictionary and creates an ONC object of the
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // given signature.
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<base::DictionaryValue> CreateTranslatedONCObject();
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void TranslateEthernet();
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void TranslateOpenVPN();
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void TranslateIPsec();
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void TranslateVPN();
750f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  void TranslateWiFiWithState();
760f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  void TranslateCellularWithState();
770f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  void TranslateCellularDevice();
780f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  void TranslateNetworkWithState();
790f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  void TranslateIPConfig();
800f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
810f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // Creates an ONC object from |dictionary| according to the signature
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // associated to |onc_field_name| and adds it to |onc_object_| at
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // |onc_field_name|.
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void TranslateAndAddNestedObject(const std::string& onc_field_name,
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   const base::DictionaryValue& dictionary);
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Creates an ONC object from |shill_dictionary_| according to the signature
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // associated to |onc_field_name| and adds it to |onc_object_| at
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // |onc_field_name|.
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void TranslateAndAddNestedObject(const std::string& onc_field_name);
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Translates a list of nested objects and adds the list to |onc_object_| at
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // |onc_field_name|. If there are errors while parsing individual objects or
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // if the resulting list contains no entries, the result will not be added to
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // |onc_object_|.
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void TranslateAndAddListOfObjects(const std::string& onc_field_name,
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    const base::ListValue& list);
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Applies function CopyProperty to each field of |value_signature| and its
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // base signatures.
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void CopyPropertiesAccordingToSignature(
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const OncValueSignature* value_signature);
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Applies function CopyProperty to each field of |onc_signature_| and its
1054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // base signatures.
1064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  void CopyPropertiesAccordingToSignature();
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If |shill_property_name| is defined in |field_signature|, copies this
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // entry from |shill_dictionary_| to |onc_object_| if it exists.
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void CopyProperty(const OncFieldSignature* field_signature);
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If existent, translates the entry at |shill_property_name| in
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |shill_dictionary_| using |table|. It is an error if no matching table
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // entry is found. Writes the result as entry at |onc_field_name| in
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |onc_object_|.
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void TranslateWithTableAndSet(const std::string& shill_property_name,
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                const StringTranslationEntry table[],
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                const std::string& onc_field_name);
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const base::DictionaryValue* shill_dictionary_;
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const OncValueSignature* onc_signature_;
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const FieldTranslationEntry* field_translation_table_;
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<base::DictionaryValue> onc_object_;
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(ShillToONCTranslator);
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)scoped_ptr<base::DictionaryValue>
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ShillToONCTranslator::CreateTranslatedONCObject() {
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  onc_object_.reset(new base::DictionaryValue);
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (onc_signature_ == &kNetworkWithStateSignature) {
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TranslateNetworkWithState();
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (onc_signature_ == &kEthernetSignature) {
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TranslateEthernet();
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (onc_signature_ == &kVPNSignature) {
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TranslateVPN();
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (onc_signature_ == &kOpenVPNSignature) {
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TranslateOpenVPN();
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (onc_signature_ == &kIPsecSignature) {
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TranslateIPsec();
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (onc_signature_ == &kWiFiWithStateSignature) {
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TranslateWiFiWithState();
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (onc_signature_ == &kCellularWithStateSignature) {
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (field_translation_table_ == kCellularDeviceTable)
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      TranslateCellularDevice();
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      TranslateCellularWithState();
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (onc_signature_ == &kIPConfigSignature) {
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TranslateIPConfig();
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CopyPropertiesAccordingToSignature();
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return onc_object_.Pass();
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ShillToONCTranslator::TranslateEthernet() {
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string shill_network_type;
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  shill_dictionary_->GetStringWithoutPathExpansion(shill::kTypeProperty,
159a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                                   &shill_network_type);
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char* onc_auth = ::onc::ethernet::kAuthenticationNone;
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (shill_network_type == shill::kTypeEthernetEap)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    onc_auth = ::onc::ethernet::k8021X;
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  onc_object_->SetStringWithoutPathExpansion(::onc::ethernet::kAuthentication,
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             onc_auth);
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ShillToONCTranslator::TranslateOpenVPN() {
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (shill_dictionary_->HasKey(shill::kOpenVPNVerifyX509NameProperty))
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TranslateAndAddNestedObject(::onc::openvpn::kVerifyX509);
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Shill supports only one RemoteCertKU but ONC requires a list. If existing,
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // wraps the value into a list.
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string certKU;
17490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (shill_dictionary_->GetStringWithoutPathExpansion(
17590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          shill::kOpenVPNRemoteCertKUProperty, &certKU)) {
17690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    scoped_ptr<base::ListValue> certKUs(new base::ListValue);
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    certKUs->AppendString(certKU);
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    onc_object_->SetWithoutPathExpansion(::onc::openvpn::kRemoteCertKU,
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         certKUs.release());
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (const OncFieldSignature* field_signature = onc_signature_->fields;
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       field_signature->onc_field_name != NULL; ++field_signature) {
184bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    const std::string& onc_field_name = field_signature->onc_field_name;
185a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (onc_field_name == ::onc::vpn::kSaveCredentials ||
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        onc_field_name == ::onc::openvpn::kRemoteCertKU ||
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        onc_field_name == ::onc::openvpn::kServerCAPEMs) {
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CopyProperty(field_signature);
1890f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      continue;
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
192f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    std::string shill_property_name;
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::Value* shill_value = NULL;
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!field_translation_table_ ||
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        !GetShillPropertyName(field_signature->onc_field_name,
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              field_translation_table_,
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              &shill_property_name) ||
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        !shill_dictionary_->GetWithoutPathExpansion(shill_property_name,
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                    &shill_value)) {
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<base::Value> translated;
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string shill_str;
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (shill_value->GetAsString(&shill_str)) {
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Shill wants all Provider/VPN fields to be strings. Translates these
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // strings back to the correct ONC type.
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      translated = ConvertStringToValue(
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          shill_str,
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          field_signature->value_signature->onc_type);
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (translated.get() == NULL) {
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        LOG(ERROR) << "Shill property '" << shill_property_name
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   << "' with value " << *shill_value
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   << " couldn't be converted to base::Value::Type "
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   << field_signature->value_signature->onc_type;
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        onc_object_->SetWithoutPathExpansion(onc_field_name,
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             translated.release());
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "Shill property '" << shill_property_name
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 << "' has value " << *shill_value
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 << ", but expected a string";
2254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    }
2264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ShillToONCTranslator::TranslateIPsec() {
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CopyPropertiesAccordingToSignature();
231  if (shill_dictionary_->HasKey(shill::kL2tpIpsecXauthUserProperty))
232    TranslateAndAddNestedObject(::onc::ipsec::kXAUTH);
233}
234
235void ShillToONCTranslator::TranslateVPN() {
236  TranslateWithTableAndSet(
237      shill::kProviderTypeProperty, kVPNTypeTable, ::onc::vpn::kType);
238  CopyPropertiesAccordingToSignature();
239
240  std::string vpn_type;
241  if (onc_object_->GetStringWithoutPathExpansion(::onc::vpn::kType,
242                                                 &vpn_type)) {
243    if (vpn_type == ::onc::vpn::kTypeL2TP_IPsec) {
244      TranslateAndAddNestedObject(::onc::vpn::kIPsec);
245      TranslateAndAddNestedObject(::onc::vpn::kL2TP);
246    } else {
247      TranslateAndAddNestedObject(vpn_type);
248    }
249  }
250}
251
252void ShillToONCTranslator::TranslateWiFiWithState() {
253  TranslateWithTableAndSet(
254      shill::kSecurityProperty, kWiFiSecurityTable, ::onc::wifi::kSecurity);
255  std::string ssid = shill_property_util::GetSSIDFromProperties(
256      *shill_dictionary_, NULL /* ignore unknown encoding */);
257  if (!ssid.empty())
258    onc_object_->SetStringWithoutPathExpansion(::onc::wifi::kSSID, ssid);
259  CopyPropertiesAccordingToSignature();
260}
261
262void ShillToONCTranslator::TranslateCellularWithState() {
263  CopyPropertiesAccordingToSignature();
264  const base::DictionaryValue* dictionary = NULL;
265  if (shill_dictionary_->GetDictionaryWithoutPathExpansion(
266        shill::kServingOperatorProperty, &dictionary)) {
267    TranslateAndAddNestedObject(::onc::cellular::kServingOperator, *dictionary);
268  }
269  if (shill_dictionary_->GetDictionaryWithoutPathExpansion(
270        shill::kCellularApnProperty, &dictionary)) {
271    TranslateAndAddNestedObject(::onc::cellular::kAPN, *dictionary);
272  }
273  // Merge the Device dictionary with this one (Cellular) using the
274  // CellularDevice signature.
275  const base::DictionaryValue* device_dictionary = NULL;
276  if (!shill_dictionary_->GetDictionaryWithoutPathExpansion(
277          shill::kDeviceProperty, &device_dictionary)) {
278    return;
279  }
280  ShillToONCTranslator nested_translator(*device_dictionary,
281                                         kCellularWithStateSignature,
282                                         kCellularDeviceTable);
283  scoped_ptr<base::DictionaryValue> nested_object =
284      nested_translator.CreateTranslatedONCObject();
285  onc_object_->MergeDictionary(nested_object.get());
286}
287
288void ShillToONCTranslator::TranslateCellularDevice() {
289  CopyPropertiesAccordingToSignature();
290  const base::DictionaryValue* shill_sim_lock_status = NULL;
291  if (shill_dictionary_->GetDictionaryWithoutPathExpansion(
292          shill::kSIMLockStatusProperty, &shill_sim_lock_status)) {
293    TranslateAndAddNestedObject(::onc::cellular::kSIMLockStatus,
294                                *shill_sim_lock_status);
295  }
296  const base::ListValue* shill_apns = NULL;
297  if (shill_dictionary_->GetListWithoutPathExpansion(
298          shill::kCellularApnListProperty, &shill_apns)) {
299    TranslateAndAddListOfObjects(::onc::cellular::kAPNList, *shill_apns);
300  }
301  const base::ListValue* shill_found_networks = NULL;
302  if (shill_dictionary_->GetListWithoutPathExpansion(
303          shill::kFoundNetworksProperty, &shill_found_networks)) {
304    TranslateAndAddListOfObjects(::onc::cellular::kFoundNetworks,
305                                 *shill_found_networks);
306  }
307}
308
309void ShillToONCTranslator::TranslateNetworkWithState() {
310  CopyPropertiesAccordingToSignature();
311
312  std::string shill_network_type;
313  shill_dictionary_->GetStringWithoutPathExpansion(shill::kTypeProperty,
314                                                   &shill_network_type);
315  std::string onc_network_type = ::onc::network_type::kEthernet;
316  if (shill_network_type != shill::kTypeEthernet &&
317      shill_network_type != shill::kTypeEthernetEap) {
318    TranslateStringToONC(
319        kNetworkTypeTable, shill_network_type, &onc_network_type);
320  }
321  // Translate nested Cellular, WiFi, etc. properties.
322  if (!onc_network_type.empty()) {
323    onc_object_->SetStringWithoutPathExpansion(::onc::network_config::kType,
324                                               onc_network_type);
325    TranslateAndAddNestedObject(onc_network_type);
326  }
327
328  // Since Name is a read only field in Shill unless it's a VPN, it is copied
329  // here, but not when going the other direction (if it's not a VPN).
330  std::string name;
331  shill_dictionary_->GetStringWithoutPathExpansion(shill::kNameProperty,
332                                                   &name);
333  onc_object_->SetStringWithoutPathExpansion(::onc::network_config::kName,
334                                             name);
335
336  // Limit ONC state to "NotConnected", "Connected", or "Connecting".
337  std::string state;
338  if (shill_dictionary_->GetStringWithoutPathExpansion(shill::kStateProperty,
339                                                       &state)) {
340    std::string onc_state = ::onc::connection_state::kNotConnected;
341    if (NetworkState::StateIsConnected(state)) {
342      onc_state = ::onc::connection_state::kConnected;
343    } else if (NetworkState::StateIsConnecting(state)) {
344      onc_state = ::onc::connection_state::kConnecting;
345    }
346    onc_object_->SetStringWithoutPathExpansion(
347        ::onc::network_config::kConnectionState, onc_state);
348  }
349
350  // Use a human-readable aa:bb format for any hardware MAC address. Note:
351  // this property is provided by the caller but is not part of the Shill
352  // Service properties (it is copied from the Device properties).
353  std::string address;
354  if (shill_dictionary_->GetStringWithoutPathExpansion(shill::kAddressProperty,
355                                                       &address)) {
356    onc_object_->SetStringWithoutPathExpansion(
357        ::onc::network_config::kMacAddress,
358        network_util::FormattedMacAddress(address));
359  }
360
361  // Shill's Service has an IPConfig property (note the singular), not an
362  // IPConfigs property. However, we require the caller of the translation to
363  // patch the Shill dictionary before passing it to the translator.
364  const base::ListValue* shill_ipconfigs = NULL;
365  if (shill_dictionary_->GetListWithoutPathExpansion(shill::kIPConfigsProperty,
366                                                     &shill_ipconfigs)) {
367    TranslateAndAddListOfObjects(::onc::network_config::kIPConfigs,
368                                 *shill_ipconfigs);
369  }
370}
371
372void ShillToONCTranslator::TranslateIPConfig() {
373  CopyPropertiesAccordingToSignature();
374  std::string shill_ip_method;
375  shill_dictionary_->GetStringWithoutPathExpansion(shill::kMethodProperty,
376                                                   &shill_ip_method);
377  std::string type;
378  if (shill_ip_method == shill::kTypeIPv4 ||
379      shill_ip_method == shill::kTypeDHCP) {
380    type = ::onc::ipconfig::kIPv4;
381  } else if (shill_ip_method == shill::kTypeIPv6 ||
382             shill_ip_method == shill::kTypeDHCP6) {
383    type = ::onc::ipconfig::kIPv6;
384  } else {
385    return;  // Ignore unhandled IPConfig types, e.g. bootp, zeroconf, ppp
386  }
387
388  onc_object_->SetStringWithoutPathExpansion(::onc::ipconfig::kType, type);
389}
390
391void ShillToONCTranslator::TranslateAndAddNestedObject(
392    const std::string& onc_field_name) {
393  TranslateAndAddNestedObject(onc_field_name, *shill_dictionary_);
394}
395
396void ShillToONCTranslator::TranslateAndAddNestedObject(
397    const std::string& onc_field_name,
398    const base::DictionaryValue& dictionary) {
399  const OncFieldSignature* field_signature =
400      GetFieldSignature(*onc_signature_, onc_field_name);
401  DCHECK(field_signature) << "Unable to find signature for field "
402                          << onc_field_name << ".";
403  ShillToONCTranslator nested_translator(dictionary,
404                                         *field_signature->value_signature);
405  scoped_ptr<base::DictionaryValue> nested_object =
406      nested_translator.CreateTranslatedONCObject();
407  if (nested_object->empty())
408    return;
409  onc_object_->SetWithoutPathExpansion(onc_field_name, nested_object.release());
410}
411
412void ShillToONCTranslator::TranslateAndAddListOfObjects(
413    const std::string& onc_field_name,
414    const base::ListValue& list) {
415  const OncFieldSignature* field_signature =
416      GetFieldSignature(*onc_signature_, onc_field_name);
417  if (field_signature->value_signature->onc_type != base::Value::TYPE_LIST) {
418    LOG(ERROR) << "ONC Field name: '" << onc_field_name << "' has type '"
419               << field_signature->value_signature->onc_type
420               << "', expected: base::Value::TYPE_LIST.";
421    return;
422  }
423  DCHECK(field_signature->value_signature->onc_array_entry_signature);
424  scoped_ptr<base::ListValue> result(new base::ListValue());
425  for (base::ListValue::const_iterator it = list.begin();
426       it != list.end(); ++it) {
427    const base::DictionaryValue* shill_value = NULL;
428    if (!(*it)->GetAsDictionary(&shill_value))
429      continue;
430    ShillToONCTranslator nested_translator(
431        *shill_value,
432        *field_signature->value_signature->onc_array_entry_signature);
433    scoped_ptr<base::DictionaryValue> nested_object =
434        nested_translator.CreateTranslatedONCObject();
435    // If the nested object couldn't be parsed, simply omit it.
436    if (nested_object->empty())
437      continue;
438    result->Append(nested_object.release());
439  }
440  // If there are no entries in the list, there is no need to expose this field.
441  if (result->empty())
442    return;
443  onc_object_->SetWithoutPathExpansion(onc_field_name, result.release());
444}
445
446void ShillToONCTranslator::CopyPropertiesAccordingToSignature() {
447  CopyPropertiesAccordingToSignature(onc_signature_);
448}
449
450void ShillToONCTranslator::CopyPropertiesAccordingToSignature(
451    const OncValueSignature* value_signature) {
452  if (value_signature->base_signature)
453    CopyPropertiesAccordingToSignature(value_signature->base_signature);
454  for (const OncFieldSignature* field_signature = value_signature->fields;
455       field_signature->onc_field_name != NULL; ++field_signature) {
456    CopyProperty(field_signature);
457  }
458}
459
460void ShillToONCTranslator::CopyProperty(
461    const OncFieldSignature* field_signature) {
462  std::string shill_property_name;
463  const base::Value* shill_value = NULL;
464  if (!field_translation_table_ ||
465      !GetShillPropertyName(field_signature->onc_field_name,
466                            field_translation_table_,
467                            &shill_property_name) ||
468      !shill_dictionary_->GetWithoutPathExpansion(shill_property_name,
469                                                  &shill_value)) {
470    return;
471  }
472
473  if (shill_value->GetType() != field_signature->value_signature->onc_type) {
474    LOG(ERROR) << "Shill property '" << shill_property_name
475               << "' with value " << *shill_value
476               << " has base::Value::Type " << shill_value->GetType()
477               << " but ONC field '" << field_signature->onc_field_name
478               << "' requires type "
479               << field_signature->value_signature->onc_type << ".";
480    return;
481  }
482
483 onc_object_->SetWithoutPathExpansion(field_signature->onc_field_name,
484                                      shill_value->DeepCopy());
485}
486
487void ShillToONCTranslator::TranslateWithTableAndSet(
488    const std::string& shill_property_name,
489    const StringTranslationEntry table[],
490    const std::string& onc_field_name) {
491  std::string shill_value;
492  if (!shill_dictionary_->GetStringWithoutPathExpansion(shill_property_name,
493                                                        &shill_value)) {
494    return;
495  }
496  std::string onc_value;
497  if (TranslateStringToONC(table, shill_value, &onc_value)) {
498    onc_object_->SetStringWithoutPathExpansion(onc_field_name, onc_value);
499    return;
500  }
501  LOG(ERROR) << "Shill property '" << shill_property_name << "' with value "
502             << shill_value << " couldn't be translated to ONC";
503}
504
505}  // namespace
506
507scoped_ptr<base::DictionaryValue> TranslateShillServiceToONCPart(
508    const base::DictionaryValue& shill_dictionary,
509    const OncValueSignature* onc_signature) {
510  CHECK(onc_signature != NULL);
511
512  ShillToONCTranslator translator(shill_dictionary, *onc_signature);
513  return translator.CreateTranslatedONCObject();
514}
515
516}  // namespace onc
517}  // namespace chromeos
518