| #include <linux/ncsi.h> |
| #include <netlink/netlink.h> |
| #include <netlink/genl/genl.h> |
| #include <netlink/genl/ctrl.h> |
| |
| #include "ncsi_util.hpp" |
| #include "xyz/openbmc_project/Common/error.hpp" |
| |
| #include <phosphor-logging/elog-errors.hpp> |
| #include <phosphor-logging/log.hpp> |
| |
| namespace phosphor |
| { |
| namespace network |
| { |
| namespace ncsi |
| { |
| |
| using namespace phosphor::logging; |
| using namespace sdbusplus::xyz::openbmc_project::Common::Error; |
| |
| namespace internal |
| { |
| |
| constexpr auto DEFAULT_VALUE = -1; |
| constexpr auto NONE = 0; |
| |
| using nlMsgPtr = std::unique_ptr<nl_msg, decltype(&::nlmsg_free)>; |
| using nlSocketPtr = std::unique_ptr<nl_sock, decltype(&::nl_socket_free)>; |
| |
| int applyCmd(int ifindex, int cmd, int package = DEFAULT_VALUE, |
| int channel = DEFAULT_VALUE, int flags = NONE) |
| { |
| nlSocketPtr socket(nl_socket_alloc(),&::nl_socket_free); |
| auto ret = genl_connect(socket.get()); |
| if (ret < 0) |
| { |
| log<level::ERR>("Failed to open the socket", |
| entry("RC=%d", ret)); |
| return ret; |
| } |
| |
| auto driverID = genl_ctrl_resolve(socket.get(), "NCSI"); |
| if (driverID < 0) |
| { |
| log<level::ERR>("Failed to resolve", |
| entry("RC=%d", ret)); |
| return driverID; |
| } |
| |
| nlMsgPtr msg(nlmsg_alloc(), &::nlmsg_free); |
| |
| auto msgHdr = genlmsg_put(msg.get(), 0, 0, driverID, 0, flags, |
| cmd, 0); |
| if (!msgHdr) |
| { |
| log<level::ERR>("Unable to add the netlink headers", |
| entry("COMMAND=%d", cmd)); |
| return -1; |
| } |
| |
| if (package != DEFAULT_VALUE) |
| { |
| ret = nla_put_u32(msg.get(), ncsi_nl_attrs::NCSI_ATTR_PACKAGE_ID, |
| package); |
| if (ret < 0) |
| { |
| log<level::ERR>("Failed to set the attribute", |
| entry("RC=%d", ret), |
| entry("PACKAGE=%x", package)); |
| return ret; |
| } |
| } |
| |
| if (channel != DEFAULT_VALUE) |
| { |
| ret = nla_put_u32(msg.get(), ncsi_nl_attrs::NCSI_ATTR_CHANNEL_ID, |
| channel); |
| if (ret < 0) |
| { |
| log<level::ERR>("Failed to set the attribute", |
| entry("RC=%d", ret), |
| entry("CHANNEL=%x", channel)); |
| return ret; |
| } |
| } |
| |
| ret = nla_put_u32(msg.get(), ncsi_nl_attrs::NCSI_ATTR_IFINDEX, ifindex); |
| if (ret < 0) |
| { |
| log<level::ERR>("Failed to set the attribute", |
| entry("RC=%d", ret), |
| entry("INTERFACE=%x", ifindex)); |
| return ret; |
| } |
| |
| |
| ret = nl_send_auto(socket.get(), msg.get()); |
| if (ret < 0) |
| { |
| log<level::ERR>("Failed to send the message", |
| entry("RC=%d", ret)); |
| return ret; |
| } |
| |
| ret = nl_recvmsgs_default(socket.get()); |
| if (ret < 0) |
| { |
| log<level::ERR>("Failed to recieve the message", |
| entry("RC=%d", ret)); |
| } |
| return ret; |
| } |
| |
| }//namespace internal |
| |
| int setChannel(int ifindex, int package, int channel) |
| { |
| return internal::applyCmd(ifindex, ncsi_nl_commands::NCSI_CMD_SET_INTERFACE, |
| package, channel); |
| } |
| |
| int clearInterface(int ifindex) |
| { |
| return internal::applyCmd(ifindex, |
| ncsi_nl_commands::NCSI_CMD_CLEAR_INTERFACE); |
| } |
| |
| }//namespace ncsi |
| }//namespace network |
| }//namespace phosphor |