blob: d8ad3b206dd6465df832e3afab24edc697727e8f [file] [log] [blame]
Patrick Venture189d44e2018-07-09 12:30:59 -07001#include "ncsi_util.hpp"
2
Ratan Guptabbe45792018-03-23 00:22:55 +05303#include <linux/ncsi.h>
Ratan Guptabbe45792018-03-23 00:22:55 +05304#include <netlink/genl/ctrl.h>
Gunnar Mills57d9c502018-09-14 14:42:34 -05005#include <netlink/genl/genl.h>
6#include <netlink/netlink.h>
Ratan Guptabbe45792018-03-23 00:22:55 +05307
Patrick Williams89d734b2023-05-10 07:50:25 -05008#include <phosphor-logging/lg2.hpp>
9
Jeremy Kerrb7885242024-09-16 12:43:36 +080010#include <optional>
11#include <span>
Jiaqing Zhao7c44a782022-04-10 15:30:04 +080012#include <vector>
Ratan Guptabbe45792018-03-23 00:22:55 +053013
14namespace phosphor
15{
16namespace network
17{
18namespace ncsi
19{
20
Jeremy Kerrb7885242024-09-16 12:43:36 +080021NCSICommand::NCSICommand(uint8_t opcode, uint8_t package,
22 std::optional<uint8_t> channel,
23 std::span<unsigned char> payload) :
24 opcode(opcode), package(package), channel(channel)
25{
26 this->payload.assign(payload.begin(), payload.end());
27}
28
29uint8_t NCSICommand::getChannel()
30{
31 return channel.value_or(CHANNEL_ID_NONE);
32}
33
Gunnar Mills57d9c502018-09-14 14:42:34 -050034using CallBack = int (*)(struct nl_msg* msg, void* arg);
Ratan Guptaaac603e2018-03-23 00:25:54 +053035
36namespace internal
37{
Ratan Guptabbe45792018-03-23 00:22:55 +053038
Eddie Jamesfa1f5c02020-09-17 15:12:46 -050039struct NCSIPacketHeader
40{
41 uint8_t MCID;
42 uint8_t revision;
43 uint8_t reserved;
44 uint8_t id;
45 uint8_t type;
46 uint8_t channel;
47 uint16_t length;
48 uint32_t rsvd[2];
49};
50
Jeremy Kerrb7885242024-09-16 12:43:36 +080051struct NCSIResponsePayload
52{
53 uint16_t response;
54 uint16_t reason;
55};
56
Jeremy Kerr3f34ff62024-09-12 13:00:27 +080057class NetlinkCommand
Eddie Jamesfa1f5c02020-09-17 15:12:46 -050058{
59 public:
Jeremy Kerr3f34ff62024-09-12 13:00:27 +080060 NetlinkCommand() = delete;
61 ~NetlinkCommand() = default;
62 NetlinkCommand(const NetlinkCommand&) = delete;
63 NetlinkCommand& operator=(const NetlinkCommand&) = delete;
64 NetlinkCommand(NetlinkCommand&&) = default;
65 NetlinkCommand& operator=(NetlinkCommand&&) = default;
66 NetlinkCommand(
Johnathan Mantey1ebea282024-02-15 10:26:06 -080067 int ncsiCmd, int operation = DEFAULT_VALUE,
Eddie Jamesfa1f5c02020-09-17 15:12:46 -050068 std::span<const unsigned char> p = std::span<const unsigned char>()) :
Patrick Williamsad205022024-08-16 15:20:07 -040069 ncsi_cmd(ncsiCmd), operation(operation), payload(p)
Patrick Williams89d734b2023-05-10 07:50:25 -050070 {}
Eddie Jamesfa1f5c02020-09-17 15:12:46 -050071
Eddie Jamesfa1f5c02020-09-17 15:12:46 -050072 int ncsi_cmd;
Johnathan Mantey1ebea282024-02-15 10:26:06 -080073 int operation;
Eddie Jamesfa1f5c02020-09-17 15:12:46 -050074 std::span<const unsigned char> payload;
75};
76
Ratan Guptabbe45792018-03-23 00:22:55 +053077using nlMsgPtr = std::unique_ptr<nl_msg, decltype(&::nlmsg_free)>;
78using nlSocketPtr = std::unique_ptr<nl_sock, decltype(&::nl_socket_free)>;
79
Jeremy Kerr7f7c0852024-08-08 11:32:55 +080080struct infoCallBackContext
81{
82 InterfaceInfo* info;
83};
84
85CallBack infoCallBack = [](struct nl_msg* msg, void* arg) {
86 if (arg == nullptr)
87 {
88 lg2::error("Internal error: invalid info callback context");
89 return -1;
90 }
91
92 struct infoCallBackContext* info = (struct infoCallBackContext*)arg;
Ratan Guptaaac603e2018-03-23 00:25:54 +053093 using namespace phosphor::network::ncsi;
94 auto nlh = nlmsg_hdr(msg);
95
Gunnar Mills57d9c502018-09-14 14:42:34 -050096 struct nlattr* tb[NCSI_ATTR_MAX + 1] = {nullptr};
97 struct nla_policy ncsiPolicy[NCSI_ATTR_MAX + 1] = {
William A. Kennington III05368f12021-05-13 18:40:47 -070098 {NLA_UNSPEC, 0, 0}, {NLA_U32, 0, 0}, {NLA_NESTED, 0, 0},
99 {NLA_U32, 0, 0}, {NLA_U32, 0, 0},
Ratan Guptaaac603e2018-03-23 00:25:54 +0530100 };
101
Gunnar Mills57d9c502018-09-14 14:42:34 -0500102 struct nlattr* packagetb[NCSI_PKG_ATTR_MAX + 1] = {nullptr};
103 struct nla_policy packagePolicy[NCSI_PKG_ATTR_MAX + 1] = {
William A. Kennington III05368f12021-05-13 18:40:47 -0700104 {NLA_UNSPEC, 0, 0}, {NLA_NESTED, 0, 0}, {NLA_U32, 0, 0},
105 {NLA_FLAG, 0, 0}, {NLA_NESTED, 0, 0},
Ratan Guptaaac603e2018-03-23 00:25:54 +0530106 };
107
Gunnar Mills57d9c502018-09-14 14:42:34 -0500108 struct nlattr* channeltb[NCSI_CHANNEL_ATTR_MAX + 1] = {nullptr};
109 struct nla_policy channelPolicy[NCSI_CHANNEL_ATTR_MAX + 1] = {
William A. Kennington III05368f12021-05-13 18:40:47 -0700110 {NLA_UNSPEC, 0, 0}, {NLA_NESTED, 0, 0}, {NLA_U32, 0, 0},
111 {NLA_FLAG, 0, 0}, {NLA_NESTED, 0, 0}, {NLA_UNSPEC, 0, 0},
Ratan Guptaaac603e2018-03-23 00:25:54 +0530112 };
113
114 auto ret = genlmsg_parse(nlh, 0, tb, NCSI_ATTR_MAX, ncsiPolicy);
115 if (!tb[NCSI_ATTR_PACKAGE_LIST])
116 {
Jagpal Singh Gilld423beb2023-04-18 11:28:03 -0700117 lg2::error("No Packages");
Ratan Guptaaac603e2018-03-23 00:25:54 +0530118 return -1;
119 }
120
121 auto attrTgt = static_cast<nlattr*>(nla_data(tb[NCSI_ATTR_PACKAGE_LIST]));
122 if (!attrTgt)
123 {
Jagpal Singh Gilld423beb2023-04-18 11:28:03 -0700124 lg2::error("Package list attribute is null");
Ratan Guptaaac603e2018-03-23 00:25:54 +0530125 return -1;
126 }
127
128 auto rem = nla_len(tb[NCSI_ATTR_PACKAGE_LIST]);
129 nla_for_each_nested(attrTgt, tb[NCSI_ATTR_PACKAGE_LIST], rem)
130 {
131 ret = nla_parse_nested(packagetb, NCSI_PKG_ATTR_MAX, attrTgt,
132 packagePolicy);
133 if (ret < 0)
134 {
Jagpal Singh Gilld423beb2023-04-18 11:28:03 -0700135 lg2::error("Failed to parse package nested");
Ratan Guptaaac603e2018-03-23 00:25:54 +0530136 return -1;
137 }
138
Jeremy Kerr7f7c0852024-08-08 11:32:55 +0800139 PackageInfo pkg;
140
Ratan Guptaaac603e2018-03-23 00:25:54 +0530141 if (packagetb[NCSI_PKG_ATTR_ID])
142 {
143 auto attrID = nla_get_u32(packagetb[NCSI_PKG_ATTR_ID]);
Jeremy Kerr7f7c0852024-08-08 11:32:55 +0800144 pkg.id = attrID;
Ratan Guptaaac603e2018-03-23 00:25:54 +0530145 }
146 else
147 {
Jagpal Singh Gilld423beb2023-04-18 11:28:03 -0700148 lg2::debug("Package with no id");
Ratan Guptaaac603e2018-03-23 00:25:54 +0530149 }
150
151 if (packagetb[NCSI_PKG_ATTR_FORCED])
152 {
Jeremy Kerr7f7c0852024-08-08 11:32:55 +0800153 pkg.forced = true;
Ratan Guptaaac603e2018-03-23 00:25:54 +0530154 }
155
156 auto channelListTarget = static_cast<nlattr*>(
Gunnar Mills57d9c502018-09-14 14:42:34 -0500157 nla_data(packagetb[NCSI_PKG_ATTR_CHANNEL_LIST]));
Ratan Guptaaac603e2018-03-23 00:25:54 +0530158
159 auto channelrem = nla_len(packagetb[NCSI_PKG_ATTR_CHANNEL_LIST]);
160 nla_for_each_nested(channelListTarget,
161 packagetb[NCSI_PKG_ATTR_CHANNEL_LIST], channelrem)
162 {
163 ret = nla_parse_nested(channeltb, NCSI_CHANNEL_ATTR_MAX,
164 channelListTarget, channelPolicy);
165 if (ret < 0)
166 {
Jagpal Singh Gilld423beb2023-04-18 11:28:03 -0700167 lg2::error("Failed to parse channel nested");
Jeremy Kerr7f7c0852024-08-08 11:32:55 +0800168 continue;
Ratan Guptaaac603e2018-03-23 00:25:54 +0530169 }
170
Jeremy Kerr7f7c0852024-08-08 11:32:55 +0800171 ChannelInfo chan;
172
Ratan Guptaaac603e2018-03-23 00:25:54 +0530173 if (channeltb[NCSI_CHANNEL_ATTR_ID])
174 {
Jeremy Kerr7f7c0852024-08-08 11:32:55 +0800175 chan.id = nla_get_u32(channeltb[NCSI_CHANNEL_ATTR_ID]);
176 chan.active = !!channeltb[NCSI_CHANNEL_ATTR_ACTIVE];
177 chan.forced = !!channeltb[NCSI_CHANNEL_ATTR_FORCED];
Ratan Guptaaac603e2018-03-23 00:25:54 +0530178 }
179 else
180 {
Jagpal Singh Gilld423beb2023-04-18 11:28:03 -0700181 lg2::debug("Channel with no ID");
Jeremy Kerr7f7c0852024-08-08 11:32:55 +0800182 continue;
Ratan Guptaaac603e2018-03-23 00:25:54 +0530183 }
Ratan Guptaed5d7ff2018-03-23 00:27:52 +0530184
Ratan Guptaaac603e2018-03-23 00:25:54 +0530185 if (channeltb[NCSI_CHANNEL_ATTR_VERSION_MAJOR])
186 {
Jeremy Kerr7f7c0852024-08-08 11:32:55 +0800187 chan.version_major =
Gunnar Mills57d9c502018-09-14 14:42:34 -0500188 nla_get_u32(channeltb[NCSI_CHANNEL_ATTR_VERSION_MAJOR]);
Ratan Guptaaac603e2018-03-23 00:25:54 +0530189 }
190 if (channeltb[NCSI_CHANNEL_ATTR_VERSION_MINOR])
191 {
Jeremy Kerr7f7c0852024-08-08 11:32:55 +0800192 chan.version_minor =
Gunnar Mills57d9c502018-09-14 14:42:34 -0500193 nla_get_u32(channeltb[NCSI_CHANNEL_ATTR_VERSION_MINOR]);
Ratan Guptaaac603e2018-03-23 00:25:54 +0530194 }
195 if (channeltb[NCSI_CHANNEL_ATTR_VERSION_STR])
196 {
Jeremy Kerr7f7c0852024-08-08 11:32:55 +0800197 chan.version =
Gunnar Mills57d9c502018-09-14 14:42:34 -0500198 nla_get_string(channeltb[NCSI_CHANNEL_ATTR_VERSION_STR]);
Ratan Guptaaac603e2018-03-23 00:25:54 +0530199 }
200 if (channeltb[NCSI_CHANNEL_ATTR_LINK_STATE])
201 {
Jeremy Kerr7f7c0852024-08-08 11:32:55 +0800202 chan.link_state =
Gunnar Mills57d9c502018-09-14 14:42:34 -0500203 nla_get_u32(channeltb[NCSI_CHANNEL_ATTR_LINK_STATE]);
Ratan Guptaaac603e2018-03-23 00:25:54 +0530204 }
205 if (channeltb[NCSI_CHANNEL_ATTR_VLAN_LIST])
206 {
Ratan Guptaaac603e2018-03-23 00:25:54 +0530207 auto vids = channeltb[NCSI_CHANNEL_ATTR_VLAN_LIST];
208 auto vid = static_cast<nlattr*>(nla_data(vids));
209 auto len = nla_len(vids);
210 while (nla_ok(vid, len))
211 {
212 auto id = nla_get_u16(vid);
Jeremy Kerr7f7c0852024-08-08 11:32:55 +0800213 chan.vlan_ids.push_back(id);
Ratan Guptaaac603e2018-03-23 00:25:54 +0530214 vid = nla_next(vid, &len);
215 }
216 }
Jeremy Kerr7f7c0852024-08-08 11:32:55 +0800217 pkg.channels.push_back(chan);
Ratan Guptaaac603e2018-03-23 00:25:54 +0530218 }
Jeremy Kerr7f7c0852024-08-08 11:32:55 +0800219
220 info->info->packages.push_back(pkg);
Ratan Guptaaac603e2018-03-23 00:25:54 +0530221 }
Jeremy Kerrbea6cde2024-08-01 15:15:42 +0800222 return static_cast<int>(NL_STOP);
Ratan Guptaaac603e2018-03-23 00:25:54 +0530223};
224
Jeremy Kerr147086d2024-08-27 13:46:38 +0800225struct sendCallBackContext
226{
Jeremy Kerrb7885242024-09-16 12:43:36 +0800227 NCSIResponse resp;
Jeremy Kerr147086d2024-08-27 13:46:38 +0800228};
229
230CallBack sendCallBack = [](struct nl_msg* msg, void* arg) {
Eddie Jamesfa1f5c02020-09-17 15:12:46 -0500231 using namespace phosphor::network::ncsi;
232 auto nlh = nlmsg_hdr(msg);
233 struct nlattr* tb[NCSI_ATTR_MAX + 1] = {nullptr};
234 static struct nla_policy ncsiPolicy[NCSI_ATTR_MAX + 1] = {
235 {NLA_UNSPEC, 0, 0}, {NLA_U32, 0, 0}, {NLA_NESTED, 0, 0},
236 {NLA_U32, 0, 0}, {NLA_U32, 0, 0}, {NLA_BINARY, 0, 0},
237 {NLA_FLAG, 0, 0}, {NLA_U32, 0, 0}, {NLA_U32, 0, 0},
238 };
239
Jeremy Kerr147086d2024-08-27 13:46:38 +0800240 if (arg == nullptr)
241 {
242 lg2::error("Internal error: invalid send callback context");
243 return -1;
244 }
245
246 struct sendCallBackContext* ctx = (struct sendCallBackContext*)arg;
247
Eddie Jamesfa1f5c02020-09-17 15:12:46 -0500248 auto ret = genlmsg_parse(nlh, 0, tb, NCSI_ATTR_MAX, ncsiPolicy);
249 if (ret)
250 {
Jeremy Kerrde8d6662024-08-01 11:33:52 +0800251 lg2::error("Failed to parse message");
Eddie Jamesfa1f5c02020-09-17 15:12:46 -0500252 return ret;
253 }
254
Jian Zhang442d9e52022-10-20 22:11:14 +0800255 if (tb[NCSI_ATTR_DATA] == nullptr)
256 {
Jagpal Singh Gilld423beb2023-04-18 11:28:03 -0700257 lg2::error("Response: No data");
Jian Zhang442d9e52022-10-20 22:11:14 +0800258 return -1;
259 }
260
Jeremy Kerrb7885242024-09-16 12:43:36 +0800261 size_t data_len = nla_len(tb[NCSI_ATTR_DATA]);
262 unsigned char* data = (unsigned char*)nla_data(tb[NCSI_ATTR_DATA]);
Eddie Jamesfa1f5c02020-09-17 15:12:46 -0500263
Jeremy Kerrb7885242024-09-16 12:43:36 +0800264 ctx->resp.full_payload.assign(data, data + data_len);
265
266 int rc = ctx->resp.parseFullPayload();
267 if (rc)
268 {
269 return -1;
270 }
Eddie Jamesfa1f5c02020-09-17 15:12:46 -0500271
Jeremy Kerrbea6cde2024-08-01 15:15:42 +0800272 return static_cast<int>(NL_STOP);
Eddie Jamesfa1f5c02020-09-17 15:12:46 -0500273};
274
Jeremy Kerr3f34ff62024-09-12 13:00:27 +0800275int applyCmd(Interface& interface, const NetlinkCommand& cmd,
Jeremy Kerr8d9af022024-07-26 16:47:16 +0800276 int package = DEFAULT_VALUE, int channel = DEFAULT_VALUE,
Jeremy Kerr7f7c0852024-08-08 11:32:55 +0800277 int flags = NONE, CallBack function = nullptr, void* arg = nullptr)
Ratan Guptabbe45792018-03-23 00:22:55 +0530278{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500279 nlSocketPtr socket(nl_socket_alloc(), &::nl_socket_free);
Johnathan Manteyd49c5c62021-06-23 09:14:42 -0700280 if (socket == nullptr)
281 {
Jagpal Singh Gilld423beb2023-04-18 11:28:03 -0700282 lg2::error("Unable to allocate memory for the socket");
Johnathan Manteyd49c5c62021-06-23 09:14:42 -0700283 return -ENOMEM;
284 }
285
Jeremy Kerrbea6cde2024-08-01 15:15:42 +0800286 nl_socket_disable_auto_ack(socket.get());
287
Ratan Guptabbe45792018-03-23 00:22:55 +0530288 auto ret = genl_connect(socket.get());
289 if (ret < 0)
290 {
Jagpal Singh Gilld423beb2023-04-18 11:28:03 -0700291 lg2::error("Failed to open the socket , RC : {RC}", "RC", ret);
Ratan Guptabbe45792018-03-23 00:22:55 +0530292 return ret;
293 }
294
295 auto driverID = genl_ctrl_resolve(socket.get(), "NCSI");
296 if (driverID < 0)
297 {
Jagpal Singh Gilld423beb2023-04-18 11:28:03 -0700298 lg2::error("Failed to resolve, RC : {RC}", "RC", ret);
Ratan Guptabbe45792018-03-23 00:22:55 +0530299 return driverID;
300 }
301
302 nlMsgPtr msg(nlmsg_alloc(), &::nlmsg_free);
Johnathan Manteyd49c5c62021-06-23 09:14:42 -0700303 if (msg == nullptr)
304 {
Jagpal Singh Gilld423beb2023-04-18 11:28:03 -0700305 lg2::error("Unable to allocate memory for the message");
Johnathan Manteyd49c5c62021-06-23 09:14:42 -0700306 return -ENOMEM;
307 }
Ratan Guptabbe45792018-03-23 00:22:55 +0530308
Johnathan Mantey1ebea282024-02-15 10:26:06 -0800309 auto msgHdr = genlmsg_put(msg.get(), NL_AUTO_PORT, NL_AUTO_SEQ, driverID, 0,
310 flags, cmd.ncsi_cmd, 0);
Ratan Guptabbe45792018-03-23 00:22:55 +0530311 if (!msgHdr)
312 {
Jagpal Singh Gilld423beb2023-04-18 11:28:03 -0700313 lg2::error("Unable to add the netlink headers , COMMAND : {COMMAND}",
Johnathan Mantey1ebea282024-02-15 10:26:06 -0800314 "COMMAND", cmd.ncsi_cmd);
Johnathan Manteyd49c5c62021-06-23 09:14:42 -0700315 return -ENOMEM;
Ratan Guptabbe45792018-03-23 00:22:55 +0530316 }
317
318 if (package != DEFAULT_VALUE)
319 {
320 ret = nla_put_u32(msg.get(), ncsi_nl_attrs::NCSI_ATTR_PACKAGE_ID,
321 package);
322 if (ret < 0)
323 {
Jagpal Singh Gilld423beb2023-04-18 11:28:03 -0700324 lg2::error("Failed to set the attribute , RC : {RC} PACKAGE "
325 "{PACKAGE}",
326 "RC", ret, "PACKAGE", lg2::hex, package);
Ratan Guptabbe45792018-03-23 00:22:55 +0530327 return ret;
328 }
329 }
330
331 if (channel != DEFAULT_VALUE)
332 {
333 ret = nla_put_u32(msg.get(), ncsi_nl_attrs::NCSI_ATTR_CHANNEL_ID,
334 channel);
335 if (ret < 0)
336 {
Jagpal Singh Gilld423beb2023-04-18 11:28:03 -0700337 lg2::error("Failed to set the attribute , RC : {RC} CHANNEL : "
338 "{CHANNEL}",
339 "RC", ret, "CHANNEL", lg2::hex, channel);
Ratan Guptabbe45792018-03-23 00:22:55 +0530340 return ret;
341 }
342 }
343
Jeremy Kerr8d9af022024-07-26 16:47:16 +0800344 ret = nla_put_u32(msg.get(), ncsi_nl_attrs::NCSI_ATTR_IFINDEX,
345 interface.ifindex);
Ratan Guptabbe45792018-03-23 00:22:55 +0530346 if (ret < 0)
347 {
Jagpal Singh Gilld423beb2023-04-18 11:28:03 -0700348 lg2::error("Failed to set the attribute , RC : {RC} INTERFACE : "
349 "{INTERFACE}",
Jeremy Kerr8a76d892024-07-26 17:19:57 +0800350 "RC", ret, "INTERFACE", interface);
Ratan Guptabbe45792018-03-23 00:22:55 +0530351 return ret;
352 }
353
Johnathan Mantey5a456062024-02-15 08:45:08 -0800354 if ((cmd.ncsi_cmd == ncsi_nl_commands::NCSI_CMD_SET_PACKAGE_MASK) ||
355 (cmd.ncsi_cmd == ncsi_nl_commands::NCSI_CMD_SET_CHANNEL_MASK))
356 {
357 if (cmd.payload.size() != sizeof(unsigned int))
358 {
359 lg2::error("Package/Channel mask must be 32-bits");
360 return -EINVAL;
361 }
362 int maskAttr =
363 cmd.ncsi_cmd == ncsi_nl_commands::NCSI_CMD_SET_PACKAGE_MASK
364 ? NCSI_ATTR_PACKAGE_MASK
365 : NCSI_ATTR_CHANNEL_MASK;
366 ret = nla_put_u32(
367 msg.get(), maskAttr,
368 *(reinterpret_cast<const unsigned int*>(cmd.payload.data())));
369 if (ret < 0)
370 {
371 lg2::error("Failed to set the mask attribute, RC : {RC}", "RC",
372 ret);
373 return ret;
374 }
375 }
376 else if (cmd.ncsi_cmd == ncsi_nl_commands::NCSI_CMD_SEND_CMD)
Eddie Jamesfa1f5c02020-09-17 15:12:46 -0500377 {
Patrick Williamsad205022024-08-16 15:20:07 -0400378 std::vector<unsigned char> pl(
379 sizeof(NCSIPacketHeader) + cmd.payload.size());
Eddie Jamesfa1f5c02020-09-17 15:12:46 -0500380 NCSIPacketHeader* hdr = (NCSIPacketHeader*)pl.data();
381
382 std::copy(cmd.payload.begin(), cmd.payload.end(),
383 pl.begin() + sizeof(NCSIPacketHeader));
384
Johnathan Mantey1ebea282024-02-15 10:26:06 -0800385 hdr->type = cmd.operation;
Eddie Jamesfa1f5c02020-09-17 15:12:46 -0500386 hdr->length = htons(cmd.payload.size());
387
388 ret = nla_put(msg.get(), ncsi_nl_attrs::NCSI_ATTR_DATA, pl.size(),
389 pl.data());
390 if (ret < 0)
391 {
Jagpal Singh Gilld423beb2023-04-18 11:28:03 -0700392 lg2::error("Failed to set the data attribute, RC : {RC}", "RC",
393 ret);
Eddie Jamesfa1f5c02020-09-17 15:12:46 -0500394 return ret;
395 }
396
397 nl_socket_disable_seq_check(socket.get());
398 }
399
Jeremy Kerr67b159a2024-08-01 15:23:57 +0800400 // Add a callback function to the socket
401 enum nl_cb_kind cb_kind = function ? NL_CB_CUSTOM : NL_CB_DEFAULT;
Jeremy Kerr7f7c0852024-08-08 11:32:55 +0800402 nl_socket_modify_cb(socket.get(), NL_CB_VALID, cb_kind, function, arg);
Ratan Guptabbe45792018-03-23 00:22:55 +0530403
404 ret = nl_send_auto(socket.get(), msg.get());
405 if (ret < 0)
406 {
Jagpal Singh Gilld423beb2023-04-18 11:28:03 -0700407 lg2::error("Failed to send the message , RC : {RC}", "RC", ret);
Ratan Guptabbe45792018-03-23 00:22:55 +0530408 return ret;
409 }
410
Jeremy Kerrbea6cde2024-08-01 15:15:42 +0800411 ret = nl_recvmsgs_default(socket.get());
412 if (ret < 0)
Ratan Guptabbe45792018-03-23 00:22:55 +0530413 {
Jeremy Kerrbea6cde2024-08-01 15:15:42 +0800414 lg2::error("Failed to receive the message , RC : {RC}", "RC", ret);
415 return ret;
416 }
Eddie Jamesfa1f5c02020-09-17 15:12:46 -0500417
Jeremy Kerrbea6cde2024-08-01 15:15:42 +0800418 return 0;
Ratan Guptabbe45792018-03-23 00:22:55 +0530419}
420
Gunnar Mills57d9c502018-09-14 14:42:34 -0500421} // namespace internal
Ratan Guptabbe45792018-03-23 00:22:55 +0530422
Jeremy Kerr8a76d892024-07-26 17:19:57 +0800423std::string to_string(Interface& interface)
424{
425 return std::to_string(interface.ifindex);
426}
427
Jeremy Kerrb7885242024-09-16 12:43:36 +0800428std::optional<NCSIResponse> Interface::sendCommand(NCSICommand& cmd)
Eddie Jamesfa1f5c02020-09-17 15:12:46 -0500429{
Jeremy Kerrb7885242024-09-16 12:43:36 +0800430 lg2::debug("Send Command, CHANNEL : {CHANNEL} , PACKAGE : {PACKAGE}, "
Jeremy Kerr8a76d892024-07-26 17:19:57 +0800431 "INTERFACE: {INTERFACE}",
Jeremy Kerrb7885242024-09-16 12:43:36 +0800432 "CHANNEL", lg2::hex, cmd.getChannel(), "PACKAGE", lg2::hex,
433 cmd.package, "INTERFACE", this);
Eddie Jamesfa1f5c02020-09-17 15:12:46 -0500434
Jeremy Kerr147086d2024-08-27 13:46:38 +0800435 internal::sendCallBackContext ctx{};
436
Jeremy Kerrb7885242024-09-16 12:43:36 +0800437 internal::NetlinkCommand nl_cmd(ncsi_nl_commands::NCSI_CMD_SEND_CMD,
438 cmd.opcode, cmd.payload);
Jeremy Kerr3f34ff62024-09-12 13:00:27 +0800439
Jeremy Kerrb7885242024-09-16 12:43:36 +0800440 int rc = internal::applyCmd(*this, nl_cmd, cmd.package, cmd.getChannel(),
441 NONE, internal::sendCallBack, &ctx);
Jeremy Kerr147086d2024-08-27 13:46:38 +0800442
443 if (rc < 0)
444 {
445 return {};
446 }
447
Jeremy Kerrb7885242024-09-16 12:43:36 +0800448 return ctx.resp;
Eddie Jamesfa1f5c02020-09-17 15:12:46 -0500449}
450
Jeremy Kerrbc22f812024-07-29 17:43:35 +0800451int Interface::setChannel(int package, int channel)
Ratan Guptabbe45792018-03-23 00:22:55 +0530452{
Jeremy Kerr8a76d892024-07-26 17:19:57 +0800453 lg2::debug("Set CHANNEL : {CHANNEL} , PACKAGE : {PACKAGE}, INTERFACE : "
454 "{INTERFACE}",
455 "CHANNEL", lg2::hex, channel, "PACKAGE", lg2::hex, package,
Jeremy Kerrbc22f812024-07-29 17:43:35 +0800456 "INTERFACE", this);
Jeremy Kerr3f34ff62024-09-12 13:00:27 +0800457
458 internal::NetlinkCommand cmd(ncsi_nl_commands::NCSI_CMD_SET_INTERFACE);
459
460 return internal::applyCmd(*this, cmd, package, channel);
Ratan Guptabbe45792018-03-23 00:22:55 +0530461}
462
Jeremy Kerrbc22f812024-07-29 17:43:35 +0800463int Interface::clearInterface()
Ratan Guptabbe45792018-03-23 00:22:55 +0530464{
Jeremy Kerrbc22f812024-07-29 17:43:35 +0800465 lg2::debug("ClearInterface , INTERFACE : {INTERFACE}", "INTERFACE", this);
Jeremy Kerr3f34ff62024-09-12 13:00:27 +0800466
467 internal::NetlinkCommand cmd(ncsi_nl_commands::NCSI_CMD_CLEAR_INTERFACE);
468 return internal::applyCmd(*this, cmd);
Ratan Guptabbe45792018-03-23 00:22:55 +0530469}
470
Jeremy Kerr7f7c0852024-08-08 11:32:55 +0800471std::optional<InterfaceInfo> Interface::getInfo(int package)
Ratan Guptaaac603e2018-03-23 00:25:54 +0530472{
Jeremy Kerr7f7c0852024-08-08 11:32:55 +0800473 int rc, flags = package == DEFAULT_VALUE ? NLM_F_DUMP : NONE;
474 InterfaceInfo info;
475
Jeremy Kerr8a76d892024-07-26 17:19:57 +0800476 lg2::debug("Get Info , PACKAGE : {PACKAGE}, INTERFACE: {INTERFACE}",
Jeremy Kerrbc22f812024-07-29 17:43:35 +0800477 "PACKAGE", lg2::hex, package, "INTERFACE", this);
Jeremy Kerr7f7c0852024-08-08 11:32:55 +0800478
479 struct internal::infoCallBackContext ctx = {
480 .info = &info,
481 };
482
Jeremy Kerr3f34ff62024-09-12 13:00:27 +0800483 internal::NetlinkCommand cmd(ncsi_nl_commands::NCSI_CMD_PKG_INFO);
484
485 rc = internal::applyCmd(*this, cmd, package, DEFAULT_VALUE, flags,
486 internal::infoCallBack, &ctx);
Jeremy Kerr7f7c0852024-08-08 11:32:55 +0800487
488 if (rc < 0)
Ratan Guptaaac603e2018-03-23 00:25:54 +0530489 {
Jeremy Kerr7f7c0852024-08-08 11:32:55 +0800490 return {};
Ratan Guptaaac603e2018-03-23 00:25:54 +0530491 }
Jeremy Kerr7f7c0852024-08-08 11:32:55 +0800492
493 return info;
Ratan Guptaaac603e2018-03-23 00:25:54 +0530494}
495
Jeremy Kerrbc22f812024-07-29 17:43:35 +0800496int Interface::setPackageMask(unsigned int mask)
Johnathan Mantey5a456062024-02-15 08:45:08 -0800497{
Jeremy Kerr8a76d892024-07-26 17:19:57 +0800498 lg2::debug("Set Package Mask , INTERFACE: {INTERFACE} MASK: {MASK}",
Jeremy Kerrbc22f812024-07-29 17:43:35 +0800499 "INTERFACE", this, "MASK", lg2::hex, mask);
Johnathan Mantey5a456062024-02-15 08:45:08 -0800500 auto payload = std::span<const unsigned char>(
501 reinterpret_cast<const unsigned char*>(&mask),
502 reinterpret_cast<const unsigned char*>(&mask) + sizeof(decltype(mask)));
Jeremy Kerr3f34ff62024-09-12 13:00:27 +0800503
504 internal::NetlinkCommand cmd(ncsi_nl_commands::NCSI_CMD_SET_PACKAGE_MASK, 0,
505 payload);
506 return internal::applyCmd(*this, cmd);
Johnathan Mantey5a456062024-02-15 08:45:08 -0800507}
508
Jeremy Kerrbc22f812024-07-29 17:43:35 +0800509int Interface::setChannelMask(int package, unsigned int mask)
Johnathan Mantey5a456062024-02-15 08:45:08 -0800510{
511 lg2::debug(
Jeremy Kerr8a76d892024-07-26 17:19:57 +0800512 "Set Channel Mask , INTERFACE: {INTERFACE}, PACKAGE : {PACKAGE} MASK: {MASK}",
Jeremy Kerrbc22f812024-07-29 17:43:35 +0800513 "INTERFACE", this, "PACKAGE", lg2::hex, package, "MASK", lg2::hex,
Jeremy Kerr8a76d892024-07-26 17:19:57 +0800514 mask);
Johnathan Mantey5a456062024-02-15 08:45:08 -0800515 auto payload = std::span<const unsigned char>(
516 reinterpret_cast<const unsigned char*>(&mask),
517 reinterpret_cast<const unsigned char*>(&mask) + sizeof(decltype(mask)));
Jeremy Kerr3f34ff62024-09-12 13:00:27 +0800518
519 internal::NetlinkCommand cmd(ncsi_nl_commands::NCSI_CMD_SET_CHANNEL_MASK, 0,
520 payload);
521 return internal::applyCmd(*this, cmd);
Johnathan Mantey5a456062024-02-15 08:45:08 -0800522}
523
Jeremy Kerrb7885242024-09-16 12:43:36 +0800524int NCSIResponse::parseFullPayload()
525{
526 if (this->full_payload.size() < sizeof(internal::NCSIPacketHeader) +
527 sizeof(internal::NCSIResponsePayload))
528 {
529 lg2::error("Response: Not enough data for a response message");
530 return -1;
531 }
532
533 internal::NCSIPacketHeader* respHeader =
534 reinterpret_cast<decltype(respHeader)>(this->full_payload.data());
535
536 unsigned int payloadLen = ntohs(respHeader->length & htons(0x0fff));
537 /* we have determined that the payload size is larger than *respHeader,
538 * so cannot underflow here */
539 if (payloadLen > this->full_payload.size() - sizeof(*respHeader))
540 {
541 lg2::error("Invalid header length {HDRLEN} (vs {LEN}) in response",
542 "HDRLEN", payloadLen, "LEN",
543 this->full_payload.size() - sizeof(*respHeader));
544 return -1;
545 }
546
547 this->opcode = respHeader->type;
548 this->payload =
549 std::span(this->full_payload.begin() + sizeof(*respHeader), payloadLen);
550
551 internal::NCSIResponsePayload* respPayload =
552 reinterpret_cast<decltype(respPayload)>(this->payload.data());
553 this->response = ntohs(respPayload->response);
554 this->reason = ntohs(respPayload->reason);
555
556 return 0;
557}
558
Gunnar Mills57d9c502018-09-14 14:42:34 -0500559} // namespace ncsi
560} // namespace network
561} // namespace phosphor