blob: 5093fff4cac136a12a6f07ab82b2a576df2f495b [file] [log] [blame]
// Copyright 2018 The Chromium OS 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 "shill/cellular/cellular_bearer.h"
#include <ModemManager/ModemManager.h>
#include <base/bind.h>
#include <chromeos/dbus/service_constants.h>
#include "shill/control_interface.h"
#include "shill/dbus/dbus_properties_proxy.h"
#include "shill/logging.h"
using std::string;
using std::vector;
namespace shill {
namespace Logging {
static auto kModuleLogScope = ScopeLogger::kCellular;
static string ObjectID(const CellularBearer* c) {
return "(cellular_bearer)";
}
} // namespace Logging
namespace {
const char kPropertyAddress[] = "address";
const char kPropertyDNS1[] = "dns1";
const char kPropertyDNS2[] = "dns2";
const char kPropertyDNS3[] = "dns3";
const char kPropertyGateway[] = "gateway";
const char kPropertyMethod[] = "method";
const char kPropertyPrefix[] = "prefix";
const char kPropertyMtu[] = "mtu";
IPConfig::Method ConvertMMBearerIPConfigMethod(uint32_t method) {
switch (method) {
case MM_BEARER_IP_METHOD_PPP:
return IPConfig::kMethodPPP;
case MM_BEARER_IP_METHOD_STATIC:
return IPConfig::kMethodStatic;
case MM_BEARER_IP_METHOD_DHCP:
return IPConfig::kMethodDHCP;
default:
return IPConfig::kMethodUnknown;
}
}
} // namespace
CellularBearer::CellularBearer(ControlInterface* control_interface,
const RpcIdentifier& dbus_path,
const string& dbus_service)
: control_interface_(control_interface),
dbus_path_(dbus_path),
dbus_service_(dbus_service) {
CHECK(control_interface_);
}
CellularBearer::~CellularBearer() = default;
bool CellularBearer::Init() {
SLOG(this, 3) << __func__ << ": path='" << dbus_path_.value()
<< "', service='" << dbus_service_ << "'";
dbus_properties_proxy_ =
control_interface_->CreateDBusPropertiesProxy(dbus_path_, dbus_service_);
// It is possible that ProxyFactory::CreateDBusPropertiesProxy() returns
// nullptr as the bearer DBus object may no longer exist.
if (!dbus_properties_proxy_) {
LOG(WARNING) << "Failed to create DBus properties proxy for bearer '"
<< dbus_path_.value() << "'. Bearer is likely gone.";
return false;
}
dbus_properties_proxy_->SetPropertiesChangedCallback(
base::Bind(&CellularBearer::OnPropertiesChanged, base::Unretained(this)));
UpdateProperties();
return true;
}
void CellularBearer::GetIPConfigMethodAndProperties(
const KeyValueStore& properties,
IPAddress::Family address_family,
IPConfig::Method* ipconfig_method,
std::unique_ptr<IPConfig::Properties>* ipconfig_properties) const {
DCHECK(ipconfig_method);
DCHECK(ipconfig_properties);
uint32_t method = MM_BEARER_IP_METHOD_UNKNOWN;
if (properties.Contains<uint32_t>(kPropertyMethod)) {
method = properties.Get<uint32_t>(kPropertyMethod);
} else {
SLOG(this, 2) << "Bearer '" << dbus_path_.value()
<< "' does not specify an IP configuration method.";
}
*ipconfig_method = ConvertMMBearerIPConfigMethod(method);
ipconfig_properties->reset();
if (*ipconfig_method != IPConfig::kMethodStatic)
return;
if (!properties.Contains<string>(kPropertyAddress) ||
!properties.Contains<string>(kPropertyGateway)) {
SLOG(this, 2) << "Bearer '" << dbus_path_.value()
<< "' static IP configuration does not specify valid "
"address/gateway information.";
*ipconfig_method = IPConfig::kMethodUnknown;
return;
}
ipconfig_properties->reset(new IPConfig::Properties);
(*ipconfig_properties)->address_family = address_family;
(*ipconfig_properties)->address = properties.Get<string>(kPropertyAddress);
(*ipconfig_properties)->gateway = properties.Get<string>(kPropertyGateway);
// Set method string for kMethodStatic
if ((*ipconfig_properties)->address_family == IPAddress::kFamilyIPv4) {
(*ipconfig_properties)->method = kTypeIPv4;
} else if ((*ipconfig_properties)->address_family == IPAddress::kFamilyIPv6) {
(*ipconfig_properties)->method = kTypeIPv6;
}
uint32_t prefix;
if (!properties.Contains<uint32_t>(kPropertyPrefix)) {
prefix = IPAddress::GetMaxPrefixLength(address_family);
} else {
prefix = properties.Get<uint32_t>(kPropertyPrefix);
}
(*ipconfig_properties)->subnet_prefix = prefix;
if (properties.Contains<string>(kPropertyDNS1)) {
(*ipconfig_properties)
->dns_servers.push_back(properties.Get<string>(kPropertyDNS1));
}
if (properties.Contains<string>(kPropertyDNS2)) {
(*ipconfig_properties)
->dns_servers.push_back(properties.Get<string>(kPropertyDNS2));
}
if (properties.Contains<string>(kPropertyDNS3)) {
(*ipconfig_properties)
->dns_servers.push_back(properties.Get<string>(kPropertyDNS3));
}
if (properties.Contains<uint32_t>(kPropertyMtu)) {
uint32_t mtu = properties.Get<uint32_t>(kPropertyMtu);
// TODO(b/139816862): A larger-than-expected MTU value has been observed
// on some modem. Here we temporarily ignore any MTU value larger than
// |IPConfig::kDefaultMTU| until the issue has been addressed on the modem
// side. Remove this workaround later.
if (mtu <= static_cast<uint32_t>(IPConfig::kDefaultMTU)) {
(*ipconfig_properties)->mtu = mtu;
}
}
}
void CellularBearer::ResetProperties() {
connected_ = false;
data_interface_.clear();
ipv4_config_method_ = IPConfig::kMethodUnknown;
ipv4_config_properties_.reset();
ipv6_config_method_ = IPConfig::kMethodUnknown;
ipv6_config_properties_.reset();
}
void CellularBearer::UpdateProperties() {
ResetProperties();
if (!dbus_properties_proxy_)
return;
auto properties = dbus_properties_proxy_->GetAll(MM_DBUS_INTERFACE_BEARER);
OnPropertiesChanged(MM_DBUS_INTERFACE_BEARER, properties);
}
void CellularBearer::OnPropertiesChanged(
const string& interface, const KeyValueStore& changed_properties) {
SLOG(this, 3) << __func__ << ": path=" << dbus_path_.value()
<< ", interface=" << interface;
if (interface != MM_DBUS_INTERFACE_BEARER)
return;
if (changed_properties.Contains<bool>(MM_BEARER_PROPERTY_CONNECTED)) {
connected_ = changed_properties.Get<bool>(MM_BEARER_PROPERTY_CONNECTED);
}
string data_interface;
if (changed_properties.Contains<string>(MM_BEARER_PROPERTY_INTERFACE)) {
data_interface_ =
changed_properties.Get<string>(MM_BEARER_PROPERTY_INTERFACE);
}
if (changed_properties.Contains<KeyValueStore>(
MM_BEARER_PROPERTY_IP4CONFIG)) {
KeyValueStore ipconfig =
changed_properties.Get<KeyValueStore>(MM_BEARER_PROPERTY_IP4CONFIG);
GetIPConfigMethodAndProperties(ipconfig, IPAddress::kFamilyIPv4,
&ipv4_config_method_,
&ipv4_config_properties_);
}
if (changed_properties.Contains<KeyValueStore>(
MM_BEARER_PROPERTY_IP6CONFIG)) {
KeyValueStore ipconfig =
changed_properties.Get<KeyValueStore>(MM_BEARER_PROPERTY_IP6CONFIG);
GetIPConfigMethodAndProperties(ipconfig, IPAddress::kFamilyIPv6,
&ipv6_config_method_,
&ipv6_config_properties_);
}
}
} // namespace shill