blob: eabbe823afa38f5d0d90af735f0e2713ced3d0bc [file] [log] [blame]
// Copyright 2017 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 "modemfwd/modem.h"
#include <map>
#include <string>
#include <utility>
#include <base/bind.h>
#include <base/files/file_path.h>
#include <base/files/file_util.h>
#include <base/memory/ptr_util.h>
#include <base/logging.h>
#include <base/strings/string_util.h>
#include <base/unguessable_token.h>
#include <brillo/dbus/dbus_method_invoker.h>
#include <chromeos/dbus/service_constants.h>
#include <ModemManager/ModemManager.h>
#include "modemfwd/logging.h"
#include "modemfwd/modem_helper.h"
#include "modemmanager/dbus-proxies.h"
namespace {
class Inhibitor {
public:
Inhibitor(std::unique_ptr<org::freedesktop::ModemManager1Proxy> mm_proxy,
const std::string& physdev_uid)
: mm_proxy_(std::move(mm_proxy)), physdev_uid_(physdev_uid) {}
bool SetInhibited(bool inhibited) {
brillo::ErrorPtr error_unused;
return mm_proxy_->InhibitDevice(physdev_uid_, inhibited, &error_unused);
}
private:
std::unique_ptr<org::freedesktop::ModemManager1Proxy> mm_proxy_;
std::string physdev_uid_;
};
std::unique_ptr<Inhibitor> GetInhibitor(
scoped_refptr<dbus::Bus> bus, const dbus::ObjectPath& mm_object_path) {
// Get the MM object backing this modem, and retrieve its Device property.
// This is the mm_physdev_uid we use for inhibition during updates.
auto mm_device = bus->GetObjectProxy(modemmanager::kModemManager1ServiceName,
mm_object_path);
if (!mm_device)
return nullptr;
brillo::ErrorPtr error;
auto resp = brillo::dbus_utils::CallMethodAndBlock(
mm_device, dbus::kDBusPropertiesInterface, dbus::kDBusPropertiesGet,
&error, std::string(modemmanager::kModemManager1ModemInterface),
std::string(MM_MODEM_PROPERTY_DEVICE));
if (!resp)
return nullptr;
std::string mm_physdev_uid;
if (!brillo::dbus_utils::ExtractMethodCallResults(resp.get(), &error,
&mm_physdev_uid)) {
return nullptr;
}
EVLOG(1) << "Modem " << mm_object_path.value() << " has physdev UID "
<< mm_physdev_uid;
auto mm_proxy = std::make_unique<org::freedesktop::ModemManager1Proxy>(
bus, modemmanager::kModemManager1ServiceName);
return std::make_unique<Inhibitor>(std::move(mm_proxy), mm_physdev_uid);
}
} // namespace
namespace modemfwd {
class ModemImpl : public Modem {
public:
ModemImpl(const std::string& device_id,
const std::string& equipment_id,
const std::string& carrier_id,
std::unique_ptr<Inhibitor> inhibitor,
ModemHelper* helper)
: device_id_(device_id),
equipment_id_(equipment_id),
carrier_id_(carrier_id),
inhibitor_(std::move(inhibitor)),
helper_(helper) {
if (!helper->GetFirmwareInfo(&installed_firmware_))
LOG(WARNING) << "Could not fetch installed firmware information";
}
ModemImpl(const ModemImpl&) = delete;
ModemImpl& operator=(const ModemImpl&) = delete;
~ModemImpl() override = default;
// modemfwd::Modem overrides.
std::string GetDeviceId() const override { return device_id_; }
std::string GetEquipmentId() const override { return equipment_id_; }
std::string GetCarrierId() const override { return carrier_id_; }
std::string GetMainFirmwareVersion() const override {
return installed_firmware_.main_version;
}
std::string GetCarrierFirmwareId() const override {
return installed_firmware_.carrier_uuid;
}
std::string GetCarrierFirmwareVersion() const override {
return installed_firmware_.carrier_version;
}
bool SetInhibited(bool inhibited) override {
if (!inhibitor_) {
EVLOG(1) << "Inhibiting unavailable on this modem";
return false;
}
return inhibitor_->SetInhibited(inhibited);
}
bool FlashMainFirmware(const base::FilePath& path_to_fw,
const std::string& version) override {
return helper_->FlashMainFirmware(path_to_fw, version);
}
bool FlashCarrierFirmware(const base::FilePath& path_to_fw,
const std::string& version) override {
return helper_->FlashCarrierFirmware(path_to_fw, version);
}
bool ClearAttachAPN(const std::string& carrier_uuid) override {
return helper_->ClearAttachAPN(carrier_uuid);
}
private:
std::string device_id_;
std::string equipment_id_;
std::string carrier_id_;
std::unique_ptr<Inhibitor> inhibitor_;
FirmwareInfo installed_firmware_;
ModemHelper* helper_;
};
std::unique_ptr<Modem> CreateModem(
scoped_refptr<dbus::Bus> bus,
std::unique_ptr<org::chromium::flimflam::DeviceProxy> device,
ModemHelperDirectory* helper_directory) {
std::string object_path = device->GetObjectPath().value();
DVLOG(1) << "Creating modem proxy for " << object_path;
brillo::ErrorPtr error;
brillo::VariantDictionary properties;
if (!device->GetProperties(&properties, &error)) {
LOG(WARNING) << "Could not get properties for modem " << object_path;
return nullptr;
}
// If we don't have a device ID, modemfwd can't do anything with this modem,
// so check it first and just return if we can't find it.
std::string device_id;
if (!properties[shill::kDeviceIdProperty].GetValue(&device_id)) {
LOG(INFO) << "Modem " << object_path << " has no device ID, ignoring";
return nullptr;
}
// Equipment ID is also pretty important since we use it as a stable
// identifier that can distinguish between modems of the same type.
std::string equipment_id;
if (!properties[shill::kEquipmentIdProperty].GetValue(&equipment_id)) {
LOG(INFO) << "Modem " << object_path << " has no equipment ID, ignoring";
return nullptr;
}
// This property may not exist and it's not a big deal if it doesn't.
std::map<std::string, std::string> operator_info;
std::string carrier_id;
if (properties[shill::kHomeProviderProperty].GetValue(&operator_info))
carrier_id = operator_info[shill::kOperatorUuidKey];
// Get a helper object for inhibiting the modem, if possible.
std::unique_ptr<Inhibitor> inhibitor;
std::string mm_object_path;
if (!properties[shill::kDBusObjectProperty].GetValue(&mm_object_path)) {
LOG(INFO) << "Modem " << object_path << " has no ModemManager object";
} else {
inhibitor = GetInhibitor(bus, dbus::ObjectPath(mm_object_path));
}
if (!inhibitor)
LOG(INFO) << "Inhibiting modem " << object_path << " will not be possible";
// Use the device ID to grab a helper.
ModemHelper* helper = helper_directory->GetHelperForDeviceId(device_id);
if (!helper) {
LOG(INFO) << "No helper found to update modems with ID [" << device_id
<< "]";
return nullptr;
}
return std::make_unique<ModemImpl>(device_id, equipment_id, carrier_id,
std::move(inhibitor), helper);
}
// StubModem acts like a modem with a particular device ID but does not
// actually talk to a real modem. This allows us to use it for force-
// flashing.
class StubModem : public Modem {
public:
StubModem(const std::string& device_id, ModemHelper* helper)
: device_id_(device_id),
equipment_id_(base::UnguessableToken().ToString()),
helper_(helper) {}
StubModem(const StubModem&) = delete;
StubModem& operator=(const StubModem&) = delete;
~StubModem() override = default;
// modemfwd::Modem overrides.
std::string GetDeviceId() const override { return device_id_; }
std::string GetEquipmentId() const override { return equipment_id_; }
std::string GetCarrierId() const override { return ""; }
std::string GetMainFirmwareVersion() const override { return ""; }
std::string GetCarrierFirmwareId() const override { return ""; }
std::string GetCarrierFirmwareVersion() const override { return ""; }
bool SetInhibited(bool inhibited) override { return true; }
bool FlashMainFirmware(const base::FilePath& path_to_fw,
const std::string& version) override {
return helper_->FlashMainFirmware(path_to_fw, version);
}
bool FlashCarrierFirmware(const base::FilePath& path_to_fw,
const std::string& version) override {
return helper_->FlashCarrierFirmware(path_to_fw, version);
}
bool ClearAttachAPN(const std::string& carrier_uuid) override {
return helper_->ClearAttachAPN(carrier_uuid);
}
private:
std::string device_id_;
std::string equipment_id_;
ModemHelper* helper_;
};
std::unique_ptr<Modem> CreateStubModem(const std::string& device_id,
ModemHelperDirectory* helper_directory) {
// Use the device ID to grab a helper.
ModemHelper* helper = helper_directory->GetHelperForDeviceId(device_id);
if (!helper) {
LOG(INFO) << "No helper found to update modems with ID [" << device_id
<< "]";
return nullptr;
}
return std::make_unique<StubModem>(device_id, helper);
}
} // namespace modemfwd