Home | History | Annotate | Download | only in onc
      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.
      4 
      5 #include "chromeos/network/onc/onc_translation_tables.h"
      6 
      7 #include <cstddef>
      8 
      9 #include "base/logging.h"
     10 #include "components/onc/onc_constants.h"
     11 #include "third_party/cros_system_api/dbus/service_constants.h"
     12 
     13 namespace chromeos {
     14 namespace onc {
     15 
     16 // CertificatePattern is converted with function CreateUIData(...) to UIData
     17 // stored in Shill.
     18 //
     19 // Proxy settings are converted to Shill by function
     20 // ConvertOncProxySettingsToProxyConfig(...).
     21 
     22 namespace {
     23 
     24 const FieldTranslationEntry eap_fields[] = {
     25     { ::onc::eap::kAnonymousIdentity, shill::kEapAnonymousIdentityProperty},
     26     { ::onc::eap::kIdentity, shill::kEapIdentityProperty},
     27     // This field is converted during translation, see onc_translator_*.
     28     // { ::onc::eap::kInner, shill::kEapPhase2AuthProperty },
     29 
     30     // This field is converted during translation, see onc_translator_*.
     31     // { ::onc::eap::kOuter, shill::kEapMethodProperty },
     32     { ::onc::eap::kPassword, shill::kEapPasswordProperty},
     33     { ::onc::eap::kSaveCredentials, shill::kSaveCredentialsProperty},
     34     { ::onc::eap::kServerCAPEMs, shill::kEapCaCertPemProperty},
     35     { ::onc::eap::kUseSystemCAs, shill::kEapUseSystemCasProperty},
     36     {NULL}};
     37 
     38 const FieldTranslationEntry ipsec_fields[] = {
     39     // This field is converted during translation, see onc_translator_*.
     40     // { ::onc::ipsec::kAuthenticationType, shill::kL2tpIpsecAuthenticationType
     41     // },
     42     { ::onc::ipsec::kGroup, shill::kL2tpIpsecTunnelGroupProperty},
     43     // Ignored by Shill, not necessary to synchronize.
     44     // { ::onc::ipsec::kIKEVersion, shill::kL2tpIpsecIkeVersion },
     45     { ::onc::ipsec::kPSK, shill::kL2tpIpsecPskProperty},
     46     // This field is converted during translation, see onc_translator_*.
     47     // { ::onc::vpn::kSaveCredentials, shill::kSaveCredentialsProperty},
     48     { ::onc::ipsec::kServerCAPEMs, shill::kL2tpIpsecCaCertPemProperty},
     49     {NULL}};
     50 
     51 const FieldTranslationEntry xauth_fields[] = {
     52     { ::onc::vpn::kPassword, shill::kL2tpIpsecXauthPasswordProperty},
     53     { ::onc::vpn::kUsername, shill::kL2tpIpsecXauthUserProperty},
     54     {NULL}};
     55 
     56 const FieldTranslationEntry l2tp_fields[] = {
     57     { ::onc::vpn::kPassword, shill::kL2tpIpsecPasswordProperty},
     58     // We don't synchronize l2tp's SaveCredentials field for now, as Shill
     59     // doesn't support separate settings for ipsec and l2tp.
     60     // { ::onc::vpn::kSaveCredentials, &kBoolSignature },
     61     { ::onc::vpn::kUsername, shill::kL2tpIpsecUserProperty}, {NULL}};
     62 
     63 const FieldTranslationEntry openvpn_fields[] = {
     64     { ::onc::openvpn::kAuth, shill::kOpenVPNAuthProperty},
     65     { ::onc::openvpn::kAuthNoCache, shill::kOpenVPNAuthNoCacheProperty},
     66     { ::onc::openvpn::kAuthRetry, shill::kOpenVPNAuthRetryProperty},
     67     { ::onc::openvpn::kCipher, shill::kOpenVPNCipherProperty},
     68     { ::onc::openvpn::kCompLZO, shill::kOpenVPNCompLZOProperty},
     69     { ::onc::openvpn::kCompNoAdapt, shill::kOpenVPNCompNoAdaptProperty},
     70     { ::onc::openvpn::kIgnoreDefaultRoute,
     71       shill::kOpenVPNIgnoreDefaultRouteProperty},
     72     { ::onc::openvpn::kKeyDirection, shill::kOpenVPNKeyDirectionProperty},
     73     { ::onc::openvpn::kNsCertType, shill::kOpenVPNNsCertTypeProperty},
     74     { ::onc::vpn::kPassword, shill::kOpenVPNPasswordProperty},
     75     { ::onc::openvpn::kPort, shill::kOpenVPNPortProperty},
     76     { ::onc::openvpn::kProto, shill::kOpenVPNProtoProperty},
     77     { ::onc::openvpn::kPushPeerInfo, shill::kOpenVPNPushPeerInfoProperty},
     78     { ::onc::openvpn::kRemoteCertEKU, shill::kOpenVPNRemoteCertEKUProperty},
     79     // This field is converted during translation, see onc_translator_*.
     80     // { ::onc::openvpn::kRemoteCertKU, shill::kOpenVPNRemoteCertKUProperty },
     81     { ::onc::openvpn::kRemoteCertTLS, shill::kOpenVPNRemoteCertTLSProperty},
     82     { ::onc::openvpn::kRenegSec, shill::kOpenVPNRenegSecProperty},
     83     // This field is converted during translation, see onc_translator_*.
     84     // { ::onc::vpn::kSaveCredentials, shill::kSaveCredentialsProperty},
     85     { ::onc::openvpn::kServerCAPEMs, shill::kOpenVPNCaCertPemProperty},
     86     { ::onc::openvpn::kServerPollTimeout,
     87       shill::kOpenVPNServerPollTimeoutProperty},
     88     { ::onc::openvpn::kShaper, shill::kOpenVPNShaperProperty},
     89     { ::onc::openvpn::kStaticChallenge, shill::kOpenVPNStaticChallengeProperty},
     90     { ::onc::openvpn::kTLSAuthContents, shill::kOpenVPNTLSAuthContentsProperty},
     91     { ::onc::openvpn::kTLSRemote, shill::kOpenVPNTLSRemoteProperty},
     92     { ::onc::vpn::kUsername, shill::kOpenVPNUserProperty},
     93     { ::onc::openvpn::kVerifyHash, shill::kOpenVPNVerifyHashProperty},
     94     {NULL}};
     95 
     96 const FieldTranslationEntry verify_x509_fields[] = {
     97     { ::onc::verify_x509::kName, shill::kOpenVPNVerifyX509NameProperty},
     98     { ::onc::verify_x509::kType, shill::kOpenVPNVerifyX509TypeProperty},
     99     {NULL}};
    100 
    101 const FieldTranslationEntry vpn_fields[] = {
    102     { ::onc::vpn::kAutoConnect, shill::kAutoConnectProperty},
    103     // These fields are converted during translation, see onc_translator_*.
    104     // { ::onc::vpn::kHost, shill::kProviderHostProperty},
    105     // { ::onc::vpn::kType, shill::kProviderTypeProperty },
    106     {NULL}};
    107 
    108 const FieldTranslationEntry wifi_fields[] = {
    109     { ::onc::wifi::kAutoConnect, shill::kAutoConnectProperty},
    110     { ::onc::wifi::kBSSID, shill::kWifiBSsid},
    111     // This dictionary is converted during translation, see onc_translator_*.
    112     // { ::onc::wifi::kEAP, shill::kEap*},
    113     { ::onc::wifi::kFrequency, shill::kWifiFrequency},
    114     { ::onc::wifi::kFrequencyList, shill::kWifiFrequencyListProperty},
    115     { ::onc::wifi::kHiddenSSID, shill::kWifiHiddenSsid},
    116     { ::onc::wifi::kPassphrase, shill::kPassphraseProperty},
    117     // This field is converted during translation, see onc_translator_*.
    118     // { ::onc::wifi::kSSID, shill::kWifiHexSsid},
    119     // This field is converted during translation, see onc_translator_*.
    120     // { ::onc::wifi::kSecurity, shill::kSecurityProperty },
    121     { ::onc::wifi::kSignalStrength, shill::kSignalStrengthProperty},
    122     {NULL}};
    123 
    124 const FieldTranslationEntry wimax_fields[] = {
    125     { ::onc::wimax::kAutoConnect, shill::kAutoConnectProperty},
    126     // This dictionary is converted during translation, see onc_translator_*.
    127     // { ::onc::wimax::kEAP, shill::kEap*},
    128     { ::onc::wimax::kSignalStrength, shill::kSignalStrengthProperty},
    129     {NULL}};
    130 
    131 const FieldTranslationEntry cellular_apn_fields[] = {
    132     { ::onc::cellular_apn::kAccessPointName, shill::kApnProperty},
    133     { ::onc::cellular_apn::kName, shill::kApnNameProperty},
    134     { ::onc::cellular_apn::kUsername, shill::kApnUsernameProperty},
    135     { ::onc::cellular_apn::kPassword, shill::kApnPasswordProperty},
    136     { ::onc::cellular_apn::kLocalizedName, shill::kApnLocalizedNameProperty},
    137     { ::onc::cellular_apn::kLanguage, shill::kApnLanguageProperty},
    138     {NULL}};
    139 
    140 const FieldTranslationEntry cellular_found_network_fields[] = {
    141     { ::onc::cellular_found_network::kNetworkId, shill::kNetworkIdProperty},
    142     { ::onc::cellular_found_network::kStatus, shill::kStatusProperty},
    143     { ::onc::cellular_found_network::kTechnology, shill::kTechnologyProperty},
    144     { ::onc::cellular_found_network::kShortName, shill::kShortNameProperty},
    145     { ::onc::cellular_found_network::kLongName, shill::kLongNameProperty},
    146     {NULL}};
    147 
    148 const FieldTranslationEntry cellular_provider_fields[] = {
    149     { ::onc::cellular_provider::kCode, shill::kOperatorCodeKey},
    150     { ::onc::cellular_provider::kCountry, shill::kOperatorCountryKey},
    151     { ::onc::cellular_provider::kName, shill::kOperatorNameKey},
    152     {NULL}};
    153 
    154 const FieldTranslationEntry sim_lock_status_fields[] = {
    155     { ::onc::sim_lock_status::kLockEnabled, shill::kSIMLockEnabledProperty},
    156     { ::onc::sim_lock_status::kLockType, shill::kSIMLockTypeProperty},
    157     { ::onc::sim_lock_status::kRetriesLeft, shill::kSIMLockRetriesLeftProperty},
    158     {NULL}};
    159 
    160 // This must only contain Service properties and not Device properties.
    161 // For Device properties see kCellularDeviceTable.
    162 const FieldTranslationEntry cellular_fields[] = {
    163     { ::onc::cellular::kActivationType, shill::kActivationTypeProperty},
    164     // This field is converted during translation, see onc_translator_*.
    165     // { ::onc::cellular::kActivationState, shill::kActivationStateProperty},
    166     { ::onc::vpn::kAutoConnect, shill::kAutoConnectProperty},
    167     { ::onc::cellular::kNetworkTechnology, shill::kNetworkTechnologyProperty},
    168     // This field is converted during translation, see onc_translator_*.
    169     // { ::onc::cellular::kRoamingState, shill::kRoamingStateProperty},
    170     {NULL}};
    171 
    172 const FieldTranslationEntry network_fields[] = {
    173     { ::onc::network_config::kGUID, shill::kGuidProperty},
    174     { ::onc::network_config::kConnectable, shill::kConnectableProperty },
    175     { ::onc::network_config::kErrorState, shill::kErrorProperty },
    176     { ::onc::network_config::kPriority, shill::kPriorityProperty },
    177 
    178     // Shill doesn't allow setting the name for non-VPN networks.
    179     // Name is conditionally translated, see onc_translator_*.
    180     // { ::onc::network_config::kName, shill::kNameProperty },
    181 
    182     // Type is converted during translation, see onc_translator_*.
    183     // { ::onc::network_config::kType, shill::kTypeProperty },
    184 
    185     // These fields are converted during translation, see
    186     // onc_translator_shill_to_onc.cc. They are only converted when going from
    187     // Shill->ONC, and ignored otherwise.
    188     // { ::onc::network_config::kConnectionState, shill::kStateProperty },
    189     // { ::onc::network_config::kRestrictedConnectivity,
    190     //   shill::kStateProperty },
    191     // { ::onc::network_config::kSource, shill::kProfileProperty },
    192     // { ::onc::network_config::kMacAddress, shill::kAddressProperty },
    193     {NULL}};
    194 
    195 const FieldTranslationEntry ipconfig_fields[] = {
    196     { ::onc::ipconfig::kIPAddress, shill::kAddressProperty},
    197     { ::onc::ipconfig::kGateway, shill::kGatewayProperty},
    198     { ::onc::ipconfig::kRoutingPrefix, shill::kPrefixlenProperty},
    199     { ::onc::ipconfig::kNameServers, shill::kNameServersProperty},
    200     // This field is converted during translation, see ShillToONCTranslator::
    201     // TranslateIPConfig. It is only converted from Shill->ONC.
    202     // { ::onc::ipconfig::kType, shill::kMethodProperty},
    203     { ::onc::ipconfig::kWebProxyAutoDiscoveryUrl,
    204       shill::kWebProxyAutoDiscoveryUrlProperty},
    205     {NULL}};
    206 
    207 const FieldTranslationEntry saved_ipconfig_fields[] = {
    208     { ::onc::ipconfig::kIPAddress, shill::kSavedIPAddressProperty},
    209     { ::onc::ipconfig::kGateway, shill::kSavedIPGatewayProperty},
    210     { ::onc::ipconfig::kRoutingPrefix, shill::kSavedIPPrefixlenProperty},
    211     // NameServers are converted during translation, see onc_translator_*.
    212     // { ::onc::ipconfig::kNameServers, shill::kSavedIPNameServersProperty},
    213     {NULL}};
    214 
    215 const FieldTranslationEntry static_ipconfig_fields[] = {
    216     { ::onc::ipconfig::kIPAddress, shill::kStaticIPAddressProperty},
    217     { ::onc::ipconfig::kGateway, shill::kStaticIPGatewayProperty},
    218     { ::onc::ipconfig::kRoutingPrefix, shill::kStaticIPPrefixlenProperty},
    219     // NameServers are converted during translation, see onc_translator_*.
    220     // { ::onc::ipconfig::kNameServers, shill::kStaticIPNameServersProperty},
    221     {NULL}};
    222 
    223 struct OncValueTranslationEntry {
    224   const OncValueSignature* onc_signature;
    225   const FieldTranslationEntry* field_translation_table;
    226 };
    227 
    228 const OncValueTranslationEntry onc_value_translation_table[] = {
    229   { &kEAPSignature, eap_fields },
    230   { &kIPsecSignature, ipsec_fields },
    231   { &kL2TPSignature, l2tp_fields },
    232   { &kXAUTHSignature, xauth_fields },
    233   { &kOpenVPNSignature, openvpn_fields },
    234   { &kVerifyX509Signature, verify_x509_fields },
    235   { &kVPNSignature, vpn_fields },
    236   { &kWiFiSignature, wifi_fields },
    237   { &kWiFiWithStateSignature, wifi_fields },
    238   { &kWiMAXSignature, wimax_fields },
    239   { &kWiMAXWithStateSignature, wimax_fields },
    240   { &kCellularApnSignature, cellular_apn_fields },
    241   { &kCellularFoundNetworkSignature, cellular_found_network_fields },
    242   { &kCellularProviderSignature, cellular_provider_fields },
    243   { &kSIMLockStatusSignature, sim_lock_status_fields },
    244   { &kCellularSignature, cellular_fields },
    245   { &kCellularWithStateSignature, cellular_fields },
    246   { &kNetworkWithStateSignature, network_fields },
    247   { &kNetworkConfigurationSignature, network_fields },
    248   { &kIPConfigSignature, ipconfig_fields },
    249   { &kSavedIPConfigSignature, saved_ipconfig_fields },
    250   { &kStaticIPConfigSignature, static_ipconfig_fields },
    251   { NULL }
    252 };
    253 
    254 struct NestedShillDictionaryEntry {
    255   const OncValueSignature* onc_signature;
    256   // NULL terminated list of Shill property keys.
    257   const char* const* shill_property_path;
    258 };
    259 
    260 const char* cellular_apn_property_path_entries[] = {
    261   shill::kCellularApnProperty,
    262   NULL
    263 };
    264 
    265 const NestedShillDictionaryEntry nested_shill_dictionaries[] = {
    266   { &kCellularApnSignature, cellular_apn_property_path_entries },
    267   { NULL }
    268 };
    269 
    270 }  // namespace
    271 
    272 const StringTranslationEntry kNetworkTypeTable[] = {
    273     // This mapping is ensured in the translation code.
    274     //  { network_type::kEthernet, shill::kTypeEthernet },
    275     //  { network_type::kEthernet, shill::kTypeEthernetEap },
    276     { ::onc::network_type::kWiFi, shill::kTypeWifi},
    277     { ::onc::network_type::kWimax, shill::kTypeWimax},
    278     { ::onc::network_type::kCellular, shill::kTypeCellular},
    279     { ::onc::network_type::kVPN, shill::kTypeVPN},
    280     {NULL}};
    281 
    282 const StringTranslationEntry kVPNTypeTable[] = {
    283     { ::onc::vpn::kTypeL2TP_IPsec, shill::kProviderL2tpIpsec},
    284     { ::onc::vpn::kOpenVPN, shill::kProviderOpenVpn}, {NULL}};
    285 
    286 // The first matching line is chosen.
    287 const StringTranslationEntry kWiFiSecurityTable[] = {
    288     { ::onc::wifi::kSecurityNone, shill::kSecurityNone},
    289     { ::onc::wifi::kWEP_PSK, shill::kSecurityWep},
    290     { ::onc::wifi::kWPA_PSK, shill::kSecurityPsk},
    291     { ::onc::wifi::kWPA_EAP, shill::kSecurity8021x},
    292     { ::onc::wifi::kWPA_PSK, shill::kSecurityRsn},
    293     { ::onc::wifi::kWPA_PSK, shill::kSecurityWpa},
    294     {NULL}};
    295 
    296 const StringTranslationEntry kEAPOuterTable[] = {
    297     { ::onc::eap::kPEAP, shill::kEapMethodPEAP},
    298     { ::onc::eap::kEAP_TLS, shill::kEapMethodTLS},
    299     { ::onc::eap::kEAP_TTLS, shill::kEapMethodTTLS},
    300     { ::onc::eap::kLEAP, shill::kEapMethodLEAP},
    301     {NULL}};
    302 
    303 // Translation of the EAP.Inner field in case of EAP.Outer == PEAP
    304 const StringTranslationEntry kEAP_PEAP_InnerTable[] = {
    305     { ::onc::eap::kMD5, shill::kEapPhase2AuthPEAPMD5},
    306     { ::onc::eap::kMSCHAPv2, shill::kEapPhase2AuthPEAPMSCHAPV2}, {NULL}};
    307 
    308 // Translation of the EAP.Inner field in case of EAP.Outer == TTLS
    309 const StringTranslationEntry kEAP_TTLS_InnerTable[] = {
    310     { ::onc::eap::kMD5, shill::kEapPhase2AuthTTLSMD5},
    311     { ::onc::eap::kMSCHAPv2, shill::kEapPhase2AuthTTLSMSCHAPV2},
    312     { ::onc::eap::kPAP, shill::kEapPhase2AuthTTLSPAP},
    313     {NULL}};
    314 
    315 const StringTranslationEntry kActivationStateTable[] = {
    316     { ::onc::cellular::kActivated, shill::kActivationStateActivated},
    317     { ::onc::cellular::kActivating, shill::kActivationStateActivating},
    318     { ::onc::cellular::kNotActivated, shill::kActivationStateNotActivated},
    319     { ::onc::cellular::kPartiallyActivated,
    320       shill::kActivationStatePartiallyActivated},
    321     {NULL}};
    322 
    323 const StringTranslationEntry kRoamingStateTable[] = {
    324     { ::onc::cellular::kHome, shill::kRoamingStateHome},
    325     { ::onc::cellular::kRoaming, shill::kRoamingStateRoaming},
    326     {NULL}};
    327 
    328 // This must contain only Shill Device properties and no Service properties.
    329 // For Service properties see cellular_fields.
    330 const FieldTranslationEntry kCellularDeviceTable[] = {
    331     // This field is converted during translation, see onc_translator_*.
    332     // { ::onc::cellular::kAPNList, shill::kCellularApnListProperty},
    333     { ::onc::cellular::kAllowRoaming, shill::kCellularAllowRoamingProperty},
    334     { ::onc::cellular::kCarrier, shill::kCarrierProperty},
    335     { ::onc::cellular::kESN, shill::kEsnProperty},
    336     { ::onc::cellular::kFamily, shill::kTechnologyFamilyProperty},
    337     { ::onc::cellular::kFirmwareRevision, shill::kFirmwareRevisionProperty},
    338     // This field is converted during translation, see onc_translator_*.
    339     // { ::onc::cellular::kFoundNetworks, shill::kFoundNetworksProperty},
    340     { ::onc::cellular::kHardwareRevision, shill::kHardwareRevisionProperty},
    341     { ::onc::cellular::kHomeProvider, shill::kHomeProviderProperty},
    342     { ::onc::cellular::kICCID, shill::kIccidProperty},
    343     { ::onc::cellular::kIMEI, shill::kImeiProperty},
    344     { ::onc::cellular::kIMSI, shill::kImsiProperty},
    345     { ::onc::cellular::kManufacturer, shill::kManufacturerProperty},
    346     { ::onc::cellular::kMDN, shill::kMdnProperty},
    347     { ::onc::cellular::kMEID, shill::kMeidProperty},
    348     { ::onc::cellular::kMIN, shill::kMinProperty},
    349     { ::onc::cellular::kModelID, shill::kModelIDProperty},
    350     { ::onc::cellular::kPRLVersion, shill::kPRLVersionProperty},
    351     { ::onc::cellular::kProviderRequiresRoaming,
    352       shill::kProviderRequiresRoamingProperty},
    353     // This field is converted during translation, see onc_translator_*.
    354     // { ::onc::cellular::kSIMLockStatus, shill::kSIMLockStatusProperty},
    355     { ::onc::cellular::kSIMPresent, shill::kSIMPresentProperty},
    356     { ::onc::cellular::kSupportedCarriers, shill::kSupportedCarriersProperty},
    357     { ::onc::cellular::kSupportNetworkScan, shill::kSupportNetworkScanProperty},
    358     {NULL}};
    359 
    360 const FieldTranslationEntry* GetFieldTranslationTable(
    361     const OncValueSignature& onc_signature) {
    362   for (const OncValueTranslationEntry* it = onc_value_translation_table;
    363        it->onc_signature != NULL; ++it) {
    364     if (it->onc_signature == &onc_signature)
    365       return it->field_translation_table;
    366   }
    367   return NULL;
    368 }
    369 
    370 std::vector<std::string> GetPathToNestedShillDictionary(
    371     const OncValueSignature& onc_signature) {
    372   std::vector<std::string> shill_property_path;
    373   for (const NestedShillDictionaryEntry* it = nested_shill_dictionaries;
    374        it->onc_signature != NULL; ++it) {
    375     if (it->onc_signature == &onc_signature) {
    376       for (const char* const* key = it->shill_property_path; *key != NULL;
    377            ++key) {
    378         shill_property_path.push_back(std::string(*key));
    379       }
    380       break;
    381     }
    382   }
    383   return shill_property_path;
    384 }
    385 
    386 bool GetShillPropertyName(const std::string& onc_field_name,
    387                           const FieldTranslationEntry table[],
    388                           std::string* shill_property_name) {
    389   for (const FieldTranslationEntry* it = table;
    390        it->onc_field_name != NULL; ++it) {
    391     if (it->onc_field_name != onc_field_name)
    392       continue;
    393     *shill_property_name = it->shill_property_name;
    394     return true;
    395   }
    396   return false;
    397 }
    398 
    399 bool TranslateStringToShill(const StringTranslationEntry table[],
    400                             const std::string& onc_value,
    401                             std::string* shill_value) {
    402   for (int i = 0; table[i].onc_value != NULL; ++i) {
    403     if (onc_value != table[i].onc_value)
    404       continue;
    405     *shill_value = table[i].shill_value;
    406     return true;
    407   }
    408   LOG(ERROR) << "Value '" << onc_value << "' cannot be translated to Shill";
    409   return false;
    410 }
    411 
    412 bool TranslateStringToONC(const StringTranslationEntry table[],
    413                           const std::string& shill_value,
    414                           std::string* onc_value) {
    415   for (int i = 0; table[i].shill_value != NULL; ++i) {
    416     if (shill_value != table[i].shill_value)
    417       continue;
    418     *onc_value = table[i].onc_value;
    419     return true;
    420   }
    421   LOG(ERROR) << "Value '" << shill_value << "' cannot be translated to ONC";
    422   return false;
    423 }
    424 
    425 }  // namespace onc
    426 }  // namespace chromeos
    427