| // Copyright 2020 The ChromiumOS Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "runtime_probe/functions/network.h" |
| |
| #include <algorithm> |
| #include <map> |
| #include <memory> |
| #include <optional> |
| #include <utility> |
| #include <vector> |
| |
| #include <base/files/file_path.h> |
| #include <base/logging.h> |
| #include <base/values.h> |
| #include <brillo/dbus/dbus_connection.h> |
| #include <brillo/variant_dictionary.h> |
| #include <chromeos/dbus/service_constants.h> |
| #include <chromeos/dbus/shill/dbus-constants.h> |
| #include <shill/dbus-proxies.h> |
| |
| #include "runtime_probe/system/context.h" |
| #include "runtime_probe/utils/bus_utils.h" |
| #include "runtime_probe/utils/file_utils.h" |
| |
| namespace runtime_probe { |
| namespace { |
| |
| constexpr const char* kValidNetworkTypes[] = { |
| "", // The default value which means all the type are accepted. |
| shill::kTypeWifi, |
| shill::kTypeCellular, |
| shill::kTypeEthernet, |
| }; |
| constexpr const char kDefaultRealCellularInterface[] = "wwan0"; |
| |
| std::map<std::string, std::string> GetDevicesType() { |
| std::map<std::string, std::string> result; |
| |
| auto shill_proxy = Context::Get()->shill_manager_proxy(); |
| brillo::VariantDictionary props; |
| if (!shill_proxy->GetProperties(&props, nullptr)) { |
| LOG(ERROR) << "Unable to get manager properties."; |
| return {}; |
| } |
| const auto it = props.find(shill::kDevicesProperty); |
| if (it == props.end()) { |
| LOG(ERROR) << "Manager properties is missing devices."; |
| return {}; |
| } |
| |
| for (const auto& path : it->second.TryGet<std::vector<dbus::ObjectPath>>()) { |
| auto device = Context::Get()->CreateShillDeviceProxy(path); |
| brillo::VariantDictionary device_props; |
| if (!device->GetProperties(&device_props, nullptr)) { |
| VLOG(2) << "Unable to get device properties of " << path.value() |
| << ". Skipped."; |
| continue; |
| } |
| std::string interface = |
| device_props.at(shill::kInterfaceProperty).TryGet<std::string>(); |
| // (b/414308737) Sometimes, shill might temporarily report the default |
| // cellular interface. When this happens, we simply treat it as "wwan0" so |
| // that the probe function can identify /sys/class/net/wwan0 as a cellular |
| // device. |
| if (interface == shill::kCellularDefaultInterfaceName) { |
| interface = kDefaultRealCellularInterface; |
| } |
| |
| std::string type = |
| device_props.at(shill::kTypeProperty).TryGet<std::string>(); |
| result[interface] = type; |
| } |
| |
| return result; |
| } |
| } // namespace |
| |
| bool NetworkFunction::PostParseArguments() { |
| if (!std::ranges::contains(kValidNetworkTypes, device_type_)) { |
| LOG(ERROR) << "function " << GetFunctionName() |
| << " got an unexpected network type " << device_type_; |
| return false; |
| } |
| return true; |
| } |
| |
| NetworkFunction::DataType NetworkFunction::EvalImpl() const { |
| DataType results; |
| base::FilePath net_dev_pattern = |
| Context::Get()->root_dir().Append("sys/class/net/*"); |
| for (const auto& net_dev_path : Glob(net_dev_pattern)) { |
| auto node_res = GetDeviceBusDataFromSysfsNode(net_dev_path); |
| if (node_res) { |
| results.Append(std::move(*node_res)); |
| } |
| } |
| |
| return results; |
| } |
| |
| void NetworkFunction::PostHelperEvalImpl(DataType* results) const { |
| const std::optional<std::string> target_type = GetNetworkType(); |
| const auto devices_type = GetDevicesType(); |
| auto helper_results = std::move(*results); |
| *results = DataType(); |
| |
| for (auto& helper_result : helper_results) { |
| auto& dict = helper_result.GetDict(); |
| auto* path = dict.FindString("path"); |
| CHECK(path); |
| const std::string interface = base::FilePath{*path}.BaseName().value(); |
| auto it = devices_type.find(interface); |
| if (it == devices_type.end()) { |
| LOG(ERROR) << "Cannot get type of interface " << interface; |
| continue; |
| } |
| if (target_type && target_type.value() != it->second) { |
| VLOG(3) << "Interface " << interface << " doesn't match the target type " |
| << target_type.value(); |
| continue; |
| } |
| // (b/327536271) Only filter removable for ethernet because other network |
| // types might be removable as intended. |
| if (it->second == shill::kTypeEthernet && |
| IsRemovableBusDevice(helper_result.GetDict())) { |
| continue; |
| } |
| CHECK(!dict.FindString("type")); |
| dict.Set("type", it->second); |
| results->Append(std::move(helper_result)); |
| } |
| } |
| |
| std::optional<std::string> NetworkFunction::GetNetworkType() const { |
| if (device_type_.empty()) { |
| return std::nullopt; |
| } |
| return device_type_; |
| } |
| |
| } // namespace runtime_probe |