blob: c9ac7b5c4a02513e9e0345cedc5f6f313b6f2a97 [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 Kerr2d0b48d2024-09-16 13:03:26 +0800275int applyCmd(NetlinkInterface& 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{
Jeremy Kerr2d0b48d2024-09-16 13:03:26 +0800425 return interface.toString();
Jeremy Kerr8a76d892024-07-26 17:19:57 +0800426}
427
Jeremy Kerr2d0b48d2024-09-16 13:03:26 +0800428NetlinkInterface::NetlinkInterface(int ifindex) : ifindex(ifindex) {}
429
430std::string NetlinkInterface::toString()
431{
432 return std::to_string(ifindex);
433}
434
435std::optional<NCSIResponse> NetlinkInterface::sendCommand(NCSICommand& cmd)
Eddie Jamesfa1f5c02020-09-17 15:12:46 -0500436{
Jeremy Kerrb7885242024-09-16 12:43:36 +0800437 lg2::debug("Send Command, CHANNEL : {CHANNEL} , PACKAGE : {PACKAGE}, "
Jeremy Kerr8a76d892024-07-26 17:19:57 +0800438 "INTERFACE: {INTERFACE}",
Jeremy Kerrb7885242024-09-16 12:43:36 +0800439 "CHANNEL", lg2::hex, cmd.getChannel(), "PACKAGE", lg2::hex,
440 cmd.package, "INTERFACE", this);
Eddie Jamesfa1f5c02020-09-17 15:12:46 -0500441
Jeremy Kerr147086d2024-08-27 13:46:38 +0800442 internal::sendCallBackContext ctx{};
443
Jeremy Kerrb7885242024-09-16 12:43:36 +0800444 internal::NetlinkCommand nl_cmd(ncsi_nl_commands::NCSI_CMD_SEND_CMD,
445 cmd.opcode, cmd.payload);
Jeremy Kerr3f34ff62024-09-12 13:00:27 +0800446
Jeremy Kerrb7885242024-09-16 12:43:36 +0800447 int rc = internal::applyCmd(*this, nl_cmd, cmd.package, cmd.getChannel(),
448 NONE, internal::sendCallBack, &ctx);
Jeremy Kerr147086d2024-08-27 13:46:38 +0800449
450 if (rc < 0)
451 {
452 return {};
453 }
454
Jeremy Kerrb7885242024-09-16 12:43:36 +0800455 return ctx.resp;
Eddie Jamesfa1f5c02020-09-17 15:12:46 -0500456}
457
Jeremy Kerr2d0b48d2024-09-16 13:03:26 +0800458int NetlinkInterface::setChannel(int package, int channel)
Ratan Guptabbe45792018-03-23 00:22:55 +0530459{
Jeremy Kerr8a76d892024-07-26 17:19:57 +0800460 lg2::debug("Set CHANNEL : {CHANNEL} , PACKAGE : {PACKAGE}, INTERFACE : "
461 "{INTERFACE}",
462 "CHANNEL", lg2::hex, channel, "PACKAGE", lg2::hex, package,
Jeremy Kerrbc22f812024-07-29 17:43:35 +0800463 "INTERFACE", this);
Jeremy Kerr3f34ff62024-09-12 13:00:27 +0800464
465 internal::NetlinkCommand cmd(ncsi_nl_commands::NCSI_CMD_SET_INTERFACE);
466
467 return internal::applyCmd(*this, cmd, package, channel);
Ratan Guptabbe45792018-03-23 00:22:55 +0530468}
469
Jeremy Kerr2d0b48d2024-09-16 13:03:26 +0800470int NetlinkInterface::clearInterface()
Ratan Guptabbe45792018-03-23 00:22:55 +0530471{
Jeremy Kerrbc22f812024-07-29 17:43:35 +0800472 lg2::debug("ClearInterface , INTERFACE : {INTERFACE}", "INTERFACE", this);
Jeremy Kerr3f34ff62024-09-12 13:00:27 +0800473
474 internal::NetlinkCommand cmd(ncsi_nl_commands::NCSI_CMD_CLEAR_INTERFACE);
475 return internal::applyCmd(*this, cmd);
Ratan Guptabbe45792018-03-23 00:22:55 +0530476}
477
Jeremy Kerr2d0b48d2024-09-16 13:03:26 +0800478std::optional<InterfaceInfo> NetlinkInterface::getInfo(int package)
Ratan Guptaaac603e2018-03-23 00:25:54 +0530479{
Jeremy Kerr7f7c0852024-08-08 11:32:55 +0800480 int rc, flags = package == DEFAULT_VALUE ? NLM_F_DUMP : NONE;
481 InterfaceInfo info;
482
Jeremy Kerr8a76d892024-07-26 17:19:57 +0800483 lg2::debug("Get Info , PACKAGE : {PACKAGE}, INTERFACE: {INTERFACE}",
Jeremy Kerrbc22f812024-07-29 17:43:35 +0800484 "PACKAGE", lg2::hex, package, "INTERFACE", this);
Jeremy Kerr7f7c0852024-08-08 11:32:55 +0800485
486 struct internal::infoCallBackContext ctx = {
487 .info = &info,
488 };
489
Jeremy Kerr3f34ff62024-09-12 13:00:27 +0800490 internal::NetlinkCommand cmd(ncsi_nl_commands::NCSI_CMD_PKG_INFO);
491
492 rc = internal::applyCmd(*this, cmd, package, DEFAULT_VALUE, flags,
493 internal::infoCallBack, &ctx);
Jeremy Kerr7f7c0852024-08-08 11:32:55 +0800494
495 if (rc < 0)
Ratan Guptaaac603e2018-03-23 00:25:54 +0530496 {
Jeremy Kerr7f7c0852024-08-08 11:32:55 +0800497 return {};
Ratan Guptaaac603e2018-03-23 00:25:54 +0530498 }
Jeremy Kerr7f7c0852024-08-08 11:32:55 +0800499
500 return info;
Ratan Guptaaac603e2018-03-23 00:25:54 +0530501}
502
Jeremy Kerr2d0b48d2024-09-16 13:03:26 +0800503int NetlinkInterface::setPackageMask(unsigned int mask)
Johnathan Mantey5a456062024-02-15 08:45:08 -0800504{
Jeremy Kerr8a76d892024-07-26 17:19:57 +0800505 lg2::debug("Set Package Mask , INTERFACE: {INTERFACE} MASK: {MASK}",
Jeremy Kerrbc22f812024-07-29 17:43:35 +0800506 "INTERFACE", this, "MASK", lg2::hex, mask);
Johnathan Mantey5a456062024-02-15 08:45:08 -0800507 auto payload = std::span<const unsigned char>(
508 reinterpret_cast<const unsigned char*>(&mask),
509 reinterpret_cast<const unsigned char*>(&mask) + sizeof(decltype(mask)));
Jeremy Kerr3f34ff62024-09-12 13:00:27 +0800510
511 internal::NetlinkCommand cmd(ncsi_nl_commands::NCSI_CMD_SET_PACKAGE_MASK, 0,
512 payload);
513 return internal::applyCmd(*this, cmd);
Johnathan Mantey5a456062024-02-15 08:45:08 -0800514}
515
Jeremy Kerr2d0b48d2024-09-16 13:03:26 +0800516int NetlinkInterface::setChannelMask(int package, unsigned int mask)
Johnathan Mantey5a456062024-02-15 08:45:08 -0800517{
518 lg2::debug(
Jeremy Kerr8a76d892024-07-26 17:19:57 +0800519 "Set Channel Mask , INTERFACE: {INTERFACE}, PACKAGE : {PACKAGE} MASK: {MASK}",
Jeremy Kerrbc22f812024-07-29 17:43:35 +0800520 "INTERFACE", this, "PACKAGE", lg2::hex, package, "MASK", lg2::hex,
Jeremy Kerr8a76d892024-07-26 17:19:57 +0800521 mask);
Johnathan Mantey5a456062024-02-15 08:45:08 -0800522 auto payload = std::span<const unsigned char>(
523 reinterpret_cast<const unsigned char*>(&mask),
524 reinterpret_cast<const unsigned char*>(&mask) + sizeof(decltype(mask)));
Jeremy Kerr3f34ff62024-09-12 13:00:27 +0800525
526 internal::NetlinkCommand cmd(ncsi_nl_commands::NCSI_CMD_SET_CHANNEL_MASK, 0,
527 payload);
528 return internal::applyCmd(*this, cmd);
Johnathan Mantey5a456062024-02-15 08:45:08 -0800529}
530
Jeremy Kerrb7885242024-09-16 12:43:36 +0800531int NCSIResponse::parseFullPayload()
532{
533 if (this->full_payload.size() < sizeof(internal::NCSIPacketHeader) +
534 sizeof(internal::NCSIResponsePayload))
535 {
536 lg2::error("Response: Not enough data for a response message");
537 return -1;
538 }
539
540 internal::NCSIPacketHeader* respHeader =
541 reinterpret_cast<decltype(respHeader)>(this->full_payload.data());
542
543 unsigned int payloadLen = ntohs(respHeader->length & htons(0x0fff));
544 /* we have determined that the payload size is larger than *respHeader,
545 * so cannot underflow here */
546 if (payloadLen > this->full_payload.size() - sizeof(*respHeader))
547 {
548 lg2::error("Invalid header length {HDRLEN} (vs {LEN}) in response",
549 "HDRLEN", payloadLen, "LEN",
550 this->full_payload.size() - sizeof(*respHeader));
551 return -1;
552 }
553
554 this->opcode = respHeader->type;
555 this->payload =
556 std::span(this->full_payload.begin() + sizeof(*respHeader), payloadLen);
557
558 internal::NCSIResponsePayload* respPayload =
559 reinterpret_cast<decltype(respPayload)>(this->payload.data());
560 this->response = ntohs(respPayload->response);
561 this->reason = ntohs(respPayload->reason);
562
563 return 0;
564}
565
Gunnar Mills57d9c502018-09-14 14:42:34 -0500566} // namespace ncsi
567} // namespace network
568} // namespace phosphor