1*275f7c39SAndrew Jeffery #include "MCTPEndpoint.hpp" 2*275f7c39SAndrew Jeffery 3*275f7c39SAndrew Jeffery #include "Utils.hpp" 4*275f7c39SAndrew Jeffery #include "VariantVisitors.hpp" 5*275f7c39SAndrew Jeffery 6*275f7c39SAndrew Jeffery #include <bits/fs_dir.h> 7*275f7c39SAndrew Jeffery 8*275f7c39SAndrew Jeffery #include <boost/system/detail/errc.hpp> 9*275f7c39SAndrew Jeffery #include <phosphor-logging/lg2.hpp> 10*275f7c39SAndrew Jeffery #include <sdbusplus/asio/connection.hpp> 11*275f7c39SAndrew Jeffery #include <sdbusplus/bus.hpp> 12*275f7c39SAndrew Jeffery #include <sdbusplus/bus/match.hpp> 13*275f7c39SAndrew Jeffery #include <sdbusplus/exception.hpp> 14*275f7c39SAndrew Jeffery #include <sdbusplus/message.hpp> 15*275f7c39SAndrew Jeffery #include <sdbusplus/message/native_types.hpp> 16*275f7c39SAndrew Jeffery 17*275f7c39SAndrew Jeffery #include <cassert> 18*275f7c39SAndrew Jeffery #include <charconv> 19*275f7c39SAndrew Jeffery #include <cstdint> 20*275f7c39SAndrew Jeffery #include <exception> 21*275f7c39SAndrew Jeffery #include <filesystem> 22*275f7c39SAndrew Jeffery #include <format> 23*275f7c39SAndrew Jeffery #include <functional> 24*275f7c39SAndrew Jeffery #include <map> 25*275f7c39SAndrew Jeffery #include <memory> 26*275f7c39SAndrew Jeffery #include <optional> 27*275f7c39SAndrew Jeffery #include <set> 28*275f7c39SAndrew Jeffery #include <stdexcept> 29*275f7c39SAndrew Jeffery #include <string> 30*275f7c39SAndrew Jeffery #include <system_error> 31*275f7c39SAndrew Jeffery #include <utility> 32*275f7c39SAndrew Jeffery #include <variant> 33*275f7c39SAndrew Jeffery #include <vector> 34*275f7c39SAndrew Jeffery 35*275f7c39SAndrew Jeffery PHOSPHOR_LOG2_USING; 36*275f7c39SAndrew Jeffery 37*275f7c39SAndrew Jeffery static constexpr const char* mctpdBusName = "xyz.openbmc_project.MCTP"; 38*275f7c39SAndrew Jeffery static constexpr const char* mctpdControlPath = "/xyz/openbmc_project/mctp"; 39*275f7c39SAndrew Jeffery static constexpr const char* mctpdControlInterface = 40*275f7c39SAndrew Jeffery "au.com.CodeConstruct.MCTP"; 41*275f7c39SAndrew Jeffery static constexpr const char* mctpdEndpointControlInterface = 42*275f7c39SAndrew Jeffery "au.com.CodeConstruct.MCTP.Endpoint"; 43*275f7c39SAndrew Jeffery 44*275f7c39SAndrew Jeffery MCTPDDevice::MCTPDDevice( 45*275f7c39SAndrew Jeffery const std::shared_ptr<sdbusplus::asio::connection>& connection, 46*275f7c39SAndrew Jeffery const std::string& interface, const std::vector<uint8_t>& physaddr) : 47*275f7c39SAndrew Jeffery connection(connection), interface(interface), physaddr(physaddr) 48*275f7c39SAndrew Jeffery {} 49*275f7c39SAndrew Jeffery 50*275f7c39SAndrew Jeffery void MCTPDDevice::onEndpointInterfacesRemoved( 51*275f7c39SAndrew Jeffery const std::weak_ptr<MCTPDDevice>& weak, const std::string& objpath, 52*275f7c39SAndrew Jeffery sdbusplus::message_t& msg) 53*275f7c39SAndrew Jeffery { 54*275f7c39SAndrew Jeffery auto path = msg.unpack<sdbusplus::message::object_path>(); 55*275f7c39SAndrew Jeffery assert(path.str == objpath); 56*275f7c39SAndrew Jeffery 57*275f7c39SAndrew Jeffery auto removedIfaces = msg.unpack<std::set<std::string>>(); 58*275f7c39SAndrew Jeffery if (!removedIfaces.contains(mctpdEndpointControlInterface)) 59*275f7c39SAndrew Jeffery { 60*275f7c39SAndrew Jeffery return; 61*275f7c39SAndrew Jeffery } 62*275f7c39SAndrew Jeffery 63*275f7c39SAndrew Jeffery if (auto self = weak.lock()) 64*275f7c39SAndrew Jeffery { 65*275f7c39SAndrew Jeffery self->endpointRemoved(); 66*275f7c39SAndrew Jeffery } 67*275f7c39SAndrew Jeffery else 68*275f7c39SAndrew Jeffery { 69*275f7c39SAndrew Jeffery info( 70*275f7c39SAndrew Jeffery "Device for inventory at '{INVENTORY_PATH}' was destroyed concurrent to endpoint removal", 71*275f7c39SAndrew Jeffery "INVENTORY_PATH", objpath); 72*275f7c39SAndrew Jeffery } 73*275f7c39SAndrew Jeffery } 74*275f7c39SAndrew Jeffery 75*275f7c39SAndrew Jeffery void MCTPDDevice::finaliseEndpoint( 76*275f7c39SAndrew Jeffery const std::string& objpath, uint8_t eid, int network, 77*275f7c39SAndrew Jeffery std::function<void(const std::error_code& ec, 78*275f7c39SAndrew Jeffery const std::shared_ptr<MCTPEndpoint>& ep)>& added) 79*275f7c39SAndrew Jeffery { 80*275f7c39SAndrew Jeffery const auto matchSpec = 81*275f7c39SAndrew Jeffery sdbusplus::bus::match::rules::interfacesRemovedAtPath(objpath); 82*275f7c39SAndrew Jeffery removeMatch = std::make_unique<sdbusplus::bus::match_t>( 83*275f7c39SAndrew Jeffery *connection, matchSpec, 84*275f7c39SAndrew Jeffery std::bind_front(MCTPDDevice::onEndpointInterfacesRemoved, 85*275f7c39SAndrew Jeffery weak_from_this(), objpath)); 86*275f7c39SAndrew Jeffery endpoint = std::make_shared<MCTPDEndpoint>(shared_from_this(), connection, 87*275f7c39SAndrew Jeffery objpath, network, eid); 88*275f7c39SAndrew Jeffery added({}, endpoint); 89*275f7c39SAndrew Jeffery } 90*275f7c39SAndrew Jeffery 91*275f7c39SAndrew Jeffery void MCTPDDevice::setup( 92*275f7c39SAndrew Jeffery std::function<void(const std::error_code& ec, 93*275f7c39SAndrew Jeffery const std::shared_ptr<MCTPEndpoint>& ep)>&& added) 94*275f7c39SAndrew Jeffery { 95*275f7c39SAndrew Jeffery // Use a lambda to separate state validation from business logic, 96*275f7c39SAndrew Jeffery // where the business logic for a successful setup() is encoded in 97*275f7c39SAndrew Jeffery // MctpdDevice::finaliseEndpoint() 98*275f7c39SAndrew Jeffery auto onSetup = [weak{weak_from_this()}, added{std::move(added)}]( 99*275f7c39SAndrew Jeffery const boost::system::error_code& ec, uint8_t eid, 100*275f7c39SAndrew Jeffery int network, const std::string& objpath, 101*275f7c39SAndrew Jeffery bool allocated [[maybe_unused]]) mutable { 102*275f7c39SAndrew Jeffery if (ec) 103*275f7c39SAndrew Jeffery { 104*275f7c39SAndrew Jeffery added(ec, {}); 105*275f7c39SAndrew Jeffery return; 106*275f7c39SAndrew Jeffery } 107*275f7c39SAndrew Jeffery 108*275f7c39SAndrew Jeffery if (auto self = weak.lock()) 109*275f7c39SAndrew Jeffery { 110*275f7c39SAndrew Jeffery self->finaliseEndpoint(objpath, eid, network, added); 111*275f7c39SAndrew Jeffery } 112*275f7c39SAndrew Jeffery else 113*275f7c39SAndrew Jeffery { 114*275f7c39SAndrew Jeffery info( 115*275f7c39SAndrew Jeffery "Device object for inventory at '{INVENTORY_PATH}' was destroyed concurrent to completion of its endpoint setup", 116*275f7c39SAndrew Jeffery "INVENTORY_PATH", objpath); 117*275f7c39SAndrew Jeffery } 118*275f7c39SAndrew Jeffery }; 119*275f7c39SAndrew Jeffery connection->async_method_call(onSetup, mctpdBusName, mctpdControlPath, 120*275f7c39SAndrew Jeffery mctpdControlInterface, "AssignEndpoint", 121*275f7c39SAndrew Jeffery interface, physaddr); 122*275f7c39SAndrew Jeffery } 123*275f7c39SAndrew Jeffery 124*275f7c39SAndrew Jeffery void MCTPDDevice::endpointRemoved() 125*275f7c39SAndrew Jeffery { 126*275f7c39SAndrew Jeffery if (endpoint) 127*275f7c39SAndrew Jeffery { 128*275f7c39SAndrew Jeffery debug("Endpoint removed @ [ {MCTP_ENDPOINT} ]", "MCTP_ENDPOINT", 129*275f7c39SAndrew Jeffery endpoint->describe()); 130*275f7c39SAndrew Jeffery removeMatch.reset(); 131*275f7c39SAndrew Jeffery endpoint->removed(); 132*275f7c39SAndrew Jeffery endpoint.reset(); 133*275f7c39SAndrew Jeffery } 134*275f7c39SAndrew Jeffery } 135*275f7c39SAndrew Jeffery 136*275f7c39SAndrew Jeffery void MCTPDDevice::remove() 137*275f7c39SAndrew Jeffery { 138*275f7c39SAndrew Jeffery if (endpoint) 139*275f7c39SAndrew Jeffery { 140*275f7c39SAndrew Jeffery debug("Removing endpoint @ [ {MCTP_ENDPOINT} ]", "MCTP_ENDPOINT", 141*275f7c39SAndrew Jeffery endpoint->describe()); 142*275f7c39SAndrew Jeffery endpoint->remove(); 143*275f7c39SAndrew Jeffery } 144*275f7c39SAndrew Jeffery } 145*275f7c39SAndrew Jeffery 146*275f7c39SAndrew Jeffery std::string MCTPDDevice::describe() const 147*275f7c39SAndrew Jeffery { 148*275f7c39SAndrew Jeffery std::string description = std::format("interface: {}", interface); 149*275f7c39SAndrew Jeffery if (!physaddr.empty()) 150*275f7c39SAndrew Jeffery { 151*275f7c39SAndrew Jeffery description.append(", address: 0x [ "); 152*275f7c39SAndrew Jeffery auto it = physaddr.begin(); 153*275f7c39SAndrew Jeffery for (; it != physaddr.end() - 1; it++) 154*275f7c39SAndrew Jeffery { 155*275f7c39SAndrew Jeffery description.append(std::format("{:02x} ", *it)); 156*275f7c39SAndrew Jeffery } 157*275f7c39SAndrew Jeffery description.append(std::format("{:02x} ]", *it)); 158*275f7c39SAndrew Jeffery } 159*275f7c39SAndrew Jeffery return description; 160*275f7c39SAndrew Jeffery } 161*275f7c39SAndrew Jeffery 162*275f7c39SAndrew Jeffery std::string MCTPDEndpoint::path(const std::shared_ptr<MCTPEndpoint>& ep) 163*275f7c39SAndrew Jeffery { 164*275f7c39SAndrew Jeffery return std::format("/xyz/openbmc_project/mctp/{}/{}", ep->network(), 165*275f7c39SAndrew Jeffery ep->eid()); 166*275f7c39SAndrew Jeffery } 167*275f7c39SAndrew Jeffery 168*275f7c39SAndrew Jeffery void MCTPDEndpoint::onMctpEndpointChange(sdbusplus::message_t& msg) 169*275f7c39SAndrew Jeffery { 170*275f7c39SAndrew Jeffery auto [iface, changed, _] = 171*275f7c39SAndrew Jeffery msg.unpack<std::string, std::map<std::string, BasicVariantType>, 172*275f7c39SAndrew Jeffery std::vector<std::string>>(); 173*275f7c39SAndrew Jeffery if (iface != mctpdEndpointControlInterface) 174*275f7c39SAndrew Jeffery { 175*275f7c39SAndrew Jeffery return; 176*275f7c39SAndrew Jeffery } 177*275f7c39SAndrew Jeffery 178*275f7c39SAndrew Jeffery auto it = changed.find("Connectivity"); 179*275f7c39SAndrew Jeffery if (it == changed.end()) 180*275f7c39SAndrew Jeffery { 181*275f7c39SAndrew Jeffery return; 182*275f7c39SAndrew Jeffery } 183*275f7c39SAndrew Jeffery 184*275f7c39SAndrew Jeffery updateEndpointConnectivity(std::get<std::string>(it->second)); 185*275f7c39SAndrew Jeffery } 186*275f7c39SAndrew Jeffery 187*275f7c39SAndrew Jeffery void MCTPDEndpoint::updateEndpointConnectivity(const std::string& connectivity) 188*275f7c39SAndrew Jeffery { 189*275f7c39SAndrew Jeffery if (connectivity == "Degraded") 190*275f7c39SAndrew Jeffery { 191*275f7c39SAndrew Jeffery if (notifyDegraded) 192*275f7c39SAndrew Jeffery { 193*275f7c39SAndrew Jeffery notifyDegraded(shared_from_this()); 194*275f7c39SAndrew Jeffery } 195*275f7c39SAndrew Jeffery } 196*275f7c39SAndrew Jeffery else if (connectivity == "Available") 197*275f7c39SAndrew Jeffery { 198*275f7c39SAndrew Jeffery if (notifyAvailable) 199*275f7c39SAndrew Jeffery { 200*275f7c39SAndrew Jeffery notifyAvailable(shared_from_this()); 201*275f7c39SAndrew Jeffery } 202*275f7c39SAndrew Jeffery } 203*275f7c39SAndrew Jeffery else 204*275f7c39SAndrew Jeffery { 205*275f7c39SAndrew Jeffery debug("Unrecognised connectivity state: '{CONNECTIVITY_STATE}'", 206*275f7c39SAndrew Jeffery "CONNECTIVITY_STATE", connectivity); 207*275f7c39SAndrew Jeffery } 208*275f7c39SAndrew Jeffery } 209*275f7c39SAndrew Jeffery 210*275f7c39SAndrew Jeffery int MCTPDEndpoint::network() const 211*275f7c39SAndrew Jeffery { 212*275f7c39SAndrew Jeffery return mctp.network; 213*275f7c39SAndrew Jeffery } 214*275f7c39SAndrew Jeffery 215*275f7c39SAndrew Jeffery uint8_t MCTPDEndpoint::eid() const 216*275f7c39SAndrew Jeffery { 217*275f7c39SAndrew Jeffery return mctp.eid; 218*275f7c39SAndrew Jeffery } 219*275f7c39SAndrew Jeffery 220*275f7c39SAndrew Jeffery void MCTPDEndpoint::subscribe(Event&& degraded, Event&& available, 221*275f7c39SAndrew Jeffery Event&& removed) 222*275f7c39SAndrew Jeffery { 223*275f7c39SAndrew Jeffery const auto matchSpec = 224*275f7c39SAndrew Jeffery sdbusplus::bus::match::rules::propertiesChangedNamespace( 225*275f7c39SAndrew Jeffery objpath.str, mctpdEndpointControlInterface); 226*275f7c39SAndrew Jeffery 227*275f7c39SAndrew Jeffery this->notifyDegraded = std::move(degraded); 228*275f7c39SAndrew Jeffery this->notifyAvailable = std::move(available); 229*275f7c39SAndrew Jeffery this->notifyRemoved = std::move(removed); 230*275f7c39SAndrew Jeffery 231*275f7c39SAndrew Jeffery try 232*275f7c39SAndrew Jeffery { 233*275f7c39SAndrew Jeffery connectivityMatch.emplace( 234*275f7c39SAndrew Jeffery static_cast<sdbusplus::bus_t&>(*connection), matchSpec, 235*275f7c39SAndrew Jeffery [weak{weak_from_this()}, 236*275f7c39SAndrew Jeffery path{objpath.str}](sdbusplus::message_t& msg) { 237*275f7c39SAndrew Jeffery if (auto self = weak.lock()) 238*275f7c39SAndrew Jeffery { 239*275f7c39SAndrew Jeffery self->onMctpEndpointChange(msg); 240*275f7c39SAndrew Jeffery } 241*275f7c39SAndrew Jeffery else 242*275f7c39SAndrew Jeffery { 243*275f7c39SAndrew Jeffery info( 244*275f7c39SAndrew Jeffery "The endpoint for the device at inventory path '{INVENTORY_PATH}' was destroyed concurrent to the removal of its state change match", 245*275f7c39SAndrew Jeffery "INVENTORY_PATH", path); 246*275f7c39SAndrew Jeffery } 247*275f7c39SAndrew Jeffery }); 248*275f7c39SAndrew Jeffery connection->async_method_call( 249*275f7c39SAndrew Jeffery [weak{weak_from_this()}, 250*275f7c39SAndrew Jeffery path{objpath.str}](const boost::system::error_code& ec, 251*275f7c39SAndrew Jeffery const std::variant<std::string>& value) { 252*275f7c39SAndrew Jeffery if (ec) 253*275f7c39SAndrew Jeffery { 254*275f7c39SAndrew Jeffery debug( 255*275f7c39SAndrew Jeffery "Failed to get current connectivity state: {ERROR_MESSAGE}", 256*275f7c39SAndrew Jeffery "ERROR_MESSAGE", ec.message(), "ERROR_CATEGORY", 257*275f7c39SAndrew Jeffery ec.category().name(), "ERROR_CODE", ec.value()); 258*275f7c39SAndrew Jeffery return; 259*275f7c39SAndrew Jeffery } 260*275f7c39SAndrew Jeffery 261*275f7c39SAndrew Jeffery if (auto self = weak.lock()) 262*275f7c39SAndrew Jeffery { 263*275f7c39SAndrew Jeffery const std::string& connectivity = 264*275f7c39SAndrew Jeffery std::get<std::string>(value); 265*275f7c39SAndrew Jeffery self->updateEndpointConnectivity(connectivity); 266*275f7c39SAndrew Jeffery } 267*275f7c39SAndrew Jeffery else 268*275f7c39SAndrew Jeffery { 269*275f7c39SAndrew Jeffery info( 270*275f7c39SAndrew Jeffery "The endpoint for the device at inventory path '{INVENTORY_PATH}' was destroyed concurrent to the completion of its connectivity state query", 271*275f7c39SAndrew Jeffery "INVENTORY_PATH", path); 272*275f7c39SAndrew Jeffery } 273*275f7c39SAndrew Jeffery }, 274*275f7c39SAndrew Jeffery mctpdBusName, objpath.str, "org.freedesktop.DBus.Properties", "Get", 275*275f7c39SAndrew Jeffery mctpdEndpointControlInterface, "Connectivity"); 276*275f7c39SAndrew Jeffery } 277*275f7c39SAndrew Jeffery catch (const sdbusplus::exception::SdBusError& err) 278*275f7c39SAndrew Jeffery { 279*275f7c39SAndrew Jeffery this->notifyDegraded = nullptr; 280*275f7c39SAndrew Jeffery this->notifyAvailable = nullptr; 281*275f7c39SAndrew Jeffery this->notifyRemoved = nullptr; 282*275f7c39SAndrew Jeffery std::throw_with_nested( 283*275f7c39SAndrew Jeffery MCTPException("Failed to register connectivity signal match")); 284*275f7c39SAndrew Jeffery } 285*275f7c39SAndrew Jeffery } 286*275f7c39SAndrew Jeffery 287*275f7c39SAndrew Jeffery void MCTPDEndpoint::remove() 288*275f7c39SAndrew Jeffery { 289*275f7c39SAndrew Jeffery connection->async_method_call( 290*275f7c39SAndrew Jeffery [self{shared_from_this()}](const boost::system::error_code& ec) { 291*275f7c39SAndrew Jeffery if (ec) 292*275f7c39SAndrew Jeffery { 293*275f7c39SAndrew Jeffery debug("Failed to remove endpoint @ [ {MCTP_ENDPOINT} ]", 294*275f7c39SAndrew Jeffery "MCTP_ENDPOINT", self->describe()); 295*275f7c39SAndrew Jeffery return; 296*275f7c39SAndrew Jeffery } 297*275f7c39SAndrew Jeffery }, 298*275f7c39SAndrew Jeffery mctpdBusName, objpath.str, mctpdEndpointControlInterface, "Remove"); 299*275f7c39SAndrew Jeffery } 300*275f7c39SAndrew Jeffery 301*275f7c39SAndrew Jeffery void MCTPDEndpoint::removed() 302*275f7c39SAndrew Jeffery { 303*275f7c39SAndrew Jeffery if (notifyRemoved) 304*275f7c39SAndrew Jeffery { 305*275f7c39SAndrew Jeffery notifyRemoved(shared_from_this()); 306*275f7c39SAndrew Jeffery } 307*275f7c39SAndrew Jeffery } 308*275f7c39SAndrew Jeffery 309*275f7c39SAndrew Jeffery std::string MCTPDEndpoint::describe() const 310*275f7c39SAndrew Jeffery { 311*275f7c39SAndrew Jeffery return std::format("network: {}, EID: {} | {}", mctp.network, mctp.eid, 312*275f7c39SAndrew Jeffery dev->describe()); 313*275f7c39SAndrew Jeffery } 314*275f7c39SAndrew Jeffery 315*275f7c39SAndrew Jeffery std::shared_ptr<MCTPDevice> MCTPDEndpoint::device() const 316*275f7c39SAndrew Jeffery { 317*275f7c39SAndrew Jeffery return dev; 318*275f7c39SAndrew Jeffery } 319*275f7c39SAndrew Jeffery 320*275f7c39SAndrew Jeffery std::optional<SensorBaseConfigMap> 321*275f7c39SAndrew Jeffery I2CMCTPDDevice::match(const SensorData& config) 322*275f7c39SAndrew Jeffery { 323*275f7c39SAndrew Jeffery auto iface = config.find(configInterfaceName(configType)); 324*275f7c39SAndrew Jeffery if (iface == config.end()) 325*275f7c39SAndrew Jeffery { 326*275f7c39SAndrew Jeffery return std::nullopt; 327*275f7c39SAndrew Jeffery } 328*275f7c39SAndrew Jeffery return iface->second; 329*275f7c39SAndrew Jeffery } 330*275f7c39SAndrew Jeffery 331*275f7c39SAndrew Jeffery bool I2CMCTPDDevice::match(const std::set<std::string>& interfaces) 332*275f7c39SAndrew Jeffery { 333*275f7c39SAndrew Jeffery return interfaces.contains(configInterfaceName(configType)); 334*275f7c39SAndrew Jeffery } 335*275f7c39SAndrew Jeffery 336*275f7c39SAndrew Jeffery std::shared_ptr<I2CMCTPDDevice> I2CMCTPDDevice::from( 337*275f7c39SAndrew Jeffery const std::shared_ptr<sdbusplus::asio::connection>& connection, 338*275f7c39SAndrew Jeffery const SensorBaseConfigMap& iface) 339*275f7c39SAndrew Jeffery { 340*275f7c39SAndrew Jeffery auto mType = iface.find("Type"); 341*275f7c39SAndrew Jeffery if (mType == iface.end()) 342*275f7c39SAndrew Jeffery { 343*275f7c39SAndrew Jeffery throw std::invalid_argument( 344*275f7c39SAndrew Jeffery "No 'Type' member found for provided configuration object"); 345*275f7c39SAndrew Jeffery } 346*275f7c39SAndrew Jeffery 347*275f7c39SAndrew Jeffery auto type = std::visit(VariantToStringVisitor(), mType->second); 348*275f7c39SAndrew Jeffery if (type != configType) 349*275f7c39SAndrew Jeffery { 350*275f7c39SAndrew Jeffery throw std::invalid_argument("Not an SMBus device"); 351*275f7c39SAndrew Jeffery } 352*275f7c39SAndrew Jeffery 353*275f7c39SAndrew Jeffery auto mAddress = iface.find("Address"); 354*275f7c39SAndrew Jeffery auto mBus = iface.find("Bus"); 355*275f7c39SAndrew Jeffery auto mName = iface.find("Name"); 356*275f7c39SAndrew Jeffery if (mAddress == iface.end() || mBus == iface.end() || mName == iface.end()) 357*275f7c39SAndrew Jeffery { 358*275f7c39SAndrew Jeffery throw std::invalid_argument( 359*275f7c39SAndrew Jeffery "Configuration object violates MCTPI2CTarget schema"); 360*275f7c39SAndrew Jeffery } 361*275f7c39SAndrew Jeffery 362*275f7c39SAndrew Jeffery auto sAddress = std::visit(VariantToStringVisitor(), mAddress->second); 363*275f7c39SAndrew Jeffery std::uint8_t address{}; 364*275f7c39SAndrew Jeffery auto [aptr, aec] = std::from_chars( 365*275f7c39SAndrew Jeffery sAddress.data(), sAddress.data() + sAddress.size(), address); 366*275f7c39SAndrew Jeffery if (aec != std::errc{}) 367*275f7c39SAndrew Jeffery { 368*275f7c39SAndrew Jeffery throw std::invalid_argument("Bad device address"); 369*275f7c39SAndrew Jeffery } 370*275f7c39SAndrew Jeffery 371*275f7c39SAndrew Jeffery auto sBus = std::visit(VariantToStringVisitor(), mBus->second); 372*275f7c39SAndrew Jeffery int bus{}; 373*275f7c39SAndrew Jeffery auto [bptr, 374*275f7c39SAndrew Jeffery bec] = std::from_chars(sBus.data(), sBus.data() + sBus.size(), bus); 375*275f7c39SAndrew Jeffery if (bec != std::errc{}) 376*275f7c39SAndrew Jeffery { 377*275f7c39SAndrew Jeffery throw std::invalid_argument("Bad bus index"); 378*275f7c39SAndrew Jeffery } 379*275f7c39SAndrew Jeffery 380*275f7c39SAndrew Jeffery try 381*275f7c39SAndrew Jeffery { 382*275f7c39SAndrew Jeffery return std::make_shared<I2CMCTPDDevice>(connection, bus, address); 383*275f7c39SAndrew Jeffery } 384*275f7c39SAndrew Jeffery catch (const MCTPException& ex) 385*275f7c39SAndrew Jeffery { 386*275f7c39SAndrew Jeffery warning( 387*275f7c39SAndrew Jeffery "Failed to create I2CMCTPDDevice at [ bus: {I2C_BUS}, address: {I2C_ADDRESS} ]: {EXCEPTION}", 388*275f7c39SAndrew Jeffery "I2C_BUS", bus, "I2C_ADDRESS", address, "EXCEPTION", ex); 389*275f7c39SAndrew Jeffery return {}; 390*275f7c39SAndrew Jeffery } 391*275f7c39SAndrew Jeffery } 392*275f7c39SAndrew Jeffery 393*275f7c39SAndrew Jeffery std::string I2CMCTPDDevice::interfaceFromBus(int bus) 394*275f7c39SAndrew Jeffery { 395*275f7c39SAndrew Jeffery std::filesystem::path netdir = 396*275f7c39SAndrew Jeffery std::format("/sys/bus/i2c/devices/i2c-{}/net", bus); 397*275f7c39SAndrew Jeffery std::error_code ec; 398*275f7c39SAndrew Jeffery std::filesystem::directory_iterator it(netdir, ec); 399*275f7c39SAndrew Jeffery if (ec || it == std::filesystem::end(it)) 400*275f7c39SAndrew Jeffery { 401*275f7c39SAndrew Jeffery error("No net device associated with I2C bus {I2C_BUS} at {NET_DEVICE}", 402*275f7c39SAndrew Jeffery "I2C_BUS", bus, "NET_DEVICE", netdir); 403*275f7c39SAndrew Jeffery throw MCTPException("Bus is not configured as an MCTP interface"); 404*275f7c39SAndrew Jeffery } 405*275f7c39SAndrew Jeffery 406*275f7c39SAndrew Jeffery return it->path().filename(); 407*275f7c39SAndrew Jeffery } 408