blob: a2bcf6b740ecba6b2fe0b70065f58d944b7d8058 [file] [log] [blame]
Dawid Fryckia642a942018-06-12 10:44:23 -07001/* Copyright 2018 Intel
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "ipmbbridged.hpp"
17
18#include "ipmbdefines.hpp"
19#include "ipmbutils.hpp"
20
Qiang XU8edcf1a2019-06-14 22:18:15 +080021#include <boost/algorithm/string/replace.hpp>
Ed Tanous1486b8a2023-02-28 13:28:59 -080022#include <boost/asio/io_context.hpp>
Ed Tanous09027c02020-08-31 17:28:36 -070023#include <boost/asio/write.hpp>
Patrick Williamsfe0d38a2023-03-30 14:51:33 -050024#include <nlohmann/json.hpp>
25#include <phosphor-logging/log.hpp>
26
Qiang XU8edcf1a2019-06-14 22:18:15 +080027#include <filesystem>
Amithash Prasad314862d2019-03-26 11:14:03 -070028#include <fstream>
Jason M. Bills7867cd72023-03-29 07:58:02 -070029#include <list>
Dawid Fryckia642a942018-06-12 10:44:23 -070030#include <tuple>
Amithash Prasad314862d2019-03-26 11:14:03 -070031#include <unordered_map>
Dawid Fryckia642a942018-06-12 10:44:23 -070032
Dawid Fryckia642a942018-06-12 10:44:23 -070033/**
34 * @brief Dbus
35 */
Patrick Williamsfe0d38a2023-03-30 14:51:33 -050036static constexpr const char* ipmbBus = "xyz.openbmc_project.Ipmi.Channel.Ipmb";
37static constexpr const char* ipmbObj = "/xyz/openbmc_project/Ipmi/Channel/Ipmb";
38static constexpr const char* ipmbDbusIntf = "org.openbmc.Ipmb";
Dawid Fryckia642a942018-06-12 10:44:23 -070039
Ed Tanous1486b8a2023-02-28 13:28:59 -080040boost::asio::io_context io;
Dawid Fryckia642a942018-06-12 10:44:23 -070041auto conn = std::make_shared<sdbusplus::asio::connection>(io);
42
Dawid Fryckia642a942018-06-12 10:44:23 -070043static std::list<IpmbChannel> ipmbChannels;
Amithash Prasad314862d2019-03-26 11:14:03 -070044static const std::unordered_map<std::string, ipmbChannelType>
45 ipmbChannelTypeMap = {{"me", ipmbChannelType::me},
46 {"ipmb", ipmbChannelType::ipmb}};
Dawid Fryckia642a942018-06-12 10:44:23 -070047
48/**
49 * @brief Ipmb request class methods
50 */
51IpmbRequest::IpmbRequest()
52{
53 data.reserve(ipmbMaxDataSize);
54}
55
56IpmbRequest::IpmbRequest(uint8_t address, uint8_t netFn, uint8_t rsLun,
57 uint8_t rqSA, uint8_t seq, uint8_t rqLun, uint8_t cmd,
Patrick Williamsfe0d38a2023-03-30 14:51:33 -050058 const std::vector<uint8_t>& inputData) :
Patrick Williams9898d612024-08-16 15:21:15 -040059 address(address), netFn(netFn), rsLun(rsLun), rqSA(rqSA), seq(seq),
60 rqLun(rqLun), cmd(cmd), timer(io)
Dawid Fryckia642a942018-06-12 10:44:23 -070061{
62 data.reserve(ipmbMaxDataSize);
63 state = ipmbRequestState::invalid;
64
65 if (inputData.size() > 0)
66 {
67 data = std::move(inputData);
68 }
69}
70
Patrick Williamsfe0d38a2023-03-30 14:51:33 -050071void IpmbRequest::i2cToIpmbConstruct(IPMB_HEADER* ipmbBuffer,
Dawid Fryckia642a942018-06-12 10:44:23 -070072 size_t bufferLength)
73{
74 // constructing ipmb request from i2c buffer
75 netFn = ipmbNetFnGet(ipmbBuffer->Header.Req.rsNetFnLUN);
76 rsLun = ipmbLunFromNetFnLunGet(ipmbBuffer->Header.Req.rsNetFnLUN);
77 rqSA = ipmbBuffer->Header.Req.rqSA;
78 seq = ipmbSeqGet(ipmbBuffer->Header.Req.rqSeqLUN);
79 rqLun = ipmbLunFromSeqLunGet(ipmbBuffer->Header.Req.rqSeqLUN);
80 cmd = ipmbBuffer->Header.Req.cmd;
81
Patrick Williams9898d612024-08-16 15:21:15 -040082 size_t dataLength =
83 bufferLength - (ipmbConnectionHeaderLength +
84 ipmbRequestDataHeaderLength + ipmbChecksumSize);
Dawid Fryckia642a942018-06-12 10:44:23 -070085
86 if (dataLength > 0)
87 {
88 data.insert(data.end(), ipmbBuffer->Header.Req.data,
89 &ipmbBuffer->Header.Req.data[dataLength]);
90 }
91}
92
Patrick Williamsfe0d38a2023-03-30 14:51:33 -050093int IpmbRequest::ipmbToi2cConstruct(std::vector<uint8_t>& buffer)
Dawid Fryckia642a942018-06-12 10:44:23 -070094{
Vijay Khemka37a7eac2019-12-06 13:52:28 -080095 /* Add one byte for length byte as per required by driver */
96 size_t bufferLength = 1 + data.size() + ipmbRequestDataHeaderLength +
Dawid Fryckia642a942018-06-12 10:44:23 -070097 ipmbConnectionHeaderLength + ipmbChecksumSize;
98
99 if (bufferLength > ipmbMaxFrameLength)
100 {
101 return -1;
102 }
103
104 buffer.resize(bufferLength);
105 static_assert(ipmbMaxFrameLength >= sizeof(IPMB_HEADER));
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500106 IPMB_PKT* ipmbPkt = reinterpret_cast<IPMB_PKT*>(buffer.data());
Vijay Khemka37a7eac2019-12-06 13:52:28 -0800107 ipmbPkt->len = bufferLength - 1;
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500108 IPMB_HEADER* ipmbBuffer = &(ipmbPkt->hdr);
Dawid Fryckia642a942018-06-12 10:44:23 -0700109
110 // constructing buffer from ipmb request
111 ipmbBuffer->Header.Req.address = address;
112 ipmbBuffer->Header.Req.rsNetFnLUN = ipmbNetFnLunSet(netFn, rsLun);
113 ipmbBuffer->Header.Req.rqSA = rqSA;
114 ipmbBuffer->Header.Req.rqSeqLUN = ipmbSeqLunSet(seq, rqLun);
115 ipmbBuffer->Header.Req.cmd = cmd;
116
Qiang XUbbfd00a2019-06-27 21:10:06 +0800117 ipmbBuffer->Header.Req.checksum1 = ipmbChecksumCompute(
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500118 (uint8_t*)ipmbBuffer, ipmbConnectionHeaderLength - ipmbChecksumSize);
Dawid Fryckia642a942018-06-12 10:44:23 -0700119
120 if (data.size() > 0)
121 {
122 std::copy(data.begin(), data.end(), ipmbBuffer->Header.Req.data);
123 }
124
125 buffer[bufferLength - ipmbChecksumSize] =
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500126 ipmbChecksumCompute((uint8_t*)ipmbBuffer + ipmbChecksum2StartOffset,
Dawid Fryckia642a942018-06-12 10:44:23 -0700127 (ipmbRequestDataHeaderLength + data.size()));
128
129 return 0;
130}
131
132std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
133 IpmbRequest::returnMatchedResponse()
134{
135 return std::make_tuple(
136 static_cast<int>(ipmbResponseStatus::success), matchedResponse->netFn,
137 matchedResponse->rsLun, matchedResponse->cmd,
138 matchedResponse->completionCode, matchedResponse->data);
139}
140
141static std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
142 returnStatus(ipmbResponseStatus status)
143{
144 // we only want to send status here, other fields are not relevant
145 return std::make_tuple(static_cast<int>(status), 0, 0, 0, 0,
146 std::vector<uint8_t>(0));
147}
148
Dawid Fryckia642a942018-06-12 10:44:23 -0700149/**
150 * @brief Ipmb response class methods
151 */
152IpmbResponse::IpmbResponse()
153{
154 data.reserve(ipmbMaxDataSize);
155}
156
157IpmbResponse::IpmbResponse(uint8_t address, uint8_t netFn, uint8_t rqLun,
158 uint8_t rsSA, uint8_t seq, uint8_t rsLun,
159 uint8_t cmd, uint8_t completionCode,
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500160 const std::vector<uint8_t>& inputData) :
Patrick Williams9898d612024-08-16 15:21:15 -0400161 address(address), netFn(netFn), rqLun(rqLun), rsSA(rsSA), seq(seq),
162 rsLun(rsLun), cmd(cmd), completionCode(completionCode)
Dawid Fryckia642a942018-06-12 10:44:23 -0700163{
164 data.reserve(ipmbMaxDataSize);
165
166 if (inputData.size() > 0)
167 {
168 data = std::move(inputData);
169 }
170}
171
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500172void IpmbResponse::i2cToIpmbConstruct(IPMB_HEADER* ipmbBuffer,
Dawid Fryckia642a942018-06-12 10:44:23 -0700173 size_t bufferLength)
174{
175 netFn = ipmbNetFnGet(ipmbBuffer->Header.Resp.rqNetFnLUN);
176 rqLun = ipmbLunFromNetFnLunGet(ipmbBuffer->Header.Resp.rqNetFnLUN);
177 rsSA = ipmbBuffer->Header.Resp.rsSA;
178 seq = ipmbSeqGet(ipmbBuffer->Header.Resp.rsSeqLUN);
179 rsLun = ipmbLunFromSeqLunGet(ipmbBuffer->Header.Resp.rsSeqLUN);
180 cmd = ipmbBuffer->Header.Resp.cmd;
181 completionCode = ipmbBuffer->Header.Resp.completionCode;
182
Patrick Williams9898d612024-08-16 15:21:15 -0400183 size_t dataLength =
184 bufferLength - (ipmbConnectionHeaderLength +
185 ipmbResponseDataHeaderLength + ipmbChecksumSize);
Dawid Fryckia642a942018-06-12 10:44:23 -0700186
187 if (dataLength > 0)
188 {
189 data.insert(data.end(), ipmbBuffer->Header.Resp.data,
190 &ipmbBuffer->Header.Resp.data[dataLength]);
191 }
192}
193
Dawid Frycki8188d762019-04-01 18:03:48 -0700194std::shared_ptr<std::vector<uint8_t>> IpmbResponse::ipmbToi2cConstruct()
Dawid Fryckia642a942018-06-12 10:44:23 -0700195{
Vijay Khemka37a7eac2019-12-06 13:52:28 -0800196 /* Add one byte for length byte as per required by driver */
197 size_t bufferLength = 1 + data.size() + ipmbResponseDataHeaderLength +
Dawid Fryckia642a942018-06-12 10:44:23 -0700198 ipmbConnectionHeaderLength + ipmbChecksumSize;
199
200 if (bufferLength > ipmbMaxFrameLength)
201 {
Dawid Frycki8188d762019-04-01 18:03:48 -0700202 return nullptr;
Dawid Fryckia642a942018-06-12 10:44:23 -0700203 }
204
Dawid Frycki8188d762019-04-01 18:03:48 -0700205 std::shared_ptr<std::vector<uint8_t>> buffer =
206 std::make_shared<std::vector<uint8_t>>(bufferLength);
207
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500208 IPMB_PKT* ipmbPkt = reinterpret_cast<IPMB_PKT*>(buffer->data());
Vijay Khemka37a7eac2019-12-06 13:52:28 -0800209 ipmbPkt->len = bufferLength - 1;
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500210 IPMB_HEADER* ipmbBuffer = &(ipmbPkt->hdr);
Dawid Fryckia642a942018-06-12 10:44:23 -0700211
212 ipmbBuffer->Header.Resp.address = address;
213 ipmbBuffer->Header.Resp.rqNetFnLUN = ipmbNetFnLunSet(netFn, rqLun);
214 ipmbBuffer->Header.Resp.rsSA = rsSA;
215 ipmbBuffer->Header.Resp.rsSeqLUN = ipmbSeqLunSet(seq, rsLun);
216 ipmbBuffer->Header.Resp.cmd = cmd;
217 ipmbBuffer->Header.Resp.completionCode = completionCode;
218
219 ipmbBuffer->Header.Resp.checksum1 = ipmbChecksumCompute(
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500220 (uint8_t*)ipmbBuffer, ipmbConnectionHeaderLength - ipmbChecksumSize);
Dawid Fryckia642a942018-06-12 10:44:23 -0700221
222 if (data.size() > 0)
223 {
224 std::copy(data.begin(), data.end(), ipmbBuffer->Header.Resp.data);
225 }
226
Dawid Frycki8188d762019-04-01 18:03:48 -0700227 (*buffer)[bufferLength - ipmbChecksumSize] =
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500228 ipmbChecksumCompute((uint8_t*)ipmbBuffer + ipmbChecksum2StartOffset,
Dawid Fryckia642a942018-06-12 10:44:23 -0700229 (ipmbResponseDataHeaderLength + data.size()));
230
Dawid Frycki8188d762019-04-01 18:03:48 -0700231 return buffer;
Dawid Fryckia642a942018-06-12 10:44:23 -0700232}
233
234bool IpmbCommandFilter::isBlocked(const uint8_t reqNetFn, const uint8_t cmd)
235{
236 auto blockedCmd = unhandledCommands.find({reqNetFn, cmd});
237
238 if (blockedCmd != unhandledCommands.end())
239 {
240 return true;
241 }
242
243 return false;
244}
245
246void IpmbCommandFilter::addFilter(const uint8_t reqNetFn, const uint8_t cmd)
247{
248 if (unhandledCommands.insert({reqNetFn, cmd}).second)
249 {
250 phosphor::logging::log<phosphor::logging::level::INFO>(
251 "addFilter: added command to filter",
252 phosphor::logging::entry("netFn = %d", reqNetFn),
253 phosphor::logging::entry("cmd = %d", cmd));
254 }
255}
256
257/**
258 * @brief Ipmb channel
259 */
Qiang XUbbfd00a2019-06-27 21:10:06 +0800260void IpmbChannel::ipmbSendI2cFrame(std::shared_ptr<std::vector<uint8_t>> buffer,
Dawid Fryckia642a942018-06-12 10:44:23 -0700261 size_t retriesAttempted = 0)
262{
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500263 IPMB_PKT* ipmbPkt = reinterpret_cast<IPMB_PKT*>(buffer->data());
Vijay Khemka37a7eac2019-12-06 13:52:28 -0800264 uint8_t targetAddr = ipmbIsResponse(&(ipmbPkt->hdr))
265 ? ipmbPkt->hdr.Header.Resp.address
266 : ipmbPkt->hdr.Header.Req.address;
Patrick Williams9898d612024-08-16 15:21:15 -0400267 boost::asio::async_write(
268 i2cTargetDescriptor, boost::asio::buffer(*buffer),
269 [this, buffer, retriesAttempted, targetAddr](
270 const boost::system::error_code& ec, size_t /* bytesSent */) {
271 if (ec)
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500272 {
Patrick Williams9898d612024-08-16 15:21:15 -0400273 size_t currentRetryCnt = retriesAttempted;
274
275 if (currentRetryCnt > ipmbI2cNumberOfRetries)
276 {
277 std::string msgToLog =
278 "ipmbSendI2cFrame: send to I2C failed after retries."
279 " busId=" +
280 std::to_string(ipmbBusId) +
281 ", targetAddr=" + std::to_string(targetAddr) +
282 ", error=" + ec.message();
283 phosphor::logging::log<phosphor::logging::level::ERR>(
284 msgToLog.c_str());
285 return;
286 }
287 currentRetryCnt++;
288 ipmbSendI2cFrame(buffer, currentRetryCnt);
Dawid Fryckia642a942018-06-12 10:44:23 -0700289 }
Patrick Williams9898d612024-08-16 15:21:15 -0400290 });
Dawid Fryckia642a942018-06-12 10:44:23 -0700291}
292
293/**
294 * @brief Ipmb Outstanding Requests
295 */
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500296void IpmbChannel::makeRequestInvalid(IpmbRequest& request)
Dawid Fryckia642a942018-06-12 10:44:23 -0700297{
298 // change request state to invalid and remove it from outstanding requests
299 // list
300 request.state = ipmbRequestState::invalid;
301 outstandingRequests[request.seq] = nullptr;
302}
303
304void IpmbChannel::makeRequestValid(std::shared_ptr<IpmbRequest> request)
305{
306 // change request state to valid and add it to outstanding requests list
307 request->state = ipmbRequestState::valid;
308 outstandingRequests[request->seq] = request;
309}
310
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500311bool IpmbChannel::seqNumGet(uint8_t& seq)
Dawid Fryckia642a942018-06-12 10:44:23 -0700312{
313 static uint8_t seqNum = 0;
314
315 for (int i = 0; i < ipmbMaxOutstandingRequestsCount; i++)
316 {
Patrick Williamse523af32023-03-30 15:32:06 -0500317 seqNum = (seqNum + 1) % ipmbMaxOutstandingRequestsCount;
Dawid Fryckia642a942018-06-12 10:44:23 -0700318
319 if (outstandingRequests[seqNum] == nullptr)
320 {
321 seq = seqNum;
322 return true;
323 }
324 }
325
326 return false;
327}
328
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500329void IpmbChannel::responseMatch(std::unique_ptr<IpmbResponse>& response)
Dawid Fryckia642a942018-06-12 10:44:23 -0700330{
331 std::shared_ptr<IpmbRequest> request = outstandingRequests[response->seq];
332
333 if (request != nullptr)
334 {
335 if (((ipmbRespNetFn(request->netFn)) == (response->netFn)) &&
336 ((request->rqLun) == (response->rqLun)) &&
337 ((request->rsLun) == (response->rsLun)) &&
338 ((request->cmd) == (response->cmd)))
339 {
340 // match, response is corresponding to previously sent request
341 request->state = ipmbRequestState::matched;
342 request->timer->cancel();
343 request->matchedResponse = std::move(response);
344 }
345 }
346}
347
348void IpmbChannel::processI2cEvent()
349{
350 std::array<uint8_t, ipmbMaxFrameLength> buffer{};
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500351 IPMB_PKT* ipmbPkt = reinterpret_cast<IPMB_PKT*>(buffer.data());
352 IPMB_HEADER* ipmbFrame = &(ipmbPkt->hdr);
Dawid Fryckia642a942018-06-12 10:44:23 -0700353
Matt Simmering0736e212023-11-01 16:28:55 -0700354 lseek(ipmbi2cTargetFd, 0, SEEK_SET);
355 ssize_t r = read(ipmbi2cTargetFd, buffer.data(), ipmbMaxFrameLength);
Patrick Williams1f5b24b2023-03-30 15:36:03 -0500356
357 // Handle error cases.
358 if (r < 0)
359 {
360 goto end;
361 }
Vijay Khemka37a7eac2019-12-06 13:52:28 -0800362
Manojkiran Eda524f7532024-06-17 14:22:24 +0530363 /* Subtract first byte len size from total frame length */
Vijay Khemka37a7eac2019-12-06 13:52:28 -0800364 r--;
365
Dawid Fryckia642a942018-06-12 10:44:23 -0700366 if ((r < ipmbMinFrameLength) || (r > ipmbMaxFrameLength))
367 {
368 goto end;
369 }
370
Manojkiran Eda524f7532024-06-17 14:22:24 +0530371 // validate the frame
Dawid Fryckia642a942018-06-12 10:44:23 -0700372 if (!isFrameValid(ipmbFrame, r))
373 {
374 goto end;
375 }
376
Chen Yugang15185ff2020-09-01 09:20:33 +0800377 // if it is message received from ipmb channel, send out dbus signal
378 if (getChannelType() == ipmbChannelType::ipmb)
Qiang XUbbfd00a2019-06-27 21:10:06 +0800379 {
380 auto ipmbMessageReceived = IpmbRequest();
381 ipmbMessageReceived.i2cToIpmbConstruct(ipmbFrame, r);
Patrick Williams9898d612024-08-16 15:21:15 -0400382 sdbusplus::message_t msg =
383 conn->new_signal(ipmbObj, ipmbDbusIntf, "receiveBroadcast");
Qiang XUbbfd00a2019-06-27 21:10:06 +0800384 msg.append(ipmbMessageReceived.netFn, ipmbMessageReceived.cmd,
385 ipmbMessageReceived.data);
386 msg.signal_send();
387 }
388
Dawid Fryckia642a942018-06-12 10:44:23 -0700389 // copy frame to ipmib message buffer
Chen Yugang3e07b9e2020-10-13 16:14:04 +0800390 if (ipmbIsResponse(ipmbFrame))
Dawid Fryckia642a942018-06-12 10:44:23 -0700391 {
392 std::unique_ptr<IpmbResponse> ipmbMessageReceived =
393 std::make_unique<IpmbResponse>();
394
395 ipmbMessageReceived->i2cToIpmbConstruct(ipmbFrame, r);
396
397 // try to match response with outstanding request
398 responseMatch(ipmbMessageReceived);
399 }
400 else
401 {
402 // if command is blocked - respond with 'invalid command'
403 // completion code
404 if (commandFilter)
405 {
406 uint8_t netFn = ipmbNetFnGet(ipmbFrame->Header.Req.rsNetFnLUN);
407 uint8_t cmd = ipmbFrame->Header.Req.cmd;
Qiang XUbbfd00a2019-06-27 21:10:06 +0800408 uint8_t rqSA = ipmbFrame->Header.Req.rqSA;
Dawid Fryckia642a942018-06-12 10:44:23 -0700409
410 if (commandFilter->isBlocked(netFn, cmd))
411 {
412 uint8_t seq = ipmbSeqGet(ipmbFrame->Header.Req.rqSeqLUN);
413 uint8_t lun =
414 ipmbLunFromSeqLunGet(ipmbFrame->Header.Req.rqSeqLUN);
Dawid Fryckia642a942018-06-12 10:44:23 -0700415
416 // prepare generic response
Qiang XUbbfd00a2019-06-27 21:10:06 +0800417 auto ipmbResponse = IpmbResponse(
Matt Simmering0736e212023-11-01 16:28:55 -0700418 rqSA, ipmbRespNetFn(netFn), lun, ipmbBmcTargetAddress, seq,
Qiang XUbbfd00a2019-06-27 21:10:06 +0800419 ipmbRsLun, cmd, ipmbIpmiInvalidCmd, {});
Dawid Fryckia642a942018-06-12 10:44:23 -0700420
Dawid Frycki8188d762019-04-01 18:03:48 -0700421 auto buffer = ipmbResponse.ipmbToi2cConstruct();
422 if (buffer)
Dawid Fryckia642a942018-06-12 10:44:23 -0700423 {
Qiang XUbbfd00a2019-06-27 21:10:06 +0800424 ipmbSendI2cFrame(buffer);
Dawid Fryckia642a942018-06-12 10:44:23 -0700425 }
426
427 goto end;
428 }
429 }
430
431 auto ipmbMessageReceived = IpmbRequest();
Dawid Fryckia642a942018-06-12 10:44:23 -0700432 ipmbMessageReceived.i2cToIpmbConstruct(ipmbFrame, r);
433
Kumar Thangavel8fe0abe2020-08-19 21:42:23 +0530434 int devId = getDevIndex();
435
Dawid Frycki8188d762019-04-01 18:03:48 -0700436 std::map<std::string, std::variant<int>> options{
Kumar Thangavel8fe0abe2020-08-19 21:42:23 +0530437 {"rqSA", ipmbAddressTo7BitSet(ipmbMessageReceived.rqSA)},
438 {"hostId", devId}};
439
Dawid Frycki8188d762019-04-01 18:03:48 -0700440 using IpmiDbusRspType = std::tuple<uint8_t, uint8_t, uint8_t, uint8_t,
441 std::vector<uint8_t>>;
442 conn->async_method_call(
443 [this, rqLun{ipmbMessageReceived.rqLun},
Qiang XUbbfd00a2019-06-27 21:10:06 +0800444 seq{ipmbMessageReceived.seq}, address{ipmbMessageReceived.rqSA}](
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500445 const boost::system::error_code& ec,
446 const IpmiDbusRspType& response) {
Patrick Williams9898d612024-08-16 15:21:15 -0400447 const auto& [netfn, lun, cmd, cc, payload] = response;
448 if (ec)
Dawid Frycki8188d762019-04-01 18:03:48 -0700449 {
Patrick Williams9898d612024-08-16 15:21:15 -0400450 phosphor::logging::log<phosphor::logging::level::ERR>(
451 "processI2cEvent: error getting response from IPMI");
452 return;
Dawid Frycki8188d762019-04-01 18:03:48 -0700453 }
454
Patrick Williams9898d612024-08-16 15:21:15 -0400455 uint8_t bmcTargetAddress = getBmcTargetAddress();
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500456
Patrick Williams9898d612024-08-16 15:21:15 -0400457 if (payload.size() > ipmbMaxDataSize)
458 {
459 phosphor::logging::log<phosphor::logging::level::ERR>(
460 "processI2cEvent: response exceeding maximum size");
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500461
Patrick Williams9898d612024-08-16 15:21:15 -0400462 // prepare generic response
463 auto ipmbResponse = IpmbResponse(
464 address, netfn, rqLun, bmcTargetAddress, seq, ipmbRsLun,
465 cmd, ipmbIpmiCmdRespNotProvided, {});
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500466
Patrick Williams9898d612024-08-16 15:21:15 -0400467 auto buffer = ipmbResponse.ipmbToi2cConstruct();
468 if (buffer)
469 {
470 ipmbSendI2cFrame(buffer);
471 }
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500472
Patrick Williams9898d612024-08-16 15:21:15 -0400473 return;
474 }
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500475
Patrick Williams9898d612024-08-16 15:21:15 -0400476 if (!(netfn & ipmbNetFnResponseMask))
477 {
478 // we are not expecting request here
479 phosphor::logging::log<phosphor::logging::level::ERR>(
480 "processI2cEvent: got a request instead of response");
481 return;
482 }
483
484 // if command is not supported, add it to filter
485 if (cc == ipmbIpmiInvalidCmd)
486 {
487 addFilter(ipmbReqNetFnFromRespNetFn(netfn), cmd);
488 }
489
490 // payload is empty after constructor invocation
491 auto ipmbResponse =
492 IpmbResponse(address, netfn, rqLun, bmcTargetAddress, seq,
493 lun, cmd, cc, payload);
494
495 auto buffer = ipmbResponse.ipmbToi2cConstruct();
496 if (!buffer)
497 {
498 phosphor::logging::log<phosphor::logging::level::ERR>(
499 "processI2cEvent: error constructing a request");
500 return;
501 }
502
503 ipmbSendI2cFrame(buffer);
504 },
Dawid Frycki8188d762019-04-01 18:03:48 -0700505 "xyz.openbmc_project.Ipmi.Host", "/xyz/openbmc_project/Ipmi",
506 "xyz.openbmc_project.Ipmi.Server", "execute",
507 ipmbMessageReceived.netFn, ipmbMessageReceived.rsLun,
508 ipmbMessageReceived.cmd, ipmbMessageReceived.data, options);
Dawid Fryckia642a942018-06-12 10:44:23 -0700509 }
510
511end:
Matt Simmering0736e212023-11-01 16:28:55 -0700512 i2cTargetDescriptor.async_wait(
Vijay Khemka37a7eac2019-12-06 13:52:28 -0800513 boost::asio::posix::descriptor_base::wait_read,
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500514 [this](const boost::system::error_code& ec) {
Patrick Williams9898d612024-08-16 15:21:15 -0400515 if (ec)
516 {
517 phosphor::logging::log<phosphor::logging::level::ERR>(
518 "Error: processI2cEvent()");
519 return;
520 }
Dawid Fryckia642a942018-06-12 10:44:23 -0700521
Patrick Williams9898d612024-08-16 15:21:15 -0400522 processI2cEvent();
523 });
Dawid Fryckia642a942018-06-12 10:44:23 -0700524}
525
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500526IpmbChannel::IpmbChannel(boost::asio::io_context& io,
Matt Simmering0736e212023-11-01 16:28:55 -0700527 uint8_t ipmbBmcTargetAddress,
528 uint8_t ipmbRqTargetAddress, uint8_t channelIdx,
Dawid Fryckia642a942018-06-12 10:44:23 -0700529 std::shared_ptr<IpmbCommandFilter> commandFilter) :
Patrick Williams9898d612024-08-16 15:21:15 -0400530 i2cTargetDescriptor(io), ipmbBmcTargetAddress(ipmbBmcTargetAddress),
Matt Simmering0736e212023-11-01 16:28:55 -0700531 ipmbRqTargetAddress(ipmbRqTargetAddress), channelIdx(channelIdx),
Dawid Fryckia642a942018-06-12 10:44:23 -0700532 commandFilter(commandFilter)
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500533{}
Dawid Fryckia642a942018-06-12 10:44:23 -0700534
Matt Simmering0736e212023-11-01 16:28:55 -0700535int IpmbChannel::ipmbChannelInit(const char* ipmbI2cTarget)
Dawid Fryckia642a942018-06-12 10:44:23 -0700536{
Matt Simmering0736e212023-11-01 16:28:55 -0700537 // extract bus id from target path and save
538 std::string ipmbI2cTargetStr(ipmbI2cTarget);
539 auto findHyphen = ipmbI2cTargetStr.find("-");
540 std::string busStr = ipmbI2cTargetStr.substr(findHyphen + 1);
Qiang XU8edcf1a2019-06-14 22:18:15 +0800541 try
542 {
543 ipmbBusId = std::stoi(busStr);
544 }
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500545 catch (const std::invalid_argument&)
Qiang XU8edcf1a2019-06-14 22:18:15 +0800546 {
547 phosphor::logging::log<phosphor::logging::level::ERR>(
Matt Simmering0736e212023-11-01 16:28:55 -0700548 "ipmbChannelInit: invalid bus id in target-path config");
Qiang XU8edcf1a2019-06-14 22:18:15 +0800549 return -1;
550 }
551
Matt Simmering0736e212023-11-01 16:28:55 -0700552 // Check if sysfs has device. If not, enable I2C target driver by command
Vijay Khemka37a7eac2019-12-06 13:52:28 -0800553 // echo "ipmb-dev 0x1010" > /sys/bus/i2c/devices/i2c-0/new_device
Matt Simmering0736e212023-11-01 16:28:55 -0700554 bool hasSysfs = std::filesystem::exists(ipmbI2cTarget);
Qiang XU8edcf1a2019-06-14 22:18:15 +0800555 if (!hasSysfs)
556 {
Patrick Williams9898d612024-08-16 15:21:15 -0400557 std::string deviceFileName =
558 "/sys/bus/i2c/devices/i2c-" + busStr + "/new_device";
Vijay Khemka37a7eac2019-12-06 13:52:28 -0800559 std::string para = "ipmb-dev 0x1010"; // init with BMC addr 0x20
Qiang XU8edcf1a2019-06-14 22:18:15 +0800560 std::fstream deviceFile;
561 deviceFile.open(deviceFileName, std::ios::out);
562 if (!deviceFile.good())
563 {
564 phosphor::logging::log<phosphor::logging::level::ERR>(
565 "ipmbChannelInit: error opening deviceFile");
566 return -1;
567 }
568 deviceFile << para;
569 deviceFile.close();
570 }
571
Matt Simmering0736e212023-11-01 16:28:55 -0700572 // open fd to i2c target device for read write
573 ipmbi2cTargetFd = open(ipmbI2cTarget, O_RDWR | O_NONBLOCK | O_CLOEXEC);
574 if (ipmbi2cTargetFd < 0)
Dawid Fryckia642a942018-06-12 10:44:23 -0700575 {
576 phosphor::logging::log<phosphor::logging::level::ERR>(
Matt Simmering0736e212023-11-01 16:28:55 -0700577 "ipmbChannelInit: error opening ipmbI2cTarget");
Dawid Fryckia642a942018-06-12 10:44:23 -0700578 return -1;
579 }
580
Matt Simmering0736e212023-11-01 16:28:55 -0700581 i2cTargetDescriptor.assign(ipmbi2cTargetFd);
Dawid Fryckia642a942018-06-12 10:44:23 -0700582
Matt Simmering0736e212023-11-01 16:28:55 -0700583 i2cTargetDescriptor.async_wait(
Vijay Khemka37a7eac2019-12-06 13:52:28 -0800584 boost::asio::posix::descriptor_base::wait_read,
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500585 [this](const boost::system::error_code& ec) {
Patrick Williams9898d612024-08-16 15:21:15 -0400586 if (ec)
587 {
588 phosphor::logging::log<phosphor::logging::level::ERR>(
589 "Error: processI2cEvent()");
590 return;
591 }
Dawid Fryckia642a942018-06-12 10:44:23 -0700592
Patrick Williams9898d612024-08-16 15:21:15 -0400593 processI2cEvent();
594 });
Dawid Fryckia642a942018-06-12 10:44:23 -0700595
596 return 0;
597}
598
Matt Simmering0736e212023-11-01 16:28:55 -0700599int IpmbChannel::ipmbChannelUpdateTargetAddress(const uint8_t newBmcTargetAddr)
Qiang XU8edcf1a2019-06-14 22:18:15 +0800600{
Matt Simmering0736e212023-11-01 16:28:55 -0700601 if (ipmbi2cTargetFd > 0)
Qiang XU8edcf1a2019-06-14 22:18:15 +0800602 {
Matt Simmering0736e212023-11-01 16:28:55 -0700603 i2cTargetDescriptor.close();
604 close(ipmbi2cTargetFd);
605 ipmbi2cTargetFd = 0;
Qiang XU8edcf1a2019-06-14 22:18:15 +0800606 }
607
Matt Simmering0736e212023-11-01 16:28:55 -0700608 // disable old I2C target driver by command:
Qiang XU8edcf1a2019-06-14 22:18:15 +0800609 // echo "0x1010" > /sys/bus/i2c/devices/i2c-0/delete_device
610 std::string deviceFileName;
611 std::string para;
612 std::fstream deviceFile;
613 deviceFileName = "/sys/bus/i2c/devices/i2c-" + std::to_string(ipmbBusId) +
614 "/delete_device";
615 para = "0x1010"; // align with removed ipmb0 definition in dts file
616 deviceFile.open(deviceFileName, std::ios::out);
617 if (!deviceFile.good())
618 {
619 phosphor::logging::log<phosphor::logging::level::ERR>(
Matt Simmering0736e212023-11-01 16:28:55 -0700620 "ipmbChannelUpdateTargetAddress: error opening deviceFile to delete "
Qiang XU8edcf1a2019-06-14 22:18:15 +0800621 "sysfs");
622 return -1;
623 }
624 deviceFile << para;
625 deviceFile.close();
626
Matt Simmering0736e212023-11-01 16:28:55 -0700627 // enable new I2C target driver by command:
Vijay Khemka37a7eac2019-12-06 13:52:28 -0800628 // echo "ipmb-dev 0x1012" > /sys/bus/i2c/devices/i2c-0/new_device
Patrick Williams9898d612024-08-16 15:21:15 -0400629 deviceFileName =
630 "/sys/bus/i2c/devices/i2c-" + std::to_string(ipmbBusId) + "/new_device";
Qiang XU8edcf1a2019-06-14 22:18:15 +0800631 std::ostringstream hex;
Matt Simmering0736e212023-11-01 16:28:55 -0700632 uint16_t addr = 0x1000 + (newBmcTargetAddr >> 1);
Qiang XU8edcf1a2019-06-14 22:18:15 +0800633 hex << std::hex << static_cast<uint16_t>(addr);
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500634 const std::string& addressHexStr = hex.str();
Vijay Khemka37a7eac2019-12-06 13:52:28 -0800635 para = "ipmb-dev 0x" + addressHexStr;
Qiang XU8edcf1a2019-06-14 22:18:15 +0800636 deviceFile.open(deviceFileName, std::ios::out);
637 if (!deviceFile.good())
638 {
639 phosphor::logging::log<phosphor::logging::level::ERR>(
Matt Simmering0736e212023-11-01 16:28:55 -0700640 "ipmbChannelUpdateTargetAddress: error opening deviceFile to create "
Qiang XU8edcf1a2019-06-14 22:18:15 +0800641 "sysfs");
642 return -1;
643 }
644 deviceFile << para;
645 deviceFile.close();
646
Matt Simmering0736e212023-11-01 16:28:55 -0700647 // open fd to i2c target device
648 std::string ipmbI2cTargetStr = "/dev/ipmb-" + std::to_string(ipmbBusId);
649 ipmbi2cTargetFd = open(ipmbI2cTargetStr.c_str(), O_RDWR | O_NONBLOCK);
650 if (ipmbi2cTargetFd < 0)
Qiang XU8edcf1a2019-06-14 22:18:15 +0800651 {
652 phosphor::logging::log<phosphor::logging::level::ERR>(
Matt Simmering0736e212023-11-01 16:28:55 -0700653 "ipmbChannelInit: error opening ipmbI2cTarget");
Qiang XU8edcf1a2019-06-14 22:18:15 +0800654 return -1;
655 }
656
Matt Simmering0736e212023-11-01 16:28:55 -0700657 // start to receive i2c data as target
658 i2cTargetDescriptor.assign(ipmbi2cTargetFd);
659 i2cTargetDescriptor.async_wait(
Vijay Khemka37a7eac2019-12-06 13:52:28 -0800660 boost::asio::posix::descriptor_base::wait_read,
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500661 [this](const boost::system::error_code& ec) {
Patrick Williams9898d612024-08-16 15:21:15 -0400662 if (ec)
663 {
664 phosphor::logging::log<phosphor::logging::level::ERR>(
665 "Error: processI2cEvent()");
666 return;
667 }
Qiang XU8edcf1a2019-06-14 22:18:15 +0800668
Patrick Williams9898d612024-08-16 15:21:15 -0400669 processI2cEvent();
670 });
Qiang XU8edcf1a2019-06-14 22:18:15 +0800671
Matt Simmering0736e212023-11-01 16:28:55 -0700672 ipmbBmcTargetAddress = newBmcTargetAddr;
Qiang XUbbfd00a2019-06-27 21:10:06 +0800673
Qiang XU8edcf1a2019-06-14 22:18:15 +0800674 return 0;
675}
676
677uint8_t IpmbChannel::getBusId()
678{
679 return ipmbBusId;
680}
681
Matt Simmering0736e212023-11-01 16:28:55 -0700682uint8_t IpmbChannel::getBmcTargetAddress()
Dawid Fryckia642a942018-06-12 10:44:23 -0700683{
Matt Simmering0736e212023-11-01 16:28:55 -0700684 return ipmbBmcTargetAddress;
Dawid Fryckia642a942018-06-12 10:44:23 -0700685}
686
Matt Simmering0736e212023-11-01 16:28:55 -0700687uint8_t IpmbChannel::getRqTargetAddress()
Dawid Fryckia642a942018-06-12 10:44:23 -0700688{
Matt Simmering0736e212023-11-01 16:28:55 -0700689 return ipmbRqTargetAddress;
Dawid Fryckia642a942018-06-12 10:44:23 -0700690}
691
Kumar Thangavel950a2e82020-07-10 18:07:33 +0530692uint8_t IpmbChannel::getDevIndex()
693{
694 return channelIdx >> 2;
695}
696
697uint8_t IpmbChannel::getChannelIdx()
698{
699 return channelIdx;
700}
701
Dawid Fryckia642a942018-06-12 10:44:23 -0700702ipmbChannelType IpmbChannel::getChannelType()
703{
Kumar Thangavel950a2e82020-07-10 18:07:33 +0530704 return static_cast<ipmbChannelType>((channelIdx & 3));
Dawid Fryckia642a942018-06-12 10:44:23 -0700705}
706
707void IpmbChannel::addFilter(const uint8_t respNetFn, const uint8_t cmd)
708{
709 if (commandFilter)
710 {
711 commandFilter->addFilter(respNetFn, cmd);
712 }
713}
714
715std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500716 IpmbChannel::requestAdd(boost::asio::yield_context& yield,
Dawid Fryckia642a942018-06-12 10:44:23 -0700717 std::shared_ptr<IpmbRequest> request)
718{
719 makeRequestValid(request);
720
Patrick Williams9ae88932024-07-13 15:39:58 -0500721 std::vector<uint8_t> buffer{};
Dawid Fryckia642a942018-06-12 10:44:23 -0700722 if (request->ipmbToi2cConstruct(buffer) != 0)
723 {
Tian Jingzaib922c2d2025-04-08 16:30:45 +0800724 makeRequestInvalid(*request);
Dawid Fryckia642a942018-06-12 10:44:23 -0700725 return returnStatus(ipmbResponseStatus::error);
726 }
727
728 for (int i = 0; i < ipmbNumberOfTries; i++)
729 {
730 boost::system::error_code ec;
Jae Hyun Yoo25e85c72019-03-05 14:28:13 -0800731 int i2cRetryCnt = 0;
Dawid Fryckia642a942018-06-12 10:44:23 -0700732
Jae Hyun Yoo25e85c72019-03-05 14:28:13 -0800733 for (; i2cRetryCnt < ipmbI2cNumberOfRetries; i2cRetryCnt++)
Dawid Fryckia642a942018-06-12 10:44:23 -0700734 {
Matt Simmering0736e212023-11-01 16:28:55 -0700735 boost::asio::async_write(i2cTargetDescriptor,
Vijay Khemka37a7eac2019-12-06 13:52:28 -0800736 boost::asio::buffer(buffer), yield[ec]);
Dawid Fryckia642a942018-06-12 10:44:23 -0700737
738 if (ec)
739 {
Jae Hyun Yoo25e85c72019-03-05 14:28:13 -0800740 continue; // retry
Dawid Fryckia642a942018-06-12 10:44:23 -0700741 }
742 break;
743 }
744
Jae Hyun Yoo25e85c72019-03-05 14:28:13 -0800745 if (i2cRetryCnt == ipmbI2cNumberOfRetries)
746 {
Qiang XUbbfd00a2019-06-27 21:10:06 +0800747 std::string msgToLog =
748 "requestAdd: Sent to I2C failed after retries."
749 " busId=" +
750 std::to_string(ipmbBusId) + ", error=" + ec.message();
Jae Hyun Yoo25e85c72019-03-05 14:28:13 -0800751 phosphor::logging::log<phosphor::logging::level::INFO>(
Qiang XUbbfd00a2019-06-27 21:10:06 +0800752 msgToLog.c_str());
Jae Hyun Yoo25e85c72019-03-05 14:28:13 -0800753 }
754
Dawid Fryckia642a942018-06-12 10:44:23 -0700755 request->timer->expires_after(
756 std::chrono::milliseconds(ipmbRequestRetryTimeout));
757 request->timer->async_wait(yield[ec]);
758
759 if (ec && ec != boost::asio::error::operation_aborted)
760 {
761 // unexpected error - invalidate request and return generic error
762 phosphor::logging::log<phosphor::logging::level::ERR>(
763 "requestAdd: async_wait error");
764 makeRequestInvalid(*request);
765 return returnStatus(ipmbResponseStatus::error);
766 }
767
768 if (request->state == ipmbRequestState::matched)
769 {
770 // matched response, send it to client application
771 makeRequestInvalid(*request);
772 return request->returnMatchedResponse();
773 }
774 }
775
776 makeRequestInvalid(*request);
777 return returnStatus(ipmbResponseStatus::timeout);
778}
779
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500780static IpmbChannel* getChannel(uint8_t reqChannel)
Dawid Fryckia642a942018-06-12 10:44:23 -0700781{
Patrick Williams9898d612024-08-16 15:21:15 -0400782 auto channel =
783 std::find_if(ipmbChannels.begin(), ipmbChannels.end(),
784 [reqChannel](IpmbChannel& channel) {
785 return channel.getChannelIdx() == reqChannel;
786 });
Dawid Fryckia642a942018-06-12 10:44:23 -0700787 if (channel != ipmbChannels.end())
788 {
789 return &(*channel);
790 }
791
792 return nullptr;
793}
794
795static int initializeChannels()
796{
797 std::shared_ptr<IpmbCommandFilter> commandFilter =
798 std::make_shared<IpmbCommandFilter>();
799
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500800 constexpr const char* configFilePath =
Amithash Prasad314862d2019-03-26 11:14:03 -0700801 "/usr/share/ipmbbridge/ipmb-channels.json";
802 std::ifstream configFile(configFilePath);
803 if (!configFile.is_open())
Dawid Fryckia642a942018-06-12 10:44:23 -0700804 {
Amithash Prasad314862d2019-03-26 11:14:03 -0700805 phosphor::logging::log<phosphor::logging::level::ERR>(
806 "initializeChannels: Cannot open config path");
807 return -1;
808 }
809 try
810 {
Kumar Thangavel950a2e82020-07-10 18:07:33 +0530811 uint8_t devIndex = 0;
Amithash Prasad314862d2019-03-26 11:14:03 -0700812 auto data = nlohmann::json::parse(configFile, nullptr);
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500813 for (const auto& channelConfig : data["channels"])
Dawid Fryckia642a942018-06-12 10:44:23 -0700814 {
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500815 const std::string& typeConfig = channelConfig["type"];
Matt Simmering0736e212023-11-01 16:28:55 -0700816 const std::string& targetPath = channelConfig["slave-path"];
Amithash Prasad314862d2019-03-26 11:14:03 -0700817 uint8_t bmcAddr = channelConfig["bmc-addr"];
818 uint8_t reqAddr = channelConfig["remote-addr"];
Kumar Thangavel950a2e82020-07-10 18:07:33 +0530819
Amithash Prasad314862d2019-03-26 11:14:03 -0700820 ipmbChannelType type = ipmbChannelTypeMap.at(typeConfig);
821
Kumar Thangavel950a2e82020-07-10 18:07:33 +0530822 if (channelConfig.contains("devIndex"))
823 {
824 devIndex = channelConfig["devIndex"];
825 }
826
827 auto channel = ipmbChannels.emplace(
828 ipmbChannels.end(), io, bmcAddr, reqAddr,
829 ((devIndex << 2) | static_cast<uint8_t>(type)), commandFilter);
Matt Simmering0736e212023-11-01 16:28:55 -0700830 if (channel->ipmbChannelInit(targetPath.c_str()) < 0)
Amithash Prasad314862d2019-03-26 11:14:03 -0700831 {
832 phosphor::logging::log<phosphor::logging::level::ERR>(
833 "initializeChannels: channel initialization failed");
834 return -1;
835 }
Dawid Fryckia642a942018-06-12 10:44:23 -0700836 }
837 }
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500838 catch (const nlohmann::json::exception& e)
Amithash Prasad314862d2019-03-26 11:14:03 -0700839 {
840 phosphor::logging::log<phosphor::logging::level::ERR>(
841 "initializeChannels: Error parsing config file");
842 return -1;
843 }
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500844 catch (const std::out_of_range& e)
Amithash Prasad314862d2019-03-26 11:14:03 -0700845 {
846 phosphor::logging::log<phosphor::logging::level::ERR>(
847 "initializeChannels: Error invalid type");
848 return -1;
849 }
Dawid Fryckia642a942018-06-12 10:44:23 -0700850 return 0;
851}
852
Patrick Williams9898d612024-08-16 15:21:15 -0400853auto ipmbHandleRequest =
854 [](boost::asio::yield_context yield, uint8_t reqChannel, uint8_t netfn,
855 uint8_t lun, uint8_t cmd, std::vector<uint8_t> dataReceived) {
856 IpmbChannel* channel = getChannel(reqChannel);
Kumar Thangavel950a2e82020-07-10 18:07:33 +0530857
Patrick Williams9898d612024-08-16 15:21:15 -0400858 if (channel == nullptr)
859 {
860 phosphor::logging::log<phosphor::logging::level::ERR>(
861 "ipmbHandleRequest: requested channel does not exist");
862 return returnStatus(ipmbResponseStatus::invalid_param);
863 }
Dawid Fryckia642a942018-06-12 10:44:23 -0700864
Patrick Williams9898d612024-08-16 15:21:15 -0400865 // check outstanding request list for valid sequence number
866 uint8_t seqNum = 0;
867 bool seqValid = channel->seqNumGet(seqNum);
868 if (!seqValid)
869 {
870 phosphor::logging::log<phosphor::logging::level::WARNING>(
871 "ipmbHandleRequest: cannot add more requests to the list");
872 return returnStatus(ipmbResponseStatus::busy);
873 }
Dawid Fryckia642a942018-06-12 10:44:23 -0700874
Patrick Williams9898d612024-08-16 15:21:15 -0400875 uint8_t bmcTargetAddress = channel->getBmcTargetAddress();
876 uint8_t rqTargetAddress = channel->getRqTargetAddress();
Dawid Fryckia642a942018-06-12 10:44:23 -0700877
Patrick Williams9898d612024-08-16 15:21:15 -0400878 // construct the request to add it to outstanding request list
879 std::shared_ptr<IpmbRequest> request = std::make_shared<IpmbRequest>(
880 rqTargetAddress, netfn, ipmbRsLun, bmcTargetAddress, seqNum, lun,
881 cmd, dataReceived);
Dawid Fryckia642a942018-06-12 10:44:23 -0700882
Patrick Williams9898d612024-08-16 15:21:15 -0400883 if (!request->timer)
884 {
885 phosphor::logging::log<phosphor::logging::level::ERR>(
886 "ipmbHandleRequest: timer object does not exist");
887 return returnStatus(ipmbResponseStatus::error);
888 }
Dawid Fryckia642a942018-06-12 10:44:23 -0700889
Patrick Williams9898d612024-08-16 15:21:15 -0400890 return channel->requestAdd(yield, request);
891 };
Dawid Fryckia642a942018-06-12 10:44:23 -0700892
Matt Simmering0736e212023-11-01 16:28:55 -0700893void addUpdateTargetAddrHandler()
Qiang XU8edcf1a2019-06-14 22:18:15 +0800894{
Matt Simmering0736e212023-11-01 16:28:55 -0700895 // callback to handle dbus signal of updating target addr
896 std::function<void(sdbusplus::message_t&)> updateTargetAddrHandler =
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500897 [](sdbusplus::message_t& message) {
Patrick Williams9898d612024-08-16 15:21:15 -0400898 uint8_t reqChannel, busId, targetAddr;
Qiang XU8edcf1a2019-06-14 22:18:15 +0800899
Patrick Williams9898d612024-08-16 15:21:15 -0400900 // valid source of signal, check whether from multi-node manager
901 std::string pathName = message.get_path();
902 if (pathName != "/xyz/openbmc_project/MultiNode/Status")
903 {
904 phosphor::logging::log<phosphor::logging::level::ERR>(
905 "addUpdateTargetAddrHandler: invalid obj path");
906 return;
907 }
Qiang XU8edcf1a2019-06-14 22:18:15 +0800908
Patrick Williams9898d612024-08-16 15:21:15 -0400909 message.read(reqChannel, busId, targetAddr);
Qiang XU8edcf1a2019-06-14 22:18:15 +0800910
Patrick Williams9898d612024-08-16 15:21:15 -0400911 IpmbChannel* channel = getChannel(reqChannel);
Kumar Thangavel950a2e82020-07-10 18:07:33 +0530912
Patrick Williams9898d612024-08-16 15:21:15 -0400913 if (channel == nullptr ||
914 channel->getChannelType() != ipmbChannelType::ipmb)
915 {
916 phosphor::logging::log<phosphor::logging::level::ERR>(
917 "addUpdateTargetAddrHandler: invalid channel");
918 return;
919 }
920 if (busId != channel->getBusId())
921 {
922 phosphor::logging::log<phosphor::logging::level::ERR>(
923 "addUpdateTargetAddrHandler: invalid busId");
924 return;
925 }
926 if (channel->getBmcTargetAddress() == targetAddr)
927 {
928 phosphor::logging::log<phosphor::logging::level::INFO>(
929 "addUpdateTargetAddrHandler: channel bmc target addr is "
930 "unchanged, do nothing");
931 return;
932 }
Qiang XU8edcf1a2019-06-14 22:18:15 +0800933
Patrick Williams9898d612024-08-16 15:21:15 -0400934 channel->ipmbChannelUpdateTargetAddress(targetAddr);
935 };
Qiang XU8edcf1a2019-06-14 22:18:15 +0800936
Patrick Williams3852f8e2022-07-22 19:26:56 -0500937 static auto match = std::make_unique<sdbusplus::bus::match_t>(
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500938 static_cast<sdbusplus::bus_t&>(*conn),
Matt Simmering0736e212023-11-01 16:28:55 -0700939 "type='signal',member='updateBmcSlaveAddr',", updateTargetAddrHandler);
Qiang XU8edcf1a2019-06-14 22:18:15 +0800940}
941
Qiang XUbbfd00a2019-06-27 21:10:06 +0800942void addSendBroadcastHandler()
943{
944 // callback to handle dbus signal of sending broadcast message
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500945 std::function<void(sdbusplus::message_t&)> sendBroadcastHandler =
946 [](sdbusplus::message_t& message) {
Patrick Williams9898d612024-08-16 15:21:15 -0400947 uint8_t reqChannel, netFn, lun, cmd;
948 std::vector<uint8_t> dataReceived;
949 message.read(reqChannel, netFn, lun, cmd, dataReceived);
Qiang XUbbfd00a2019-06-27 21:10:06 +0800950
Patrick Williams9898d612024-08-16 15:21:15 -0400951 IpmbChannel* channel = getChannel(reqChannel);
Kumar Thangavel950a2e82020-07-10 18:07:33 +0530952
Patrick Williams9898d612024-08-16 15:21:15 -0400953 if (channel == nullptr)
954 {
955 phosphor::logging::log<phosphor::logging::level::ERR>(
956 "addSendBroadcastMsgHandler: requested channel does not "
957 "exist");
958 return;
959 }
Qiang XUbbfd00a2019-06-27 21:10:06 +0800960
Patrick Williams9898d612024-08-16 15:21:15 -0400961 uint8_t bmcTargetAddress = channel->getBmcTargetAddress();
962 uint8_t seqNum = 0; // seqNum is not used in broadcast msg
963 uint8_t targetAddr = broadcastAddress;
Qiang XUbbfd00a2019-06-27 21:10:06 +0800964
Patrick Williams9898d612024-08-16 15:21:15 -0400965 std::shared_ptr<IpmbRequest> request =
966 std::make_shared<IpmbRequest>(targetAddr, netFn, ipmbRsLun,
967 bmcTargetAddress, seqNum, lun,
968 cmd, dataReceived);
Qiang XUbbfd00a2019-06-27 21:10:06 +0800969
Patrick Williams9898d612024-08-16 15:21:15 -0400970 std::shared_ptr<std::vector<uint8_t>> buffer =
971 std::make_shared<std::vector<uint8_t>>();
Qiang XUbbfd00a2019-06-27 21:10:06 +0800972
Patrick Williams9898d612024-08-16 15:21:15 -0400973 if (request->ipmbToi2cConstruct(*buffer) != 0)
974 {
975 return;
976 }
Qiang XUbbfd00a2019-06-27 21:10:06 +0800977
Patrick Williams9898d612024-08-16 15:21:15 -0400978 channel->ipmbSendI2cFrame(buffer);
979 };
Qiang XUbbfd00a2019-06-27 21:10:06 +0800980
Patrick Williams3852f8e2022-07-22 19:26:56 -0500981 static auto match = std::make_unique<sdbusplus::bus::match_t>(
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500982 static_cast<sdbusplus::bus_t&>(*conn),
Qiang XUbbfd00a2019-06-27 21:10:06 +0800983 "type='signal',member='sendBroadcast',", sendBroadcastHandler);
984}
985
Dawid Fryckia642a942018-06-12 10:44:23 -0700986/**
987 * @brief Main
988 */
Patrick Williams825ad832023-03-30 15:55:04 -0500989int main()
Dawid Fryckia642a942018-06-12 10:44:23 -0700990{
991 conn->request_name(ipmbBus);
992
993 auto server = sdbusplus::asio::object_server(conn);
994
Dawid Fryckia642a942018-06-12 10:44:23 -0700995 std::shared_ptr<sdbusplus::asio::dbus_interface> ipmbIface =
996 server.add_interface(ipmbObj, ipmbDbusIntf);
997
Dawid Fryckia642a942018-06-12 10:44:23 -0700998 ipmbIface->register_method("sendRequest", std::move(ipmbHandleRequest));
Dawid Fryckia642a942018-06-12 10:44:23 -0700999 ipmbIface->initialize();
1000
1001 if (initializeChannels() < 0)
1002 {
1003 phosphor::logging::log<phosphor::logging::level::ERR>(
1004 "Error initializeChannels");
1005 return -1;
1006 }
1007
Matt Simmering0736e212023-11-01 16:28:55 -07001008 addUpdateTargetAddrHandler();
Qiang XU8edcf1a2019-06-14 22:18:15 +08001009
Qiang XUbbfd00a2019-06-27 21:10:06 +08001010 addSendBroadcastHandler();
1011
Dawid Fryckia642a942018-06-12 10:44:23 -07001012 io.run();
1013 return 0;
1014}