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
MCTPDDevice(const std::shared_ptr<sdbusplus::asio::connection> & connection,const std::string & interface,const std::vector<uint8_t> & physaddr)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
onEndpointInterfacesRemoved(const std::weak_ptr<MCTPDDevice> & weak,const std::string & objpath,sdbusplus::message_t & msg)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
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)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
setup(std::function<void (const std::error_code & ec,const std::shared_ptr<MCTPEndpoint> & ep)> && added)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 }
endpointRemoved()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 }
remove()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 }
describe() const146275f7c39SAndrew 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 }
path(const std::shared_ptr<MCTPEndpoint> & ep)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 }
onMctpEndpointChange(sdbusplus::message_t & msg)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 }
updateEndpointConnectivity(const std::string & connectivity)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 }
network() const210275f7c39SAndrew Jeffery
211275f7c39SAndrew Jeffery int MCTPDEndpoint::network() const
212275f7c39SAndrew Jeffery {
213275f7c39SAndrew Jeffery return mctp.network;
214275f7c39SAndrew Jeffery }
eid() const215275f7c39SAndrew Jeffery
216275f7c39SAndrew Jeffery uint8_t MCTPDEndpoint::eid() const
217275f7c39SAndrew Jeffery {
218275f7c39SAndrew Jeffery return mctp.eid;
219275f7c39SAndrew Jeffery }
subscribe(Event && degraded,Event && available,Event && removed)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 }
remove()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 }
removed()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 }
describe() const309275f7c39SAndrew 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 }
device() const315275f7c39SAndrew Jeffery
316275f7c39SAndrew Jeffery std::shared_ptr<MCTPDevice> MCTPDEndpoint::device() const
317275f7c39SAndrew Jeffery {
318275f7c39SAndrew Jeffery return dev;
319275f7c39SAndrew Jeffery }
320275f7c39SAndrew Jeffery
match(const SensorData & config)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 }
match(const std::set<std::string> & interfaces)331275f7c39SAndrew Jeffery
332275f7c39SAndrew Jeffery bool I2CMCTPDDevice::match(const std::set<std::string>& interfaces)
333275f7c39SAndrew Jeffery {
334275f7c39SAndrew Jeffery return interfaces.contains(configInterfaceName(configType));
335275f7c39SAndrew Jeffery }
from(const std::shared_ptr<sdbusplus::asio::connection> & connection,const SensorBaseConfigMap & iface)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 }
interfaceFromBus(int bus)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