blob: cc898441705b07a41c7e91b46fdc5d0346ae30e5 [file] [log] [blame]
Ratan Guptab8e99552017-07-27 07:07:48 +05301#include <arpa/inet.h>
2#include <dirent.h>
Yong Li7dc4ac02019-08-23 17:44:32 +08003#include <fcntl.h>
4#include <linux/i2c-dev.h>
5#include <linux/i2c.h>
Ratan Guptab8e99552017-07-27 07:07:48 +05306#include <net/if.h>
Yong Li7dc4ac02019-08-23 17:44:32 +08007#include <sys/ioctl.h>
8#include <sys/types.h>
9#include <unistd.h>
Ratan Guptab8e99552017-07-27 07:07:48 +053010
Vernon Mauery6a98fe72019-03-11 15:57:48 -070011#include <ipmid/utils.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -070012#include <phosphor-logging/elog-errors.hpp>
George Liub4b40912024-07-17 16:14:17 +080013#include <phosphor-logging/lg2.hpp>
William A. Kennington III4c008022018-10-12 17:18:14 -070014#include <sdbusplus/message/types.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -070015#include <xyz/openbmc_project/Common/error.hpp>
16
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -050017#include <algorithm>
18#include <chrono>
Prithvi Paic1e7b5c2025-09-01 13:13:15 +053019#include <sstream>
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -050020
Tom Josephbe703f72017-03-09 12:34:35 +053021namespace ipmi
22{
23
Ratan Guptacc8feb42017-07-25 21:52:10 +053024using namespace phosphor::logging;
Willy Tu523e2d12023-09-05 11:36:48 -070025using namespace sdbusplus::error::xyz::openbmc_project::common;
Ratan Guptacc8feb42017-07-25 21:52:10 +053026
Nagaraju Goruganti1fe5c832017-09-21 07:44:17 -050027namespace network
28{
29
30/** @brief checks if the given ip is Link Local Ip or not.
Patrick Venture0b02be92018-08-31 11:55:55 -070031 * @param[in] ipaddress - IPAddress.
32 */
Nagaraju Goruganti1fe5c832017-09-21 07:44:17 -050033bool isLinkLocalIP(const std::string& ipaddress);
34
Patrick Venture0b02be92018-08-31 11:55:55 -070035} // namespace network
Ratan Guptacc8feb42017-07-25 21:52:10 +053036
Patrick Venture0b02be92018-08-31 11:55:55 -070037// TODO There may be cases where an interface is implemented by multiple
Ratan Guptacc8feb42017-07-25 21:52:10 +053038// objects,to handle such cases we are interested on that object
39// which are on interested busname.
40// Currently mapper doesn't give the readable busname(gives busid) so we can't
41// use busname to find the object,will do later once the support is there.
42
Patrick Williams69b4c282025-03-03 11:19:13 -050043DbusObjectInfo getDbusObject(
44 sdbusplus::bus_t& bus, const std::string& interface,
45 const std::string& serviceRoot, const std::string& match)
Ratan Guptacc8feb42017-07-25 21:52:10 +053046{
47 std::vector<DbusInterface> interfaces;
48 interfaces.emplace_back(interface);
49
George Liu50f186c2024-02-04 16:51:26 +080050 ObjectTree objectTree = getSubTree(bus, interfaces, serviceRoot);
Ratan Guptacc8feb42017-07-25 21:52:10 +053051 if (objectTree.empty())
52 {
George Liub4b40912024-07-17 16:14:17 +080053 lg2::error("No Object has implemented the interface: {INTERFACE}",
54 "INTERFACE", interface);
Ratan Guptacc8feb42017-07-25 21:52:10 +053055 elog<InternalFailure>();
56 }
57
58 DbusObjectInfo objectInfo;
59
60 // if match is empty then return the first object
Patrick Venture0b02be92018-08-31 11:55:55 -070061 if (match == "")
Ratan Guptacc8feb42017-07-25 21:52:10 +053062 {
Patrick Venture0b02be92018-08-31 11:55:55 -070063 objectInfo = std::make_pair(
64 objectTree.begin()->first,
Ratan Guptacc8feb42017-07-25 21:52:10 +053065 std::move(objectTree.begin()->second.begin()->first));
66 return objectInfo;
67 }
68
69 // else search the match string in the object path
Patrick Williams1318a5e2024-08-16 15:19:54 -040070 auto found = std::find_if(
71 objectTree.begin(), objectTree.end(), [&match](const auto& object) {
72 return (object.first.find(match) != std::string::npos);
73 });
Ratan Guptacc8feb42017-07-25 21:52:10 +053074
Patrick Venture2e633522018-10-13 13:51:06 -070075 if (found == objectTree.end())
Ratan Guptacc8feb42017-07-25 21:52:10 +053076 {
George Liub4b40912024-07-17 16:14:17 +080077 lg2::error("Failed to find object which matches: {MATCH}", "MATCH",
78 match);
Ratan Guptacc8feb42017-07-25 21:52:10 +053079 elog<InternalFailure>();
Patrick Venture2e633522018-10-13 13:51:06 -070080 // elog<> throws an exception.
Ratan Guptacc8feb42017-07-25 21:52:10 +053081 }
Patrick Venture2e633522018-10-13 13:51:06 -070082
83 return make_pair(found->first, std::move(found->second.begin()->first));
Ratan Guptacc8feb42017-07-25 21:52:10 +053084}
85
Patrick Williams5d82f472022-07-22 19:26:53 -050086Value getDbusProperty(sdbusplus::bus_t& bus, const std::string& service,
Patrick Venture0b02be92018-08-31 11:55:55 -070087 const std::string& objPath, const std::string& interface,
Kun Yi5dcf41e2019-03-05 14:02:51 -080088 const std::string& property,
89 std::chrono::microseconds timeout)
Ratan Guptacc8feb42017-07-25 21:52:10 +053090{
Ratan Guptacc8feb42017-07-25 21:52:10 +053091 Value value;
92
Patrick Venture0b02be92018-08-31 11:55:55 -070093 auto method = bus.new_method_call(service.c_str(), objPath.c_str(),
94 PROP_INTF, METHOD_GET);
Ratan Guptacc8feb42017-07-25 21:52:10 +053095
96 method.append(interface, property);
97
Kun Yi5dcf41e2019-03-05 14:02:51 -080098 auto reply = bus.call(method, timeout.count());
Ratan Guptacc8feb42017-07-25 21:52:10 +053099 reply.read(value);
100
101 return value;
102}
103
Patrick Williams1318a5e2024-08-16 15:19:54 -0400104PropertyMap getAllDbusProperties(
105 sdbusplus::bus_t& bus, const std::string& service,
106 const std::string& objPath, const std::string& interface,
107 std::chrono::microseconds timeout)
Ratan Guptacc8feb42017-07-25 21:52:10 +0530108{
109 PropertyMap properties;
Ratan Guptacc8feb42017-07-25 21:52:10 +0530110
Patrick Venture0b02be92018-08-31 11:55:55 -0700111 auto method = bus.new_method_call(service.c_str(), objPath.c_str(),
112 PROP_INTF, METHOD_GET_ALL);
Ratan Guptacc8feb42017-07-25 21:52:10 +0530113
114 method.append(interface);
115
Kun Yi5dcf41e2019-03-05 14:02:51 -0800116 auto reply = bus.call(method, timeout.count());
Ratan Guptacc8feb42017-07-25 21:52:10 +0530117 reply.read(properties);
George Liu3e3cc352023-07-26 15:59:31 +0800118
Ratan Guptacc8feb42017-07-25 21:52:10 +0530119 return properties;
120}
121
Patrick Williams5d82f472022-07-22 19:26:53 -0500122ObjectValueTree getManagedObjects(sdbusplus::bus_t& bus,
Patrick Venture0b02be92018-08-31 11:55:55 -0700123 const std::string& service,
124 const std::string& objPath)
Dhruvaraj Subhashchandran5c0beec2018-01-23 04:47:06 -0600125{
126 ipmi::ObjectValueTree interfaces;
127
Patrick Venture0b02be92018-08-31 11:55:55 -0700128 auto method = bus.new_method_call(service.c_str(), objPath.c_str(),
129 "org.freedesktop.DBus.ObjectManager",
130 "GetManagedObjects");
Dhruvaraj Subhashchandran5c0beec2018-01-23 04:47:06 -0600131 auto reply = bus.call(method);
Dhruvaraj Subhashchandran5c0beec2018-01-23 04:47:06 -0600132 reply.read(interfaces);
George Liu3e3cc352023-07-26 15:59:31 +0800133
Dhruvaraj Subhashchandran5c0beec2018-01-23 04:47:06 -0600134 return interfaces;
135}
136
Patrick Williams5d82f472022-07-22 19:26:53 -0500137void setDbusProperty(sdbusplus::bus_t& bus, const std::string& service,
Patrick Venture0b02be92018-08-31 11:55:55 -0700138 const std::string& objPath, const std::string& interface,
Kun Yi5dcf41e2019-03-05 14:02:51 -0800139 const std::string& property, const Value& value,
140 std::chrono::microseconds timeout)
Ratan Guptacc8feb42017-07-25 21:52:10 +0530141{
Patrick Venture0b02be92018-08-31 11:55:55 -0700142 auto method = bus.new_method_call(service.c_str(), objPath.c_str(),
143 PROP_INTF, METHOD_SET);
Ratan Guptacc8feb42017-07-25 21:52:10 +0530144
145 method.append(interface, property, value);
146
Kun Yi5dcf41e2019-03-05 14:02:51 -0800147 if (!bus.call(method, timeout.count()))
Ratan Guptacc8feb42017-07-25 21:52:10 +0530148 {
George Liub4b40912024-07-17 16:14:17 +0800149 lg2::error("Failed to set {PROPERTY}, path: {PATH}, "
150 "interface: {INTERFACE}",
151 "PROPERTY", property, "PATH", objPath, "INTERFACE",
152 interface);
Ratan Guptacc8feb42017-07-25 21:52:10 +0530153 elog<InternalFailure>();
154 }
Ratan Guptacc8feb42017-07-25 21:52:10 +0530155}
156
Patrick Venture0b02be92018-08-31 11:55:55 -0700157ServiceCache::ServiceCache(const std::string& intf, const std::string& path) :
Vernon Mauery54012502018-11-07 10:17:31 -0800158 intf(intf), path(path), cachedService(std::nullopt),
159 cachedBusName(std::nullopt)
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500160{}
William A. Kennington IIIe47fdfb2018-03-15 17:09:28 -0700161
Patrick Venture0b02be92018-08-31 11:55:55 -0700162ServiceCache::ServiceCache(std::string&& intf, std::string&& path) :
Vernon Mauery54012502018-11-07 10:17:31 -0800163 intf(std::move(intf)), path(std::move(path)), cachedService(std::nullopt),
164 cachedBusName(std::nullopt)
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500165{}
William A. Kennington IIIe47fdfb2018-03-15 17:09:28 -0700166
Patrick Williams5d82f472022-07-22 19:26:53 -0500167const std::string& ServiceCache::getService(sdbusplus::bus_t& bus)
William A. Kennington IIIe47fdfb2018-03-15 17:09:28 -0700168{
169 if (!isValid(bus))
170 {
171 cachedBusName = bus.get_unique_name();
172 cachedService = ::ipmi::getService(bus, intf, path);
173 }
Jayanth Othayoth195d5522025-06-07 02:28:07 -0500174
175 if (!cachedService)
176 {
177 throw std::runtime_error("Service not cached");
178 }
William A. Kennington IIIe47fdfb2018-03-15 17:09:28 -0700179 return cachedService.value();
180}
181
182void ServiceCache::invalidate()
183{
Vernon Mauery54012502018-11-07 10:17:31 -0800184 cachedBusName = std::nullopt;
185 cachedService = std::nullopt;
William A. Kennington IIIe47fdfb2018-03-15 17:09:28 -0700186}
187
Patrick Williams1318a5e2024-08-16 15:19:54 -0400188sdbusplus::message_t ServiceCache::newMethodCall(
189 sdbusplus::bus_t& bus, const char* intf, const char* method)
William A. Kennington IIIe47fdfb2018-03-15 17:09:28 -0700190{
Patrick Venture0b02be92018-08-31 11:55:55 -0700191 return bus.new_method_call(getService(bus).c_str(), path.c_str(), intf,
192 method);
William A. Kennington IIIe47fdfb2018-03-15 17:09:28 -0700193}
194
Patrick Williams5d82f472022-07-22 19:26:53 -0500195bool ServiceCache::isValid(sdbusplus::bus_t& bus) const
William A. Kennington IIIe47fdfb2018-03-15 17:09:28 -0700196{
197 return cachedService && cachedBusName == bus.get_unique_name();
198}
199
Patrick Williams5d82f472022-07-22 19:26:53 -0500200std::string getService(sdbusplus::bus_t& bus, const std::string& intf,
Tom Josephbe703f72017-03-09 12:34:35 +0530201 const std::string& path)
202{
Patrick Williams1318a5e2024-08-16 15:19:54 -0400203 auto mapperCall =
204 bus.new_method_call("xyz.openbmc_project.ObjectMapper",
205 "/xyz/openbmc_project/object_mapper",
206 "xyz.openbmc_project.ObjectMapper", "GetObject");
Tom Josephbe703f72017-03-09 12:34:35 +0530207
208 mapperCall.append(path);
209 mapperCall.append(std::vector<std::string>({intf}));
210
211 auto mapperResponseMsg = bus.call(mapperCall);
212
Tom Josephbe703f72017-03-09 12:34:35 +0530213 std::map<std::string, std::vector<std::string>> mapperResponse;
214 mapperResponseMsg.read(mapperResponse);
215
216 if (mapperResponse.begin() == mapperResponse.end())
217 {
218 throw std::runtime_error("ERROR in reading the mapper response");
219 }
220
221 return mapperResponse.begin()->first;
222}
223
George Liu50f186c2024-02-04 16:51:26 +0800224ObjectTree getSubTree(sdbusplus::bus_t& bus, const InterfaceList& interfaces,
225 const std::string& subtreePath, int32_t depth)
226{
227 auto mapperCall = bus.new_method_call(MAPPER_BUS_NAME, MAPPER_OBJ,
228 MAPPER_INTF, "GetSubTree");
229
230 mapperCall.append(subtreePath, depth, interfaces);
231
232 auto mapperReply = bus.call(mapperCall);
233 ObjectTree objectTree;
234 mapperReply.read(objectTree);
235
236 return objectTree;
237}
238
Patrick Williams69b4c282025-03-03 11:19:13 -0500239ipmi::ObjectTree getAllDbusObjects(
240 sdbusplus::bus_t& bus, const std::string& serviceRoot,
241 const std::string& interface, const std::string& match)
Ratan Guptab8e99552017-07-27 07:07:48 +0530242{
243 std::vector<std::string> interfaces;
244 interfaces.emplace_back(interface);
Ratan Guptacc8feb42017-07-25 21:52:10 +0530245
George Liu50f186c2024-02-04 16:51:26 +0800246 ObjectTree objectTree = getSubTree(bus, interfaces, serviceRoot);
Ratan Guptab8e99552017-07-27 07:07:48 +0530247 for (auto it = objectTree.begin(); it != objectTree.end();)
248 {
249 if (it->first.find(match) == std::string::npos)
250 {
251 it = objectTree.erase(it);
252 }
253 else
254 {
255 ++it;
256 }
257 }
258
259 return objectTree;
260}
261
Ratan Guptab8e99552017-07-27 07:07:48 +0530262namespace method_no_args
263{
264
Patrick Williams5d82f472022-07-22 19:26:53 -0500265void callDbusMethod(sdbusplus::bus_t& bus, const std::string& service,
Patrick Venture0b02be92018-08-31 11:55:55 -0700266 const std::string& objPath, const std::string& interface,
Ratan Guptab8e99552017-07-27 07:07:48 +0530267 const std::string& method)
268
269{
Patrick Venture0b02be92018-08-31 11:55:55 -0700270 auto busMethod = bus.new_method_call(service.c_str(), objPath.c_str(),
271 interface.c_str(), method.c_str());
Ratan Guptab8e99552017-07-27 07:07:48 +0530272 auto reply = bus.call(busMethod);
Ratan Guptab8e99552017-07-27 07:07:48 +0530273}
274
Patrick Venture0b02be92018-08-31 11:55:55 -0700275} // namespace method_no_args
Vernon Maueryeeb0f982019-05-29 16:36:58 -0700276
277/********* Begin co-routine yielding alternatives ***************/
278
Patrick Williams69b4c282025-03-03 11:19:13 -0500279boost::system::error_code getService(Context::ptr ctx, const std::string& intf,
280 const std::string& path,
281 std::string& service)
Vernon Maueryeeb0f982019-05-29 16:36:58 -0700282{
283 boost::system::error_code ec;
284 std::map<std::string, std::vector<std::string>> mapperResponse =
285 ctx->bus->yield_method_call<decltype(mapperResponse)>(
286 ctx->yield, ec, "xyz.openbmc_project.ObjectMapper",
287 "/xyz/openbmc_project/object_mapper",
Jason M. Billsf5967982020-03-06 10:42:08 -0800288 "xyz.openbmc_project.ObjectMapper", "GetObject", path,
Vernon Maueryeeb0f982019-05-29 16:36:58 -0700289 std::vector<std::string>({intf}));
290
291 if (!ec)
292 {
293 service = std::move(mapperResponse.begin()->first);
294 }
295 return ec;
296}
297
Patrick Williams1318a5e2024-08-16 15:19:54 -0400298boost::system::error_code getSubTree(
299 Context::ptr ctx, const InterfaceList& interfaces,
300 const std::string& subtreePath, int32_t depth, ObjectTree& objectTree)
George Liu50f186c2024-02-04 16:51:26 +0800301{
302 boost::system::error_code ec;
303 objectTree = ctx->bus->yield_method_call<ObjectTree>(
304 ctx->yield, ec, MAPPER_BUS_NAME, MAPPER_OBJ, MAPPER_INTF, "GetSubTree",
305 subtreePath, depth, interfaces);
306
307 return ec;
308}
309
Patrick Williams69b4c282025-03-03 11:19:13 -0500310boost::system::error_code getDbusObject(
311 Context::ptr ctx, const std::string& interface,
312 const std::string& subtreePath, const std::string& match,
313 DbusObjectInfo& dbusObject)
Vernon Maueryeeb0f982019-05-29 16:36:58 -0700314{
315 std::vector<DbusInterface> interfaces;
316 interfaces.emplace_back(interface);
317
318 auto depth = 0;
George Liu50f186c2024-02-04 16:51:26 +0800319 ObjectTree objectTree;
Patrick Williams1318a5e2024-08-16 15:19:54 -0400320 boost::system::error_code ec =
321 getSubTree(ctx, interfaces, subtreePath, depth, objectTree);
Vernon Maueryeeb0f982019-05-29 16:36:58 -0700322
323 if (ec)
324 {
325 return ec;
326 }
327
328 if (objectTree.empty())
329 {
George Liub4b40912024-07-17 16:14:17 +0800330 lg2::error("No Object has implemented the interface: {INTERFACE}, "
331 "NetFn: {NETFN}, Cmd: {CMD}",
332 "INTERFACE", interface, "NETFN", lg2::hex, ctx->netFn, "CMD",
333 lg2::hex, ctx->cmd);
Vernon Maueryeeb0f982019-05-29 16:36:58 -0700334 return boost::system::errc::make_error_code(
335 boost::system::errc::no_such_process);
336 }
337
338 // if match is empty then return the first object
339 if (match == "")
340 {
341 dbusObject = std::make_pair(
342 std::move(objectTree.begin()->first),
343 std::move(objectTree.begin()->second.begin()->first));
344 return ec;
345 }
346
347 // else search the match string in the object path
Patrick Williams1318a5e2024-08-16 15:19:54 -0400348 auto found = std::find_if(
349 objectTree.begin(), objectTree.end(), [&match](const auto& object) {
350 return (object.first.find(match) != std::string::npos);
351 });
Vernon Maueryeeb0f982019-05-29 16:36:58 -0700352
353 if (found == objectTree.end())
354 {
George Liub4b40912024-07-17 16:14:17 +0800355 lg2::error("Failed to find object which matches: {MATCH}, "
356 "NetFn: {NETFN}, Cmd: {CMD}",
357 "MATCH", match, "NETFN", lg2::hex, ctx->netFn, "CMD",
358 lg2::hex, ctx->cmd);
Vernon Maueryeeb0f982019-05-29 16:36:58 -0700359 // set ec
360 return boost::system::errc::make_error_code(
361 boost::system::errc::no_such_file_or_directory);
362 }
363
364 dbusObject = std::make_pair(std::move(found->first),
365 std::move(found->second.begin()->first));
366 return ec;
367}
368
Patrick Williams1318a5e2024-08-16 15:19:54 -0400369boost::system::error_code getAllDbusProperties(
370 Context::ptr ctx, const std::string& service, const std::string& objPath,
371 const std::string& interface, PropertyMap& properties)
Vernon Maueryeeb0f982019-05-29 16:36:58 -0700372{
373 boost::system::error_code ec;
374 properties = ctx->bus->yield_method_call<PropertyMap>(
375 ctx->yield, ec, service.c_str(), objPath.c_str(), PROP_INTF,
376 METHOD_GET_ALL, interface);
377 return ec;
378}
379
Patrick Williams69b4c282025-03-03 11:19:13 -0500380boost::system::error_code setDbusProperty(
381 Context::ptr ctx, const std::string& service, const std::string& objPath,
382 const std::string& interface, const std::string& property,
383 const Value& value)
Vernon Maueryeeb0f982019-05-29 16:36:58 -0700384{
385 boost::system::error_code ec;
386 ctx->bus->yield_method_call(ctx->yield, ec, service.c_str(),
387 objPath.c_str(), PROP_INTF, METHOD_SET,
388 interface, property, value);
389 return ec;
390}
391
Patrick Williams69b4c282025-03-03 11:19:13 -0500392boost::system::error_code getAllDbusObjects(
393 Context::ptr ctx, const std::string& serviceRoot,
394 const std::string& interface, const std::string& match,
395 ObjectTree& objectTree)
Vernon Maueryeeb0f982019-05-29 16:36:58 -0700396{
Vernon Maueryeeb0f982019-05-29 16:36:58 -0700397 std::vector<std::string> interfaces;
398 interfaces.emplace_back(interface);
399
400 auto depth = 0;
Patrick Williams1318a5e2024-08-16 15:19:54 -0400401 boost::system::error_code ec =
402 getSubTree(ctx, interfaces, serviceRoot, depth, objectTree);
Vernon Maueryeeb0f982019-05-29 16:36:58 -0700403 if (ec)
404 {
405 return ec;
406 }
407
408 for (auto it = objectTree.begin(); it != objectTree.end();)
409 {
410 if (it->first.find(match) == std::string::npos)
411 {
412 it = objectTree.erase(it);
413 }
414 else
415 {
416 ++it;
417 }
418 }
419
420 return ec;
421}
422
Patrick Williams69b4c282025-03-03 11:19:13 -0500423boost::system::error_code getManagedObjects(
424 Context::ptr ctx, const std::string& service, const std::string& objPath,
425 ObjectValueTree& objects)
Vernon Maueryeeb0f982019-05-29 16:36:58 -0700426{
427 boost::system::error_code ec;
428 objects = ctx->bus->yield_method_call<ipmi::ObjectValueTree>(
429 ctx->yield, ec, service.c_str(), objPath.c_str(),
430 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
431 return ec;
432}
433
Patrick Williams1318a5e2024-08-16 15:19:54 -0400434boost::system::error_code callDbusMethod(
435 Context::ptr ctx, const std::string& service, const std::string& objPath,
436 const std::string& interface, const std::string& method)
Albert Zhangb53049e2022-04-02 15:39:51 +0800437{
438 boost::system::error_code ec;
439 ctx->bus->yield_method_call(ctx->yield, ec, service, objPath, interface,
440 method);
441 return ec;
442}
443
Vernon Maueryeeb0f982019-05-29 16:36:58 -0700444/********* End co-routine yielding alternatives ***************/
445
Matt Simmering68d9d402023-11-09 14:22:11 -0800446ipmi::Cc i2cWriteRead(std::string i2cBus, const uint8_t targetAddr,
Yong Li7dc4ac02019-08-23 17:44:32 +0800447 std::vector<uint8_t> writeData,
448 std::vector<uint8_t>& readBuf)
449{
450 // Open the i2c device, for low-level combined data write/read
451 int i2cDev = ::open(i2cBus.c_str(), O_RDWR | O_CLOEXEC);
452 if (i2cDev < 0)
453 {
George Liub4b40912024-07-17 16:14:17 +0800454 lg2::error("Failed to open i2c bus: {BUS}", "BUS", i2cBus);
Yong Li7dc4ac02019-08-23 17:44:32 +0800455 return ipmi::ccInvalidFieldRequest;
456 }
457
458 const size_t writeCount = writeData.size();
459 const size_t readCount = readBuf.size();
460 int msgCount = 0;
Willy Tu11d68892022-01-20 10:37:34 -0800461 i2c_msg i2cmsg[2] = {};
Yong Li7dc4ac02019-08-23 17:44:32 +0800462 if (writeCount)
463 {
Matt Simmering68d9d402023-11-09 14:22:11 -0800464 // Data will be writtern to the target address
465 i2cmsg[msgCount].addr = targetAddr;
Yong Li7dc4ac02019-08-23 17:44:32 +0800466 i2cmsg[msgCount].flags = 0x00;
467 i2cmsg[msgCount].len = writeCount;
468 i2cmsg[msgCount].buf = writeData.data();
469 msgCount++;
470 }
471 if (readCount)
472 {
Matt Simmering68d9d402023-11-09 14:22:11 -0800473 // Data will be read into the buffer from the target address
474 i2cmsg[msgCount].addr = targetAddr;
Yong Li7dc4ac02019-08-23 17:44:32 +0800475 i2cmsg[msgCount].flags = I2C_M_RD;
476 i2cmsg[msgCount].len = readCount;
477 i2cmsg[msgCount].buf = readBuf.data();
478 msgCount++;
479 }
480
Willy Tu11d68892022-01-20 10:37:34 -0800481 i2c_rdwr_ioctl_data msgReadWrite = {};
Yong Li7dc4ac02019-08-23 17:44:32 +0800482 msgReadWrite.msgs = i2cmsg;
483 msgReadWrite.nmsgs = msgCount;
484
485 // Perform the combined write/read
486 int ret = ::ioctl(i2cDev, I2C_RDWR, &msgReadWrite);
487 ::close(i2cDev);
488
489 if (ret < 0)
490 {
George Liub4b40912024-07-17 16:14:17 +0800491 lg2::error("I2C WR Failed! {RET}", "RET", ret);
Yong Li7dc4ac02019-08-23 17:44:32 +0800492 return ipmi::ccUnspecifiedError;
493 }
494 if (readCount)
495 {
496 readBuf.resize(msgReadWrite.msgs[msgCount - 1].len);
497 }
498
499 return ipmi::ccSuccess;
500}
501
Prithvi Paic1e7b5c2025-09-01 13:13:15 +0530502std::vector<std::string> split(const std::string& srcStr, char delim)
503{
504 std::vector<std::string> out;
505 std::stringstream ss(srcStr);
506 std::string item;
507
508 while (std::getline(ss, item, delim))
509 {
510 if (!item.empty())
511 {
512 out.emplace_back(item);
513 }
514 }
515 return out;
516}
517
Tom Josephbe703f72017-03-09 12:34:35 +0530518} // namespace ipmi