blob: 398e0d6f0aba886df490c6f438f89877e707c697 [file] [log] [blame]
// Copyright (c) 2012 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 "debugd/src/debug_mode_tool.h"
#include <memory>
#include <base/files/file_util.h>
#include <chromeos/dbus/service_constants.h>
#include <dbus/bus.h>
#include <dbus/message.h>
#include <dbus/object_proxy.h>
#include <dbus/property.h>
#include <shill/dbus-proxies.h>
namespace debugd {
namespace {
const int kFlimflamLogLevelVerbose3 = -3;
const int kFlimflamLogLevelInfo = 0;
const char kSupplicantServiceName[] = "fi.w1.wpa_supplicant1";
const char kSupplicantObjectPath[] = "/f1/w1/wpa_supplicant1";
const char kSupplicantDebugLevel[] = "DebugLevel";
class SupplicantProxy {
public:
struct Properties : public dbus::PropertySet {
dbus::Property<std::string> debug_level;
explicit Properties(dbus::ObjectProxy* proxy)
: dbus::PropertySet(proxy, kSupplicantServiceName,
dbus::PropertySet::PropertyChangedCallback()) {
RegisterProperty(kSupplicantDebugLevel, &debug_level);
}
~Properties() override = default;
};
explicit SupplicantProxy(scoped_refptr<dbus::Bus> bus)
: bus_(bus),
properties_(bus->GetObjectProxy(
kSupplicantServiceName, dbus::ObjectPath(kSupplicantObjectPath))) {}
~SupplicantProxy() {}
void SetDebugLevel(const std::string& level) {
properties_.debug_level.SetAndBlock(level);
}
private:
scoped_refptr<dbus::Bus> bus_;
Properties properties_;
DISALLOW_COPY_AND_ASSIGN(SupplicantProxy);
};
// Marvell wifi.
constexpr char kMwifiexDebugMask[] =
"/sys/kernel/debug/mwifiex/mlan0/debug_mask";
// Enable extra debugging: MSG | FATAL | ERROR | CMD | EVENT.
constexpr char kMwifiexEnable[] = "0x37";
// Default debugging level: MSG | FATAL | ERROR.
constexpr char kMwifiexDisable[] = "0x7";
// Intel wifi.
constexpr char kIwlwifiDebugFlag[] = "/sys/module/iwlwifi/parameters/debug";
// Full debugging: see below file for details on each bit:
// drivers/net/wireless-$(WIFIVERSION)/iwl7000/iwlwifi/iwl-debug.h
constexpr char kIwlwifiEnable[] = "0xFFFFFFFF";
// Default debugging: none
constexpr char kIwlwifiDisable[] = "0x0";
void MaybeWriteSysfs(const char* sysfs_path, const char* data) {
base::FilePath path(sysfs_path);
if (base::PathExists(path)) {
int len = strlen(data);
if (base::WriteFile(path, data, len) != len)
PLOG(WARNING) << "Writing to " << path.value() << " failed";
}
}
void WifiSetDebugLevels(bool enable) {
MaybeWriteSysfs(kIwlwifiDebugFlag,
enable ? kIwlwifiEnable : kIwlwifiDisable);
MaybeWriteSysfs(kMwifiexDebugMask,
enable ? kMwifiexEnable : kMwifiexDisable);
}
} // namespace
#if USE_CELLULAR
namespace {
const char kDBusListNames[] = "ListNames";
const char kModemManager[] = "ModemManager";
const char kSetLogging[] = "SetLogging";
} // namespace
#endif // USE_CELLULAR
DebugModeTool::DebugModeTool(scoped_refptr<dbus::Bus> bus) : bus_(bus) {}
void DebugModeTool::SetDebugMode(const std::string& subsystem) {
std::string flimflam_tags;
std::string supplicant_level = "info";
std::string modemmanager_level = "info";
bool wifi_debug = false;
if (subsystem == "wifi") {
flimflam_tags = "service+wifi+inet+device+manager";
supplicant_level = "msgdump";
wifi_debug = true;
} else if (subsystem == "wimax") {
flimflam_tags = "service+wimax+device+manager";
} else if (subsystem == "cellular") {
flimflam_tags = "service+cellular+modem+device+manager";
modemmanager_level = "debug";
} else if (subsystem == "ethernet") {
flimflam_tags = "service+ethernet+device+manager";
} else if (subsystem == "none") {
flimflam_tags = "";
}
auto shill = std::make_unique<org::chromium::flimflam::ManagerProxy>(bus_);
if (shill) {
shill->SetDebugTags(flimflam_tags, nullptr);
if (flimflam_tags.length()) {
shill->SetDebugLevel(kFlimflamLogLevelVerbose3, nullptr);
} else {
shill->SetDebugLevel(kFlimflamLogLevelInfo, nullptr);
}
}
WifiSetDebugLevels(wifi_debug);
SupplicantProxy supplicant(bus_);
supplicant.SetDebugLevel(supplicant_level);
SetAllModemManagersLogging(modemmanager_level);
}
void DebugModeTool::GetAllModemManagers(std::vector<std::string>* managers) {
#if USE_CELLULAR
managers->clear();
dbus::ObjectProxy* proxy =
bus_->GetObjectProxy(dbus::kDBusServiceName,
dbus::ObjectPath(dbus::kDBusServicePath));
dbus::MethodCall method_call(dbus::kDBusInterface, kDBusListNames);
std::unique_ptr<dbus::Response> response =
proxy->CallMethodAndBlock(&method_call,
dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
std::vector<std::string> names;
dbus::MessageReader reader(response.get());
if (!reader.PopArrayOfStrings(&names))
return;
for (const auto& name : names) {
if (name.find(kModemManager) != std::string::npos)
managers->push_back(name);
}
#endif // USE_CELLULAR
}
void DebugModeTool::SetModemManagerLogging(const std::string& service_name,
const std::string& service_path,
const std::string& level) {
dbus::ObjectProxy* proxy =
bus_->GetObjectProxy(service_name, dbus::ObjectPath(service_path));
dbus::MethodCall method_call(service_name, kSetLogging);
dbus::MessageWriter writer(&method_call);
writer.AppendString(level);
proxy->CallMethodAndBlock(&method_call,
dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
}
void DebugModeTool::SetAllModemManagersLogging(const std::string& level) {
#if USE_CELLULAR
std::vector<std::string> managers;
GetAllModemManagers(&managers);
for (const auto& manager : managers) {
if (manager == cromo::kCromoServiceName) {
SetModemManagerLogging(cromo::kCromoServiceName,
cromo::kCromoServicePath,
(level == "err" ? "error" : level));
} else if (manager == modemmanager::kModemManager1ServiceName) {
SetModemManagerLogging(modemmanager::kModemManager1ServiceName,
modemmanager::kModemManager1ServicePath,
level);
}
}
#endif // USE_CELLULAR
}
} // namespace debugd