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
MCTPDDevice(const std::shared_ptr<sdbusplus::asio::connection> & connection,const std::string & interface,const std::vector<uint8_t> & physaddr)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
onEndpointInterfacesRemoved(const std::weak_ptr<MCTPDDevice> & weak,const std::string & objpath,sdbusplus::message_t & msg)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
finaliseEndpoint(const std::string & objpath,uint8_t eid,int network,std::function<void (const std::error_code & ec,const std::shared_ptr<MCTPEndpoint> & ep)> & added)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
setup(std::function<void (const std::error_code & ec,const std::shared_ptr<MCTPEndpoint> & ep)> && added)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
endpointRemoved()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
remove()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
describe() const146*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
path(const std::shared_ptr<MCTPEndpoint> & ep)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
onMctpEndpointChange(sdbusplus::message_t & msg)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
updateEndpointConnectivity(const std::string & connectivity)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
network() const210*275f7c39SAndrew Jeffery int MCTPDEndpoint::network() const
211*275f7c39SAndrew Jeffery {
212*275f7c39SAndrew Jeffery return mctp.network;
213*275f7c39SAndrew Jeffery }
214*275f7c39SAndrew Jeffery
eid() const215*275f7c39SAndrew Jeffery uint8_t MCTPDEndpoint::eid() const
216*275f7c39SAndrew Jeffery {
217*275f7c39SAndrew Jeffery return mctp.eid;
218*275f7c39SAndrew Jeffery }
219*275f7c39SAndrew Jeffery
subscribe(Event && degraded,Event && available,Event && removed)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
remove()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
removed()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
describe() const309*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
device() const315*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>
match(const SensorData & config)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
match(const std::set<std::string> & interfaces)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
from(const std::shared_ptr<sdbusplus::asio::connection> & connection,const SensorBaseConfigMap & iface)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
interfaceFromBus(int bus)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