1275f7c39SAndrew Jeffery #include "MCTPEndpoint.hpp" 2275f7c39SAndrew Jeffery 3275f7c39SAndrew Jeffery #include "Utils.hpp" 4275f7c39SAndrew Jeffery #include "VariantVisitors.hpp" 5275f7c39SAndrew Jeffery 6275f7c39SAndrew Jeffery #include <bits/fs_dir.h> 7275f7c39SAndrew Jeffery 8275f7c39SAndrew Jeffery #include <boost/system/detail/errc.hpp> 9275f7c39SAndrew Jeffery #include <phosphor-logging/lg2.hpp> 10275f7c39SAndrew Jeffery #include <sdbusplus/asio/connection.hpp> 11275f7c39SAndrew Jeffery #include <sdbusplus/bus.hpp> 12275f7c39SAndrew Jeffery #include <sdbusplus/bus/match.hpp> 13275f7c39SAndrew Jeffery #include <sdbusplus/exception.hpp> 14275f7c39SAndrew Jeffery #include <sdbusplus/message.hpp> 15275f7c39SAndrew Jeffery #include <sdbusplus/message/native_types.hpp> 16275f7c39SAndrew Jeffery 17275f7c39SAndrew Jeffery #include <cassert> 18275f7c39SAndrew Jeffery #include <charconv> 19275f7c39SAndrew Jeffery #include <cstdint> 20275f7c39SAndrew Jeffery #include <exception> 21275f7c39SAndrew Jeffery #include <filesystem> 22275f7c39SAndrew Jeffery #include <format> 23275f7c39SAndrew Jeffery #include <functional> 24275f7c39SAndrew Jeffery #include <map> 25275f7c39SAndrew Jeffery #include <memory> 26275f7c39SAndrew Jeffery #include <optional> 27275f7c39SAndrew Jeffery #include <set> 28275f7c39SAndrew Jeffery #include <stdexcept> 29275f7c39SAndrew Jeffery #include <string> 30275f7c39SAndrew Jeffery #include <system_error> 31275f7c39SAndrew Jeffery #include <utility> 32275f7c39SAndrew Jeffery #include <variant> 33275f7c39SAndrew Jeffery #include <vector> 34275f7c39SAndrew Jeffery 35275f7c39SAndrew Jeffery PHOSPHOR_LOG2_USING; 36275f7c39SAndrew Jeffery 37*19d1fda6SThu Nguyen static constexpr const char* mctpdBusName = "au.com.codeconstruct.MCTP1"; 38*19d1fda6SThu Nguyen static constexpr const char* mctpdControlPath = "/au/com/codeconstruct/mctp1"; 39275f7c39SAndrew Jeffery static constexpr const char* mctpdControlInterface = 40*19d1fda6SThu Nguyen "au.com.codeconstruct.MCTP.BusOwner1"; 41275f7c39SAndrew Jeffery static constexpr const char* mctpdEndpointControlInterface = 42*19d1fda6SThu Nguyen "au.com.codeconstruct.MCTP.Endpoint1"; 43275f7c39SAndrew Jeffery 44275f7c39SAndrew Jeffery MCTPDDevice::MCTPDDevice( 45275f7c39SAndrew Jeffery const std::shared_ptr<sdbusplus::asio::connection>& connection, 46275f7c39SAndrew Jeffery const std::string& interface, const std::vector<uint8_t>& physaddr) : 47275f7c39SAndrew Jeffery connection(connection), interface(interface), physaddr(physaddr) 48275f7c39SAndrew Jeffery {} 49275f7c39SAndrew Jeffery 50275f7c39SAndrew Jeffery void MCTPDDevice::onEndpointInterfacesRemoved( 51275f7c39SAndrew Jeffery const std::weak_ptr<MCTPDDevice>& weak, const std::string& objpath, 52275f7c39SAndrew Jeffery sdbusplus::message_t& msg) 53275f7c39SAndrew Jeffery { 54275f7c39SAndrew Jeffery auto path = msg.unpack<sdbusplus::message::object_path>(); 55275f7c39SAndrew Jeffery assert(path.str == objpath); 56275f7c39SAndrew Jeffery 57275f7c39SAndrew Jeffery auto removedIfaces = msg.unpack<std::set<std::string>>(); 58275f7c39SAndrew Jeffery if (!removedIfaces.contains(mctpdEndpointControlInterface)) 59275f7c39SAndrew Jeffery { 60275f7c39SAndrew Jeffery return; 61275f7c39SAndrew Jeffery } 62275f7c39SAndrew Jeffery 63275f7c39SAndrew Jeffery if (auto self = weak.lock()) 64275f7c39SAndrew Jeffery { 65275f7c39SAndrew Jeffery self->endpointRemoved(); 66275f7c39SAndrew Jeffery } 67275f7c39SAndrew Jeffery else 68275f7c39SAndrew Jeffery { 69275f7c39SAndrew Jeffery info( 70275f7c39SAndrew Jeffery "Device for inventory at '{INVENTORY_PATH}' was destroyed concurrent to endpoint removal", 71275f7c39SAndrew Jeffery "INVENTORY_PATH", objpath); 72275f7c39SAndrew Jeffery } 73275f7c39SAndrew Jeffery } 74275f7c39SAndrew Jeffery 75275f7c39SAndrew Jeffery void MCTPDDevice::finaliseEndpoint( 76275f7c39SAndrew Jeffery const std::string& objpath, uint8_t eid, int network, 77275f7c39SAndrew Jeffery std::function<void(const std::error_code& ec, 78275f7c39SAndrew Jeffery const std::shared_ptr<MCTPEndpoint>& ep)>& added) 79275f7c39SAndrew Jeffery { 80275f7c39SAndrew Jeffery const auto matchSpec = 81275f7c39SAndrew Jeffery sdbusplus::bus::match::rules::interfacesRemovedAtPath(objpath); 82275f7c39SAndrew Jeffery removeMatch = std::make_unique<sdbusplus::bus::match_t>( 83275f7c39SAndrew Jeffery *connection, matchSpec, 84275f7c39SAndrew Jeffery std::bind_front(MCTPDDevice::onEndpointInterfacesRemoved, 85275f7c39SAndrew Jeffery weak_from_this(), objpath)); 86275f7c39SAndrew Jeffery endpoint = std::make_shared<MCTPDEndpoint>(shared_from_this(), connection, 87275f7c39SAndrew Jeffery objpath, network, eid); 88275f7c39SAndrew Jeffery added({}, endpoint); 89275f7c39SAndrew Jeffery } 90275f7c39SAndrew Jeffery 91275f7c39SAndrew Jeffery void MCTPDDevice::setup( 92275f7c39SAndrew Jeffery std::function<void(const std::error_code& ec, 93275f7c39SAndrew Jeffery const std::shared_ptr<MCTPEndpoint>& ep)>&& added) 94275f7c39SAndrew Jeffery { 95275f7c39SAndrew Jeffery // Use a lambda to separate state validation from business logic, 96275f7c39SAndrew Jeffery // where the business logic for a successful setup() is encoded in 97275f7c39SAndrew Jeffery // MctpdDevice::finaliseEndpoint() 98275f7c39SAndrew Jeffery auto onSetup = [weak{weak_from_this()}, added{std::move(added)}]( 99275f7c39SAndrew Jeffery const boost::system::error_code& ec, uint8_t eid, 100275f7c39SAndrew Jeffery int network, const std::string& objpath, 101275f7c39SAndrew Jeffery bool allocated [[maybe_unused]]) mutable { 102275f7c39SAndrew Jeffery if (ec) 103275f7c39SAndrew Jeffery { 104275f7c39SAndrew Jeffery added(ec, {}); 105275f7c39SAndrew Jeffery return; 106275f7c39SAndrew Jeffery } 107275f7c39SAndrew Jeffery 108275f7c39SAndrew Jeffery if (auto self = weak.lock()) 109275f7c39SAndrew Jeffery { 110275f7c39SAndrew Jeffery self->finaliseEndpoint(objpath, eid, network, added); 111275f7c39SAndrew Jeffery } 112275f7c39SAndrew Jeffery else 113275f7c39SAndrew Jeffery { 114275f7c39SAndrew Jeffery info( 115275f7c39SAndrew Jeffery "Device object for inventory at '{INVENTORY_PATH}' was destroyed concurrent to completion of its endpoint setup", 116275f7c39SAndrew Jeffery "INVENTORY_PATH", objpath); 117275f7c39SAndrew Jeffery } 118275f7c39SAndrew Jeffery }; 119*19d1fda6SThu Nguyen connection->async_method_call( 120*19d1fda6SThu Nguyen onSetup, mctpdBusName, 121*19d1fda6SThu Nguyen mctpdControlPath + std::string("/interfaces/") + interface, 122*19d1fda6SThu Nguyen mctpdControlInterface, "AssignEndpoint", physaddr); 123275f7c39SAndrew Jeffery } 124275f7c39SAndrew Jeffery 125275f7c39SAndrew Jeffery void MCTPDDevice::endpointRemoved() 126275f7c39SAndrew Jeffery { 127275f7c39SAndrew Jeffery if (endpoint) 128275f7c39SAndrew Jeffery { 129275f7c39SAndrew Jeffery debug("Endpoint removed @ [ {MCTP_ENDPOINT} ]", "MCTP_ENDPOINT", 130275f7c39SAndrew Jeffery endpoint->describe()); 131275f7c39SAndrew Jeffery removeMatch.reset(); 132275f7c39SAndrew Jeffery endpoint->removed(); 133275f7c39SAndrew Jeffery endpoint.reset(); 134275f7c39SAndrew Jeffery } 135275f7c39SAndrew Jeffery } 136275f7c39SAndrew Jeffery 137275f7c39SAndrew Jeffery void MCTPDDevice::remove() 138275f7c39SAndrew Jeffery { 139275f7c39SAndrew Jeffery if (endpoint) 140275f7c39SAndrew Jeffery { 141275f7c39SAndrew Jeffery debug("Removing endpoint @ [ {MCTP_ENDPOINT} ]", "MCTP_ENDPOINT", 142275f7c39SAndrew Jeffery endpoint->describe()); 143275f7c39SAndrew Jeffery endpoint->remove(); 144275f7c39SAndrew Jeffery } 145275f7c39SAndrew Jeffery } 146275f7c39SAndrew Jeffery 147275f7c39SAndrew Jeffery std::string MCTPDDevice::describe() const 148275f7c39SAndrew Jeffery { 149275f7c39SAndrew Jeffery std::string description = std::format("interface: {}", interface); 150275f7c39SAndrew Jeffery if (!physaddr.empty()) 151275f7c39SAndrew Jeffery { 152275f7c39SAndrew Jeffery description.append(", address: 0x [ "); 153275f7c39SAndrew Jeffery auto it = physaddr.begin(); 154275f7c39SAndrew Jeffery for (; it != physaddr.end() - 1; it++) 155275f7c39SAndrew Jeffery { 156275f7c39SAndrew Jeffery description.append(std::format("{:02x} ", *it)); 157275f7c39SAndrew Jeffery } 158275f7c39SAndrew Jeffery description.append(std::format("{:02x} ]", *it)); 159275f7c39SAndrew Jeffery } 160275f7c39SAndrew Jeffery return description; 161275f7c39SAndrew Jeffery } 162275f7c39SAndrew Jeffery 163275f7c39SAndrew Jeffery std::string MCTPDEndpoint::path(const std::shared_ptr<MCTPEndpoint>& ep) 164275f7c39SAndrew Jeffery { 165*19d1fda6SThu Nguyen return std::format("{}/networks/{}/endpoints/{}", mctpdControlPath, 166*19d1fda6SThu Nguyen ep->network(), ep->eid()); 167275f7c39SAndrew Jeffery } 168275f7c39SAndrew Jeffery 169275f7c39SAndrew Jeffery void MCTPDEndpoint::onMctpEndpointChange(sdbusplus::message_t& msg) 170275f7c39SAndrew Jeffery { 171275f7c39SAndrew Jeffery auto [iface, changed, _] = 172275f7c39SAndrew Jeffery msg.unpack<std::string, std::map<std::string, BasicVariantType>, 173275f7c39SAndrew Jeffery std::vector<std::string>>(); 174275f7c39SAndrew Jeffery if (iface != mctpdEndpointControlInterface) 175275f7c39SAndrew Jeffery { 176275f7c39SAndrew Jeffery return; 177275f7c39SAndrew Jeffery } 178275f7c39SAndrew Jeffery 179275f7c39SAndrew Jeffery auto it = changed.find("Connectivity"); 180275f7c39SAndrew Jeffery if (it == changed.end()) 181275f7c39SAndrew Jeffery { 182275f7c39SAndrew Jeffery return; 183275f7c39SAndrew Jeffery } 184275f7c39SAndrew Jeffery 185275f7c39SAndrew Jeffery updateEndpointConnectivity(std::get<std::string>(it->second)); 186275f7c39SAndrew Jeffery } 187275f7c39SAndrew Jeffery 188275f7c39SAndrew Jeffery void MCTPDEndpoint::updateEndpointConnectivity(const std::string& connectivity) 189275f7c39SAndrew Jeffery { 190275f7c39SAndrew Jeffery if (connectivity == "Degraded") 191275f7c39SAndrew Jeffery { 192275f7c39SAndrew Jeffery if (notifyDegraded) 193275f7c39SAndrew Jeffery { 194275f7c39SAndrew Jeffery notifyDegraded(shared_from_this()); 195275f7c39SAndrew Jeffery } 196275f7c39SAndrew Jeffery } 197275f7c39SAndrew Jeffery else if (connectivity == "Available") 198275f7c39SAndrew Jeffery { 199275f7c39SAndrew Jeffery if (notifyAvailable) 200275f7c39SAndrew Jeffery { 201275f7c39SAndrew Jeffery notifyAvailable(shared_from_this()); 202275f7c39SAndrew Jeffery } 203275f7c39SAndrew Jeffery } 204275f7c39SAndrew Jeffery else 205275f7c39SAndrew Jeffery { 206275f7c39SAndrew Jeffery debug("Unrecognised connectivity state: '{CONNECTIVITY_STATE}'", 207275f7c39SAndrew Jeffery "CONNECTIVITY_STATE", connectivity); 208275f7c39SAndrew Jeffery } 209275f7c39SAndrew Jeffery } 210275f7c39SAndrew Jeffery 211275f7c39SAndrew Jeffery int MCTPDEndpoint::network() const 212275f7c39SAndrew Jeffery { 213275f7c39SAndrew Jeffery return mctp.network; 214275f7c39SAndrew Jeffery } 215275f7c39SAndrew Jeffery 216275f7c39SAndrew Jeffery uint8_t MCTPDEndpoint::eid() const 217275f7c39SAndrew Jeffery { 218275f7c39SAndrew Jeffery return mctp.eid; 219275f7c39SAndrew Jeffery } 220275f7c39SAndrew Jeffery 221275f7c39SAndrew Jeffery void MCTPDEndpoint::subscribe(Event&& degraded, Event&& available, 222275f7c39SAndrew Jeffery Event&& removed) 223275f7c39SAndrew Jeffery { 224275f7c39SAndrew Jeffery const auto matchSpec = 225275f7c39SAndrew Jeffery sdbusplus::bus::match::rules::propertiesChangedNamespace( 226275f7c39SAndrew Jeffery objpath.str, mctpdEndpointControlInterface); 227275f7c39SAndrew Jeffery 228275f7c39SAndrew Jeffery this->notifyDegraded = std::move(degraded); 229275f7c39SAndrew Jeffery this->notifyAvailable = std::move(available); 230275f7c39SAndrew Jeffery this->notifyRemoved = std::move(removed); 231275f7c39SAndrew Jeffery 232275f7c39SAndrew Jeffery try 233275f7c39SAndrew Jeffery { 234275f7c39SAndrew Jeffery connectivityMatch.emplace( 235275f7c39SAndrew Jeffery static_cast<sdbusplus::bus_t&>(*connection), matchSpec, 236275f7c39SAndrew Jeffery [weak{weak_from_this()}, 237275f7c39SAndrew Jeffery path{objpath.str}](sdbusplus::message_t& msg) { 238275f7c39SAndrew Jeffery if (auto self = weak.lock()) 239275f7c39SAndrew Jeffery { 240275f7c39SAndrew Jeffery self->onMctpEndpointChange(msg); 241275f7c39SAndrew Jeffery } 242275f7c39SAndrew Jeffery else 243275f7c39SAndrew Jeffery { 244275f7c39SAndrew Jeffery info( 245275f7c39SAndrew Jeffery "The endpoint for the device at inventory path '{INVENTORY_PATH}' was destroyed concurrent to the removal of its state change match", 246275f7c39SAndrew Jeffery "INVENTORY_PATH", path); 247275f7c39SAndrew Jeffery } 248275f7c39SAndrew Jeffery }); 249275f7c39SAndrew Jeffery connection->async_method_call( 250275f7c39SAndrew Jeffery [weak{weak_from_this()}, 251275f7c39SAndrew Jeffery path{objpath.str}](const boost::system::error_code& ec, 252275f7c39SAndrew Jeffery const std::variant<std::string>& value) { 253275f7c39SAndrew Jeffery if (ec) 254275f7c39SAndrew Jeffery { 255275f7c39SAndrew Jeffery debug( 256275f7c39SAndrew Jeffery "Failed to get current connectivity state: {ERROR_MESSAGE}", 257275f7c39SAndrew Jeffery "ERROR_MESSAGE", ec.message(), "ERROR_CATEGORY", 258275f7c39SAndrew Jeffery ec.category().name(), "ERROR_CODE", ec.value()); 259275f7c39SAndrew Jeffery return; 260275f7c39SAndrew Jeffery } 261275f7c39SAndrew Jeffery 262275f7c39SAndrew Jeffery if (auto self = weak.lock()) 263275f7c39SAndrew Jeffery { 264275f7c39SAndrew Jeffery const std::string& connectivity = 265275f7c39SAndrew Jeffery std::get<std::string>(value); 266275f7c39SAndrew Jeffery self->updateEndpointConnectivity(connectivity); 267275f7c39SAndrew Jeffery } 268275f7c39SAndrew Jeffery else 269275f7c39SAndrew Jeffery { 270275f7c39SAndrew Jeffery info( 271275f7c39SAndrew Jeffery "The endpoint for the device at inventory path '{INVENTORY_PATH}' was destroyed concurrent to the completion of its connectivity state query", 272275f7c39SAndrew Jeffery "INVENTORY_PATH", path); 273275f7c39SAndrew Jeffery } 274275f7c39SAndrew Jeffery }, 275275f7c39SAndrew Jeffery mctpdBusName, objpath.str, "org.freedesktop.DBus.Properties", "Get", 276275f7c39SAndrew Jeffery mctpdEndpointControlInterface, "Connectivity"); 277275f7c39SAndrew Jeffery } 278275f7c39SAndrew Jeffery catch (const sdbusplus::exception::SdBusError& err) 279275f7c39SAndrew Jeffery { 280275f7c39SAndrew Jeffery this->notifyDegraded = nullptr; 281275f7c39SAndrew Jeffery this->notifyAvailable = nullptr; 282275f7c39SAndrew Jeffery this->notifyRemoved = nullptr; 283275f7c39SAndrew Jeffery std::throw_with_nested( 284275f7c39SAndrew Jeffery MCTPException("Failed to register connectivity signal match")); 285275f7c39SAndrew Jeffery } 286275f7c39SAndrew Jeffery } 287275f7c39SAndrew Jeffery 288275f7c39SAndrew Jeffery void MCTPDEndpoint::remove() 289275f7c39SAndrew Jeffery { 290275f7c39SAndrew Jeffery connection->async_method_call( 291275f7c39SAndrew Jeffery [self{shared_from_this()}](const boost::system::error_code& ec) { 292275f7c39SAndrew Jeffery if (ec) 293275f7c39SAndrew Jeffery { 294275f7c39SAndrew Jeffery debug("Failed to remove endpoint @ [ {MCTP_ENDPOINT} ]", 295275f7c39SAndrew Jeffery "MCTP_ENDPOINT", self->describe()); 296275f7c39SAndrew Jeffery return; 297275f7c39SAndrew Jeffery } 298275f7c39SAndrew Jeffery }, 299275f7c39SAndrew Jeffery mctpdBusName, objpath.str, mctpdEndpointControlInterface, "Remove"); 300275f7c39SAndrew Jeffery } 301275f7c39SAndrew Jeffery 302275f7c39SAndrew Jeffery void MCTPDEndpoint::removed() 303275f7c39SAndrew Jeffery { 304275f7c39SAndrew Jeffery if (notifyRemoved) 305275f7c39SAndrew Jeffery { 306275f7c39SAndrew Jeffery notifyRemoved(shared_from_this()); 307275f7c39SAndrew Jeffery } 308275f7c39SAndrew Jeffery } 309275f7c39SAndrew Jeffery 310275f7c39SAndrew Jeffery std::string MCTPDEndpoint::describe() const 311275f7c39SAndrew Jeffery { 312275f7c39SAndrew Jeffery return std::format("network: {}, EID: {} | {}", mctp.network, mctp.eid, 313275f7c39SAndrew Jeffery dev->describe()); 314275f7c39SAndrew Jeffery } 315275f7c39SAndrew Jeffery 316275f7c39SAndrew Jeffery std::shared_ptr<MCTPDevice> MCTPDEndpoint::device() const 317275f7c39SAndrew Jeffery { 318275f7c39SAndrew Jeffery return dev; 319275f7c39SAndrew Jeffery } 320275f7c39SAndrew Jeffery 321275f7c39SAndrew Jeffery std::optional<SensorBaseConfigMap> 322275f7c39SAndrew Jeffery I2CMCTPDDevice::match(const SensorData& config) 323275f7c39SAndrew Jeffery { 324275f7c39SAndrew Jeffery auto iface = config.find(configInterfaceName(configType)); 325275f7c39SAndrew Jeffery if (iface == config.end()) 326275f7c39SAndrew Jeffery { 327275f7c39SAndrew Jeffery return std::nullopt; 328275f7c39SAndrew Jeffery } 329275f7c39SAndrew Jeffery return iface->second; 330275f7c39SAndrew Jeffery } 331275f7c39SAndrew Jeffery 332275f7c39SAndrew Jeffery bool I2CMCTPDDevice::match(const std::set<std::string>& interfaces) 333275f7c39SAndrew Jeffery { 334275f7c39SAndrew Jeffery return interfaces.contains(configInterfaceName(configType)); 335275f7c39SAndrew Jeffery } 336275f7c39SAndrew Jeffery 337275f7c39SAndrew Jeffery std::shared_ptr<I2CMCTPDDevice> I2CMCTPDDevice::from( 338275f7c39SAndrew Jeffery const std::shared_ptr<sdbusplus::asio::connection>& connection, 339275f7c39SAndrew Jeffery const SensorBaseConfigMap& iface) 340275f7c39SAndrew Jeffery { 341275f7c39SAndrew Jeffery auto mType = iface.find("Type"); 342275f7c39SAndrew Jeffery if (mType == iface.end()) 343275f7c39SAndrew Jeffery { 344275f7c39SAndrew Jeffery throw std::invalid_argument( 345275f7c39SAndrew Jeffery "No 'Type' member found for provided configuration object"); 346275f7c39SAndrew Jeffery } 347275f7c39SAndrew Jeffery 348275f7c39SAndrew Jeffery auto type = std::visit(VariantToStringVisitor(), mType->second); 349275f7c39SAndrew Jeffery if (type != configType) 350275f7c39SAndrew Jeffery { 351275f7c39SAndrew Jeffery throw std::invalid_argument("Not an SMBus device"); 352275f7c39SAndrew Jeffery } 353275f7c39SAndrew Jeffery 354275f7c39SAndrew Jeffery auto mAddress = iface.find("Address"); 355275f7c39SAndrew Jeffery auto mBus = iface.find("Bus"); 356275f7c39SAndrew Jeffery auto mName = iface.find("Name"); 357275f7c39SAndrew Jeffery if (mAddress == iface.end() || mBus == iface.end() || mName == iface.end()) 358275f7c39SAndrew Jeffery { 359275f7c39SAndrew Jeffery throw std::invalid_argument( 360275f7c39SAndrew Jeffery "Configuration object violates MCTPI2CTarget schema"); 361275f7c39SAndrew Jeffery } 362275f7c39SAndrew Jeffery 363275f7c39SAndrew Jeffery auto sAddress = std::visit(VariantToStringVisitor(), mAddress->second); 364275f7c39SAndrew Jeffery std::uint8_t address{}; 365275f7c39SAndrew Jeffery auto [aptr, aec] = std::from_chars( 366275f7c39SAndrew Jeffery sAddress.data(), sAddress.data() + sAddress.size(), address); 367275f7c39SAndrew Jeffery if (aec != std::errc{}) 368275f7c39SAndrew Jeffery { 369275f7c39SAndrew Jeffery throw std::invalid_argument("Bad device address"); 370275f7c39SAndrew Jeffery } 371275f7c39SAndrew Jeffery 372275f7c39SAndrew Jeffery auto sBus = std::visit(VariantToStringVisitor(), mBus->second); 373275f7c39SAndrew Jeffery int bus{}; 374275f7c39SAndrew Jeffery auto [bptr, 375275f7c39SAndrew Jeffery bec] = std::from_chars(sBus.data(), sBus.data() + sBus.size(), bus); 376275f7c39SAndrew Jeffery if (bec != std::errc{}) 377275f7c39SAndrew Jeffery { 378275f7c39SAndrew Jeffery throw std::invalid_argument("Bad bus index"); 379275f7c39SAndrew Jeffery } 380275f7c39SAndrew Jeffery 381275f7c39SAndrew Jeffery try 382275f7c39SAndrew Jeffery { 383275f7c39SAndrew Jeffery return std::make_shared<I2CMCTPDDevice>(connection, bus, address); 384275f7c39SAndrew Jeffery } 385275f7c39SAndrew Jeffery catch (const MCTPException& ex) 386275f7c39SAndrew Jeffery { 387275f7c39SAndrew Jeffery warning( 388275f7c39SAndrew Jeffery "Failed to create I2CMCTPDDevice at [ bus: {I2C_BUS}, address: {I2C_ADDRESS} ]: {EXCEPTION}", 389275f7c39SAndrew Jeffery "I2C_BUS", bus, "I2C_ADDRESS", address, "EXCEPTION", ex); 390275f7c39SAndrew Jeffery return {}; 391275f7c39SAndrew Jeffery } 392275f7c39SAndrew Jeffery } 393275f7c39SAndrew Jeffery 394275f7c39SAndrew Jeffery std::string I2CMCTPDDevice::interfaceFromBus(int bus) 395275f7c39SAndrew Jeffery { 396275f7c39SAndrew Jeffery std::filesystem::path netdir = 397275f7c39SAndrew Jeffery std::format("/sys/bus/i2c/devices/i2c-{}/net", bus); 398275f7c39SAndrew Jeffery std::error_code ec; 399275f7c39SAndrew Jeffery std::filesystem::directory_iterator it(netdir, ec); 400275f7c39SAndrew Jeffery if (ec || it == std::filesystem::end(it)) 401275f7c39SAndrew Jeffery { 402275f7c39SAndrew Jeffery error("No net device associated with I2C bus {I2C_BUS} at {NET_DEVICE}", 403275f7c39SAndrew Jeffery "I2C_BUS", bus, "NET_DEVICE", netdir); 404275f7c39SAndrew Jeffery throw MCTPException("Bus is not configured as an MCTP interface"); 405275f7c39SAndrew Jeffery } 406275f7c39SAndrew Jeffery 407275f7c39SAndrew Jeffery return it->path().filename(); 408275f7c39SAndrew Jeffery } 409