blob: 698fa88c2de624a0c3dbc6bdbbf54d6aaa272fa9 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromeos/network/device_state.h"
#include <memory>
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
#include "base/values.h"
#include "chromeos/network/network_event_log.h"
#include "chromeos/network/shill_property_util.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
namespace chromeos {
DeviceState::DeviceState(const std::string& path)
: ManagedState(MANAGED_TYPE_DEVICE, path) {}
DeviceState::~DeviceState() = default;
bool DeviceState::PropertyChanged(const std::string& key,
const base::Value& value) {
// All property values get stored in |properties_|.
properties_.SetKey(key, value.Clone());
if (ManagedStatePropertyChanged(key, value))
return true;
if (key == shill::kAddressProperty) {
return GetStringValue(key, value, &mac_address_);
} else if (key == shill::kInterfaceProperty) {
return GetStringValue(key, value, &interface_);
} else if (key == shill::kScanningProperty) {
return GetBooleanValue(key, value, &scanning_);
} else if (key == shill::kSupportNetworkScanProperty) {
return GetBooleanValue(key, value, &support_network_scan_);
} else if (key == shill::kProviderRequiresRoamingProperty) {
return GetBooleanValue(key, value, &provider_requires_roaming_);
} else if (key == shill::kHomeProviderProperty) {
if (!value.is_dict()) {
operator_name_.clear();
country_code_.clear();
return true;
}
const base::Value* operator_name = value.FindKey(shill::kOperatorNameKey);
if (operator_name)
operator_name_ = operator_name->GetString();
if (operator_name_.empty()) {
const base::Value* operator_code = value.FindKey(shill::kOperatorCodeKey);
operator_name_ = operator_code ? operator_code->GetString() : "";
}
const base::Value* country_code = value.FindKey(shill::kOperatorCountryKey);
country_code_ = country_code ? country_code->GetString() : "";
} else if (key == shill::kTechnologyFamilyProperty) {
return GetStringValue(key, value, &technology_family_);
} else if (key == shill::kFoundNetworksProperty) {
const base::ListValue* list = nullptr;
if (!value.GetAsList(&list))
return false;
CellularScanResults parsed_results;
if (!network_util::ParseCellularScanResults(*list, &parsed_results))
return false;
scan_results_.swap(parsed_results);
return true;
} else if (key == shill::kSIMSlotInfoProperty) {
if (!value.is_list())
return false;
CellularSIMSlotInfos parsed_results;
if (!network_util::ParseCellularSIMSlotInfo(value.GetList(),
&parsed_results)) {
return false;
}
sim_slot_infos_.swap(parsed_results);
return true;
} else if (key == shill::kSIMLockStatusProperty) {
const base::DictionaryValue* dict = nullptr;
if (!value.GetAsDictionary(&dict))
return false;
// Set default values for SIM properties.
sim_lock_type_.erase();
sim_retries_left_ = 0;
sim_lock_enabled_ = false;
const base::Value* out_value = nullptr;
out_value = dict->FindKey(shill::kSIMLockTypeProperty);
if (out_value) {
GetStringValue(shill::kSIMLockTypeProperty, *out_value, &sim_lock_type_);
}
out_value = dict->FindKey(shill::kSIMLockRetriesLeftProperty);
if (out_value) {
GetIntegerValue(shill::kSIMLockRetriesLeftProperty, *out_value,
&sim_retries_left_);
}
out_value = dict->FindKey(shill::kSIMLockEnabledProperty);
if (out_value) {
GetBooleanValue(shill::kSIMLockEnabledProperty, *out_value,
&sim_lock_enabled_);
}
return true;
} else if (key == shill::kMeidProperty) {
return GetStringValue(key, value, &meid_);
} else if (key == shill::kImeiProperty) {
return GetStringValue(key, value, &imei_);
} else if (key == shill::kIccidProperty) {
return GetStringValue(key, value, &iccid_);
} else if (key == shill::kMdnProperty) {
return GetStringValue(key, value, &mdn_);
} else if (key == shill::kSIMPresentProperty) {
return GetBooleanValue(key, value, &sim_present_);
} else if (key == shill::kCellularApnListProperty) {
if (!value.is_list())
return false;
apn_list_ = value.Clone();
return true;
} else if (key == shill::kInhibitedProperty) {
return GetBooleanValue(key, value, &inhibited_);
} else if (key == shill::kEapAuthenticationCompletedProperty) {
return GetBooleanValue(key, value, &eap_authentication_completed_);
} else if (key == shill::kIPConfigsProperty) {
// If kIPConfigsProperty changes, clear any previous ip_configs_.
// ShillPropertyhandler will request the IPConfig objects which will trigger
// calls to IPConfigPropertiesChanged.
ip_configs_.Clear();
return false; // No actual state change.
} else if (key == shill::kLinkUpProperty) {
return GetBooleanValue(key, value, &link_up_);
} else if (key == shill::kDeviceBusTypeProperty) {
return GetStringValue(key, value, &device_bus_type_);
} else if (key == shill::kUsbEthernetMacAddressSourceProperty) {
return GetStringValue(key, value, &mac_address_source_);
}
return false;
}
bool DeviceState::IsActive() const {
return true;
}
void DeviceState::IPConfigPropertiesChanged(const std::string& ip_config_path,
const base::Value& properties) {
NET_LOG(EVENT) << "IPConfig for: " << path()
<< " Changed: " << ip_config_path;
ip_configs_.SetKey(ip_config_path, properties.Clone());
}
std::string DeviceState::GetName() const {
if (!operator_name_.empty())
return operator_name_;
return name();
}
DeviceState::CellularSIMSlotInfos DeviceState::GetSimSlotInfos() const {
// If information was provided from Shill, return it directly.
if (!sim_slot_infos_.empty())
return sim_slot_infos_;
// Non-cellular types do not have any SIM slots.
if (type() != shill::kTypeCellular) {
NET_LOG(ERROR) << "Attempted to fetch SIM slots for device of type "
<< type() << ". Returning empty list.";
return {};
}
// Some devices do not return SIMSlotInfo properties (see b/189874098). If the
// list is currently empty, we assume that this is a single-pSIM device and
// return one CellularSIMSlotInfo object representing the single pSIM.
CellularSIMSlotInfo info;
info.slot_id = 1; // Slot numbers start at 1, not 0.
info.eid = std::string(); // Empty EID implies a physical SIM slot.
info.iccid = iccid(); // Copy ICCID property.
info.primary = true; // Only one slot, so it must be the primary one.
return CellularSIMSlotInfos{info};
}
std::string DeviceState::GetIpAddressByType(const std::string& type) const {
for (base::DictionaryValue::Iterator iter(ip_configs_); !iter.IsAtEnd();
iter.Advance()) {
const base::DictionaryValue* ip_config;
if (!iter.value().GetAsDictionary(&ip_config))
continue;
std::string ip_config_method;
if (!ip_config->GetString(shill::kMethodProperty, &ip_config_method))
continue;
if (type == ip_config_method ||
(type == shill::kTypeIPv4 && ip_config_method == shill::kTypeDHCP) ||
(type == shill::kTypeIPv6 && ip_config_method == shill::kTypeDHCP6)) {
std::string address;
if (!ip_config->GetString(shill::kAddressProperty, &address))
continue;
return address;
}
}
return std::string();
}
bool DeviceState::IsSimAbsent() const {
return technology_family_ != shill::kTechnologyFamilyCdma && !sim_present_;
}
bool DeviceState::IsSimLocked() const {
if (technology_family_ == shill::kTechnologyFamilyCdma || !sim_present_)
return false;
return sim_lock_type_ == shill::kSIMLockPin ||
sim_lock_type_ == shill::kSIMLockPuk;
}
bool DeviceState::HasAPN(const std::string& access_point_name) const {
for (const auto& apn : apn_list_.GetList()) {
// bogus empty entries in the list might have been converted to a list while
// traveling over D-Bus, skip them rather than crashing below.
if (!apn.is_dict())
continue;
const std::string* apn_name = apn.FindStringKey(shill::kApnProperty);
if (apn_name && *apn_name == access_point_name) {
return true;
}
}
return false;
}
} // namespace chromeos