Support broadcast message
1. Support send/recv broadcast message
2. Fix an issue of inconsistent addr between src addr of incoming message
and target addr of response
Tested:
1. CMC broadcast message can be sent and received (BNP)
2. IPMI command injected to i2c bus0 via IPMB header can return correct value (WFP)
Change-Id: Ic03ee4ef6552a40d20594c4abb337f71ae5763eb
Signed-off-by: Qiang XU <qiang.xu@linux.intel.com>
diff --git a/ipmbbridged.cpp b/ipmbbridged.cpp
index 8104043..22bc9c6 100644
--- a/ipmbbridged.cpp
+++ b/ipmbbridged.cpp
@@ -26,11 +26,6 @@
#include <tuple>
#include <unordered_map>
-extern "C" {
-#include <i2c/smbus.h>
-#include <linux/i2c-dev.h>
-}
-
/**
* @brief Dbus
*/
@@ -113,7 +108,7 @@
ipmbBuffer->Header.Req.rqSeqLUN = ipmbSeqLunSet(seq, rqLun);
ipmbBuffer->Header.Req.cmd = cmd;
- ipmbBuffer->Header.Resp.checksum1 = ipmbChecksumCompute(
+ ipmbBuffer->Header.Req.checksum1 = ipmbChecksumCompute(
buffer.data(), ipmbConnectionHeaderLength - ipmbChecksumSize);
if (data.size() > 0)
@@ -254,29 +249,37 @@
/**
* @brief Ipmb channel
*/
-void IpmbChannel::ipmbResponseSend(std::shared_ptr<std::vector<uint8_t>> buffer,
+void IpmbChannel::ipmbSendI2cFrame(std::shared_ptr<std::vector<uint8_t>> buffer,
size_t retriesAttempted = 0)
{
- boost::asio::async_write(
- i2cMasterSocket,
- boost::asio::buffer(buffer->data() + ipmbAddressSize,
- buffer->size() - ipmbAddressSize),
- [this, buffer, retriesAttempted](const boost::system::error_code &ec,
- size_t bytesSent) {
- if (ec)
+ // construct i2c frame and call ioctl to send it
+ auto ipmbFrame = reinterpret_cast<IPMB_HEADER *>(buffer->data());
+ uint8_t targetAddr = ipmbIsResponse(ipmbFrame)
+ ? ipmbFrame->Header.Resp.address
+ : ipmbFrame->Header.Req.address;
+ io.post([this, buffer, retriesAttempted, targetAddr]() {
+ ioWrite ioData(*buffer);
+ boost::system::error_code ec;
+ i2cMasterSocket.io_control(ioData, ec);
+ if (ec)
+ {
+ size_t currentRetryCnt = retriesAttempted;
+ if (currentRetryCnt > ipmbI2cNumberOfRetries)
{
- size_t currentRetryCnt = retriesAttempted;
-
- if (currentRetryCnt > ipmbI2cNumberOfRetries)
- {
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "ipmbResponseSend: sent to I2C failed after retries");
- return;
- }
- currentRetryCnt++;
- ipmbResponseSend(buffer, currentRetryCnt);
+ std::string msgToLog =
+ "ipmbSendI2cFrame: sent to I2C failed after retries."
+ " busId=" +
+ std::to_string(ipmbBusId) +
+ ", targetAddr=" + std::to_string(targetAddr) +
+ ", error=" + ec.message();
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ msgToLog.c_str());
+ return;
}
- });
+ currentRetryCnt++;
+ ipmbSendI2cFrame(buffer, currentRetryCnt);
+ }
+ });
}
/**
@@ -356,8 +359,21 @@
goto end;
}
+ // if it is broadcast message from ipmb channel, send out dbus signal
+ if (ipmbFrame->Header.Req.address == broadcastAddress &&
+ getChannelType() == ipmbChannelType::ipmb)
+ {
+ auto ipmbMessageReceived = IpmbRequest();
+ ipmbMessageReceived.i2cToIpmbConstruct(ipmbFrame, r);
+ sdbusplus::message::message msg =
+ conn->new_signal(ipmbObj, ipmbDbusIntf, "receiveBroadcast");
+ msg.append(ipmbMessageReceived.netFn, ipmbMessageReceived.cmd,
+ ipmbMessageReceived.data);
+ msg.signal_send();
+ }
+
// copy frame to ipmib message buffer
- if (ipmbIsResponse(ipmbFrame))
+ else if (ipmbIsResponse(ipmbFrame))
{
std::unique_ptr<IpmbResponse> ipmbMessageReceived =
std::make_unique<IpmbResponse>();
@@ -375,6 +391,7 @@
{
uint8_t netFn = ipmbNetFnGet(ipmbFrame->Header.Req.rsNetFnLUN);
uint8_t cmd = ipmbFrame->Header.Req.cmd;
+ uint8_t rqSA = ipmbFrame->Header.Req.rqSA;
if (commandFilter->isBlocked(netFn, cmd))
{
@@ -383,15 +400,14 @@
ipmbLunFromSeqLunGet(ipmbFrame->Header.Req.rqSeqLUN);
// prepare generic response
- auto ipmbResponse =
- IpmbResponse(ipmbRqSlaveAddress, ipmbRespNetFn(netFn), lun,
- ipmbBmcSlaveAddress, seq, ipmbRsLun, cmd,
- ipmbIpmiInvalidCmd, {});
+ auto ipmbResponse = IpmbResponse(
+ rqSA, ipmbRespNetFn(netFn), lun, ipmbBmcSlaveAddress, seq,
+ ipmbRsLun, cmd, ipmbIpmiInvalidCmd, {});
auto buffer = ipmbResponse.ipmbToi2cConstruct();
if (buffer)
{
- ipmbResponseSend(buffer);
+ ipmbSendI2cFrame(buffer);
}
goto end;
@@ -402,13 +418,14 @@
ipmbMessageReceived.i2cToIpmbConstruct(ipmbFrame, r);
std::map<std::string, std::variant<int>> options{
- {"rqSA", ipmbAddressTo7BitSet(ipmbRqSlaveAddress)}};
+ {"rqSA", ipmbAddressTo7BitSet(ipmbMessageReceived.rqSA)}};
using IpmiDbusRspType = std::tuple<uint8_t, uint8_t, uint8_t, uint8_t,
std::vector<uint8_t>>;
conn->async_method_call(
[this, rqLun{ipmbMessageReceived.rqLun},
- seq{ipmbMessageReceived.seq}](const boost::system::error_code &ec,
- const IpmiDbusRspType &response) {
+ seq{ipmbMessageReceived.seq}, address{ipmbMessageReceived.rqSA}](
+ const boost::system::error_code &ec,
+ const IpmiDbusRspType &response) {
const auto &[netfn, lun, cmd, cc, payload] = response;
if (ec)
{
@@ -417,7 +434,6 @@
return;
}
- uint8_t rqSlaveAddress = getRqSlaveAddress();
uint8_t bmcSlaveAddress = getBmcSlaveAddress();
if (payload.size() > ipmbMaxDataSize)
@@ -427,13 +443,13 @@
// prepare generic response
auto ipmbResponse = IpmbResponse(
- rqSlaveAddress, netfn, rqLun, bmcSlaveAddress, seq,
- ipmbRsLun, cmd, ipmbIpmiCmdRespNotProvided, {});
+ address, netfn, rqLun, bmcSlaveAddress, seq, ipmbRsLun,
+ cmd, ipmbIpmiCmdRespNotProvided, {});
auto buffer = ipmbResponse.ipmbToi2cConstruct();
if (buffer)
{
- ipmbResponseSend(buffer);
+ ipmbSendI2cFrame(buffer);
}
return;
@@ -455,8 +471,8 @@
// payload is empty after constructor invocation
auto ipmbResponse =
- IpmbResponse(rqSlaveAddress, netfn, rqLun, bmcSlaveAddress,
- seq, lun, cmd, cc, payload);
+ IpmbResponse(address, netfn, rqLun, bmcSlaveAddress, seq,
+ lun, cmd, cc, payload);
auto buffer = ipmbResponse.ipmbToi2cConstruct();
if (!buffer)
@@ -466,7 +482,7 @@
return;
}
- ipmbResponseSend(buffer);
+ ipmbSendI2cFrame(buffer);
},
"xyz.openbmc_project.Ipmi.Host", "/xyz/openbmc_project/Ipmi",
"xyz.openbmc_project.Ipmi.Server", "execute",
@@ -665,6 +681,8 @@
processI2cEvent();
});
+ ipmbBmcSlaveAddress = newBmcSlaveAddr;
+
return 0;
}
@@ -730,8 +748,12 @@
if (i2cRetryCnt == ipmbI2cNumberOfRetries)
{
+ std::string msgToLog =
+ "requestAdd: Sent to I2C failed after retries."
+ " busId=" +
+ std::to_string(ipmbBusId) + ", error=" + ec.message();
phosphor::logging::log<phosphor::logging::level::INFO>(
- "requestAdd: Sent to I2C failed after retries");
+ msgToLog.c_str());
}
request->timer->expires_after(
@@ -914,6 +936,50 @@
"type='signal',member='updateBmcSlaveAddr',", updateSlaveAddrHandler);
}
+void addSendBroadcastHandler()
+{
+ // callback to handle dbus signal of sending broadcast message
+ std::function<void(sdbusplus::message::message &)> sendBroadcastHandler =
+ [](sdbusplus::message::message &message) {
+ uint8_t reqChannel, netFn, lun, cmd;
+ std::vector<uint8_t> dataReceived;
+ message.read(reqChannel, netFn, lun, cmd, dataReceived);
+
+ IpmbChannel *channel =
+ getChannel(static_cast<ipmbChannelType>(reqChannel));
+ if (channel == nullptr)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "addSendBroadcastMsgHandler: requested channel does not "
+ "exist");
+ return;
+ }
+
+ uint8_t bmcSlaveAddress = channel->getBmcSlaveAddress();
+ uint8_t seqNum = 0; // seqNum is not used in broadcast msg
+ uint8_t targetAddr = broadcastAddress;
+
+ std::shared_ptr<IpmbRequest> request =
+ std::make_shared<IpmbRequest>(targetAddr, netFn, ipmbRsLun,
+ bmcSlaveAddress, seqNum, lun, cmd,
+ dataReceived);
+
+ std::shared_ptr<std::vector<uint8_t>> buffer =
+ std::make_shared<std::vector<uint8_t>>();
+
+ if (request->ipmbToi2cConstruct(*buffer) != 0)
+ {
+ return;
+ }
+
+ channel->ipmbSendI2cFrame(buffer);
+ };
+
+ static auto match = std::make_unique<sdbusplus::bus::match::match>(
+ static_cast<sdbusplus::bus::bus &>(*conn),
+ "type='signal',member='sendBroadcast',", sendBroadcastHandler);
+}
+
/**
* @brief Main
*/
@@ -938,6 +1004,8 @@
addUpdateSlaveAddrHandler();
+ addSendBroadcastHandler();
+
io.run();
return 0;
}
diff --git a/ipmbbridged.hpp b/ipmbbridged.hpp
index 01b2f44..d781e17 100644
--- a/ipmbbridged.hpp
+++ b/ipmbbridged.hpp
@@ -21,6 +21,11 @@
#include <sdbusplus/message.hpp>
#include <vector>
+extern "C" {
+#include <i2c/smbus.h>
+#include <linux/i2c-dev.h>
+}
+
#ifndef IPMBBRIDGED_HPP
#define IPMBBRIDGED_HPP
@@ -49,6 +54,11 @@
constexpr uint8_t ipmbI2cNumberOfRetries = 2;
/**
+ * @brief Ipmb boardcast address
+ */
+constexpr uint8_t broadcastAddress = 0x0;
+
+/**
* @brief Ipmb defines
*/
constexpr size_t ipmbMaxDataSize = 256;
@@ -273,7 +283,7 @@
void processI2cEvent();
- void ipmbResponseSend(std::shared_ptr<std::vector<uint8_t>> buffer,
+ void ipmbSendI2cFrame(std::shared_ptr<std::vector<uint8_t>> buffer,
size_t retriesAttempted);
std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
@@ -309,4 +319,36 @@
void makeRequestValid(std::shared_ptr<IpmbRequest> request);
};
+/**
+ * @brief ioWrite class declaration
+ */
+class ioWrite
+{
+ public:
+ ioWrite(std::vector<uint8_t> &buffer)
+ {
+ i2cmsg[0].addr = ipmbAddressTo7BitSet(buffer[0]);
+ i2cmsg[0].len = buffer.size() - ipmbAddressSize;
+ i2cmsg[0].buf = buffer.data() + ipmbAddressSize;
+
+ msgRdwr.msgs = i2cmsg;
+ msgRdwr.nmsgs = 1;
+ };
+
+ int name()
+ {
+ return static_cast<int>(I2C_RDWR);
+ }
+
+ void *data()
+ {
+ return &msgRdwr;
+ }
+
+ private:
+ int myname;
+ i2c_rdwr_ioctl_data msgRdwr = {0};
+ i2c_msg i2cmsg[1] = {0};
+};
+
#endif