blob: 678c750dffae59a05c575e03d009a71bf5787447 [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) :
Dawid Fryckia642a942018-06-12 10:44:23 -070059 address(address),
60 netFn(netFn), rsLun(rsLun), rqSA(rqSA), seq(seq), rqLun(rqLun), cmd(cmd),
61 timer(io)
62{
63 data.reserve(ipmbMaxDataSize);
64 state = ipmbRequestState::invalid;
65
66 if (inputData.size() > 0)
67 {
68 data = std::move(inputData);
69 }
70}
71
Patrick Williamsfe0d38a2023-03-30 14:51:33 -050072void IpmbRequest::i2cToIpmbConstruct(IPMB_HEADER* ipmbBuffer,
Dawid Fryckia642a942018-06-12 10:44:23 -070073 size_t bufferLength)
74{
75 // constructing ipmb request from i2c buffer
76 netFn = ipmbNetFnGet(ipmbBuffer->Header.Req.rsNetFnLUN);
77 rsLun = ipmbLunFromNetFnLunGet(ipmbBuffer->Header.Req.rsNetFnLUN);
78 rqSA = ipmbBuffer->Header.Req.rqSA;
79 seq = ipmbSeqGet(ipmbBuffer->Header.Req.rqSeqLUN);
80 rqLun = ipmbLunFromSeqLunGet(ipmbBuffer->Header.Req.rqSeqLUN);
81 cmd = ipmbBuffer->Header.Req.cmd;
82
Patrick Williamsfe0d38a2023-03-30 14:51:33 -050083 size_t dataLength = bufferLength -
84 (ipmbConnectionHeaderLength +
85 ipmbRequestDataHeaderLength + ipmbChecksumSize);
Dawid Fryckia642a942018-06-12 10:44:23 -070086
87 if (dataLength > 0)
88 {
89 data.insert(data.end(), ipmbBuffer->Header.Req.data,
90 &ipmbBuffer->Header.Req.data[dataLength]);
91 }
92}
93
Patrick Williamsfe0d38a2023-03-30 14:51:33 -050094int IpmbRequest::ipmbToi2cConstruct(std::vector<uint8_t>& buffer)
Dawid Fryckia642a942018-06-12 10:44:23 -070095{
Vijay Khemka37a7eac2019-12-06 13:52:28 -080096 /* Add one byte for length byte as per required by driver */
97 size_t bufferLength = 1 + data.size() + ipmbRequestDataHeaderLength +
Dawid Fryckia642a942018-06-12 10:44:23 -070098 ipmbConnectionHeaderLength + ipmbChecksumSize;
99
100 if (bufferLength > ipmbMaxFrameLength)
101 {
102 return -1;
103 }
104
105 buffer.resize(bufferLength);
106 static_assert(ipmbMaxFrameLength >= sizeof(IPMB_HEADER));
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500107 IPMB_PKT* ipmbPkt = reinterpret_cast<IPMB_PKT*>(buffer.data());
Vijay Khemka37a7eac2019-12-06 13:52:28 -0800108 ipmbPkt->len = bufferLength - 1;
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500109 IPMB_HEADER* ipmbBuffer = &(ipmbPkt->hdr);
Dawid Fryckia642a942018-06-12 10:44:23 -0700110
111 // constructing buffer from ipmb request
112 ipmbBuffer->Header.Req.address = address;
113 ipmbBuffer->Header.Req.rsNetFnLUN = ipmbNetFnLunSet(netFn, rsLun);
114 ipmbBuffer->Header.Req.rqSA = rqSA;
115 ipmbBuffer->Header.Req.rqSeqLUN = ipmbSeqLunSet(seq, rqLun);
116 ipmbBuffer->Header.Req.cmd = cmd;
117
Qiang XUbbfd00a2019-06-27 21:10:06 +0800118 ipmbBuffer->Header.Req.checksum1 = ipmbChecksumCompute(
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500119 (uint8_t*)ipmbBuffer, ipmbConnectionHeaderLength - ipmbChecksumSize);
Dawid Fryckia642a942018-06-12 10:44:23 -0700120
121 if (data.size() > 0)
122 {
123 std::copy(data.begin(), data.end(), ipmbBuffer->Header.Req.data);
124 }
125
126 buffer[bufferLength - ipmbChecksumSize] =
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500127 ipmbChecksumCompute((uint8_t*)ipmbBuffer + ipmbChecksum2StartOffset,
Dawid Fryckia642a942018-06-12 10:44:23 -0700128 (ipmbRequestDataHeaderLength + data.size()));
129
130 return 0;
131}
132
133std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
134 IpmbRequest::returnMatchedResponse()
135{
136 return std::make_tuple(
137 static_cast<int>(ipmbResponseStatus::success), matchedResponse->netFn,
138 matchedResponse->rsLun, matchedResponse->cmd,
139 matchedResponse->completionCode, matchedResponse->data);
140}
141
142static std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
143 returnStatus(ipmbResponseStatus status)
144{
145 // we only want to send status here, other fields are not relevant
146 return std::make_tuple(static_cast<int>(status), 0, 0, 0, 0,
147 std::vector<uint8_t>(0));
148}
149
Dawid Fryckia642a942018-06-12 10:44:23 -0700150/**
151 * @brief Ipmb response class methods
152 */
153IpmbResponse::IpmbResponse()
154{
155 data.reserve(ipmbMaxDataSize);
156}
157
158IpmbResponse::IpmbResponse(uint8_t address, uint8_t netFn, uint8_t rqLun,
159 uint8_t rsSA, uint8_t seq, uint8_t rsLun,
160 uint8_t cmd, uint8_t completionCode,
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500161 const std::vector<uint8_t>& inputData) :
Dawid Fryckia642a942018-06-12 10:44:23 -0700162 address(address),
163 netFn(netFn), rqLun(rqLun), rsSA(rsSA), seq(seq), rsLun(rsLun), cmd(cmd),
164 completionCode(completionCode)
165{
166 data.reserve(ipmbMaxDataSize);
167
168 if (inputData.size() > 0)
169 {
170 data = std::move(inputData);
171 }
172}
173
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500174void IpmbResponse::i2cToIpmbConstruct(IPMB_HEADER* ipmbBuffer,
Dawid Fryckia642a942018-06-12 10:44:23 -0700175 size_t bufferLength)
176{
177 netFn = ipmbNetFnGet(ipmbBuffer->Header.Resp.rqNetFnLUN);
178 rqLun = ipmbLunFromNetFnLunGet(ipmbBuffer->Header.Resp.rqNetFnLUN);
179 rsSA = ipmbBuffer->Header.Resp.rsSA;
180 seq = ipmbSeqGet(ipmbBuffer->Header.Resp.rsSeqLUN);
181 rsLun = ipmbLunFromSeqLunGet(ipmbBuffer->Header.Resp.rsSeqLUN);
182 cmd = ipmbBuffer->Header.Resp.cmd;
183 completionCode = ipmbBuffer->Header.Resp.completionCode;
184
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500185 size_t dataLength = bufferLength -
186 (ipmbConnectionHeaderLength +
187 ipmbResponseDataHeaderLength + ipmbChecksumSize);
Dawid Fryckia642a942018-06-12 10:44:23 -0700188
189 if (dataLength > 0)
190 {
191 data.insert(data.end(), ipmbBuffer->Header.Resp.data,
192 &ipmbBuffer->Header.Resp.data[dataLength]);
193 }
194}
195
Dawid Frycki8188d762019-04-01 18:03:48 -0700196std::shared_ptr<std::vector<uint8_t>> IpmbResponse::ipmbToi2cConstruct()
Dawid Fryckia642a942018-06-12 10:44:23 -0700197{
Vijay Khemka37a7eac2019-12-06 13:52:28 -0800198 /* Add one byte for length byte as per required by driver */
199 size_t bufferLength = 1 + data.size() + ipmbResponseDataHeaderLength +
Dawid Fryckia642a942018-06-12 10:44:23 -0700200 ipmbConnectionHeaderLength + ipmbChecksumSize;
201
202 if (bufferLength > ipmbMaxFrameLength)
203 {
Dawid Frycki8188d762019-04-01 18:03:48 -0700204 return nullptr;
Dawid Fryckia642a942018-06-12 10:44:23 -0700205 }
206
Dawid Frycki8188d762019-04-01 18:03:48 -0700207 std::shared_ptr<std::vector<uint8_t>> buffer =
208 std::make_shared<std::vector<uint8_t>>(bufferLength);
209
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500210 IPMB_PKT* ipmbPkt = reinterpret_cast<IPMB_PKT*>(buffer->data());
Vijay Khemka37a7eac2019-12-06 13:52:28 -0800211 ipmbPkt->len = bufferLength - 1;
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500212 IPMB_HEADER* ipmbBuffer = &(ipmbPkt->hdr);
Dawid Fryckia642a942018-06-12 10:44:23 -0700213
214 ipmbBuffer->Header.Resp.address = address;
215 ipmbBuffer->Header.Resp.rqNetFnLUN = ipmbNetFnLunSet(netFn, rqLun);
216 ipmbBuffer->Header.Resp.rsSA = rsSA;
217 ipmbBuffer->Header.Resp.rsSeqLUN = ipmbSeqLunSet(seq, rsLun);
218 ipmbBuffer->Header.Resp.cmd = cmd;
219 ipmbBuffer->Header.Resp.completionCode = completionCode;
220
221 ipmbBuffer->Header.Resp.checksum1 = ipmbChecksumCompute(
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500222 (uint8_t*)ipmbBuffer, ipmbConnectionHeaderLength - ipmbChecksumSize);
Dawid Fryckia642a942018-06-12 10:44:23 -0700223
224 if (data.size() > 0)
225 {
226 std::copy(data.begin(), data.end(), ipmbBuffer->Header.Resp.data);
227 }
228
Dawid Frycki8188d762019-04-01 18:03:48 -0700229 (*buffer)[bufferLength - ipmbChecksumSize] =
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500230 ipmbChecksumCompute((uint8_t*)ipmbBuffer + ipmbChecksum2StartOffset,
Dawid Fryckia642a942018-06-12 10:44:23 -0700231 (ipmbResponseDataHeaderLength + data.size()));
232
Dawid Frycki8188d762019-04-01 18:03:48 -0700233 return buffer;
Dawid Fryckia642a942018-06-12 10:44:23 -0700234}
235
236bool IpmbCommandFilter::isBlocked(const uint8_t reqNetFn, const uint8_t cmd)
237{
238 auto blockedCmd = unhandledCommands.find({reqNetFn, cmd});
239
240 if (blockedCmd != unhandledCommands.end())
241 {
242 return true;
243 }
244
245 return false;
246}
247
248void IpmbCommandFilter::addFilter(const uint8_t reqNetFn, const uint8_t cmd)
249{
250 if (unhandledCommands.insert({reqNetFn, cmd}).second)
251 {
252 phosphor::logging::log<phosphor::logging::level::INFO>(
253 "addFilter: added command to filter",
254 phosphor::logging::entry("netFn = %d", reqNetFn),
255 phosphor::logging::entry("cmd = %d", cmd));
256 }
257}
258
259/**
260 * @brief Ipmb channel
261 */
Qiang XUbbfd00a2019-06-27 21:10:06 +0800262void IpmbChannel::ipmbSendI2cFrame(std::shared_ptr<std::vector<uint8_t>> buffer,
Dawid Fryckia642a942018-06-12 10:44:23 -0700263 size_t retriesAttempted = 0)
264{
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500265 IPMB_PKT* ipmbPkt = reinterpret_cast<IPMB_PKT*>(buffer->data());
Vijay Khemka37a7eac2019-12-06 13:52:28 -0800266 uint8_t targetAddr = ipmbIsResponse(&(ipmbPkt->hdr))
267 ? ipmbPkt->hdr.Header.Resp.address
268 : ipmbPkt->hdr.Header.Req.address;
269 boost::asio::async_write(
270 i2cSlaveDescriptor, boost::asio::buffer(*buffer),
271 [this, buffer, retriesAttempted,
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500272 targetAddr](const boost::system::error_code& ec, size_t bytesSent) {
273 if (ec)
274 {
275 size_t currentRetryCnt = retriesAttempted;
Vijay Khemka37a7eac2019-12-06 13:52:28 -0800276
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500277 if (currentRetryCnt > ipmbI2cNumberOfRetries)
278 {
279 std::string msgToLog =
280 "ipmbSendI2cFrame: send to I2C failed after retries."
281 " busId=" +
282 std::to_string(ipmbBusId) +
283 ", targetAddr=" + std::to_string(targetAddr) +
284 ", error=" + ec.message();
285 phosphor::logging::log<phosphor::logging::level::ERR>(
286 msgToLog.c_str());
287 return;
Dawid Fryckia642a942018-06-12 10:44:23 -0700288 }
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500289 currentRetryCnt++;
290 ipmbSendI2cFrame(buffer, currentRetryCnt);
291 }
Vijay Khemka37a7eac2019-12-06 13:52:28 -0800292 });
Dawid Fryckia642a942018-06-12 10:44:23 -0700293}
294
295/**
296 * @brief Ipmb Outstanding Requests
297 */
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500298void IpmbChannel::makeRequestInvalid(IpmbRequest& request)
Dawid Fryckia642a942018-06-12 10:44:23 -0700299{
300 // change request state to invalid and remove it from outstanding requests
301 // list
302 request.state = ipmbRequestState::invalid;
303 outstandingRequests[request.seq] = nullptr;
304}
305
306void IpmbChannel::makeRequestValid(std::shared_ptr<IpmbRequest> request)
307{
308 // change request state to valid and add it to outstanding requests list
309 request->state = ipmbRequestState::valid;
310 outstandingRequests[request->seq] = request;
311}
312
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500313bool IpmbChannel::seqNumGet(uint8_t& seq)
Dawid Fryckia642a942018-06-12 10:44:23 -0700314{
315 static uint8_t seqNum = 0;
316
317 for (int i = 0; i < ipmbMaxOutstandingRequestsCount; i++)
318 {
Patrick Williamse523af32023-03-30 15:32:06 -0500319 seqNum = (seqNum + 1) % ipmbMaxOutstandingRequestsCount;
Dawid Fryckia642a942018-06-12 10:44:23 -0700320
321 if (outstandingRequests[seqNum] == nullptr)
322 {
323 seq = seqNum;
324 return true;
325 }
326 }
327
328 return false;
329}
330
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500331void IpmbChannel::responseMatch(std::unique_ptr<IpmbResponse>& response)
Dawid Fryckia642a942018-06-12 10:44:23 -0700332{
333 std::shared_ptr<IpmbRequest> request = outstandingRequests[response->seq];
334
335 if (request != nullptr)
336 {
337 if (((ipmbRespNetFn(request->netFn)) == (response->netFn)) &&
338 ((request->rqLun) == (response->rqLun)) &&
339 ((request->rsLun) == (response->rsLun)) &&
340 ((request->cmd) == (response->cmd)))
341 {
342 // match, response is corresponding to previously sent request
343 request->state = ipmbRequestState::matched;
344 request->timer->cancel();
345 request->matchedResponse = std::move(response);
346 }
347 }
348}
349
350void IpmbChannel::processI2cEvent()
351{
352 std::array<uint8_t, ipmbMaxFrameLength> buffer{};
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500353 IPMB_PKT* ipmbPkt = reinterpret_cast<IPMB_PKT*>(buffer.data());
354 IPMB_HEADER* ipmbFrame = &(ipmbPkt->hdr);
Dawid Fryckia642a942018-06-12 10:44:23 -0700355
356 lseek(ipmbi2cSlaveFd, 0, SEEK_SET);
357 int r = read(ipmbi2cSlaveFd, buffer.data(), ipmbMaxFrameLength);
Vijay Khemka37a7eac2019-12-06 13:52:28 -0800358
359 /* Substract first byte len size from total frame length */
360 r--;
361
Dawid Fryckia642a942018-06-12 10:44:23 -0700362 if ((r < ipmbMinFrameLength) || (r > ipmbMaxFrameLength))
363 {
364 goto end;
365 }
366
367 // valiate the frame
368 if (!isFrameValid(ipmbFrame, r))
369 {
370 goto end;
371 }
372
Chen Yugang15185ff2020-09-01 09:20:33 +0800373 // if it is message received from ipmb channel, send out dbus signal
374 if (getChannelType() == ipmbChannelType::ipmb)
Qiang XUbbfd00a2019-06-27 21:10:06 +0800375 {
376 auto ipmbMessageReceived = IpmbRequest();
377 ipmbMessageReceived.i2cToIpmbConstruct(ipmbFrame, r);
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500378 sdbusplus::message_t msg = conn->new_signal(ipmbObj, ipmbDbusIntf,
379 "receiveBroadcast");
Qiang XUbbfd00a2019-06-27 21:10:06 +0800380 msg.append(ipmbMessageReceived.netFn, ipmbMessageReceived.cmd,
381 ipmbMessageReceived.data);
382 msg.signal_send();
383 }
384
Dawid Fryckia642a942018-06-12 10:44:23 -0700385 // copy frame to ipmib message buffer
Chen Yugang3e07b9e2020-10-13 16:14:04 +0800386 if (ipmbIsResponse(ipmbFrame))
Dawid Fryckia642a942018-06-12 10:44:23 -0700387 {
388 std::unique_ptr<IpmbResponse> ipmbMessageReceived =
389 std::make_unique<IpmbResponse>();
390
391 ipmbMessageReceived->i2cToIpmbConstruct(ipmbFrame, r);
392
393 // try to match response with outstanding request
394 responseMatch(ipmbMessageReceived);
395 }
396 else
397 {
398 // if command is blocked - respond with 'invalid command'
399 // completion code
400 if (commandFilter)
401 {
402 uint8_t netFn = ipmbNetFnGet(ipmbFrame->Header.Req.rsNetFnLUN);
403 uint8_t cmd = ipmbFrame->Header.Req.cmd;
Qiang XUbbfd00a2019-06-27 21:10:06 +0800404 uint8_t rqSA = ipmbFrame->Header.Req.rqSA;
Dawid Fryckia642a942018-06-12 10:44:23 -0700405
406 if (commandFilter->isBlocked(netFn, cmd))
407 {
408 uint8_t seq = ipmbSeqGet(ipmbFrame->Header.Req.rqSeqLUN);
409 uint8_t lun =
410 ipmbLunFromSeqLunGet(ipmbFrame->Header.Req.rqSeqLUN);
Dawid Fryckia642a942018-06-12 10:44:23 -0700411
412 // prepare generic response
Qiang XUbbfd00a2019-06-27 21:10:06 +0800413 auto ipmbResponse = IpmbResponse(
414 rqSA, ipmbRespNetFn(netFn), lun, ipmbBmcSlaveAddress, seq,
415 ipmbRsLun, cmd, ipmbIpmiInvalidCmd, {});
Dawid Fryckia642a942018-06-12 10:44:23 -0700416
Dawid Frycki8188d762019-04-01 18:03:48 -0700417 auto buffer = ipmbResponse.ipmbToi2cConstruct();
418 if (buffer)
Dawid Fryckia642a942018-06-12 10:44:23 -0700419 {
Qiang XUbbfd00a2019-06-27 21:10:06 +0800420 ipmbSendI2cFrame(buffer);
Dawid Fryckia642a942018-06-12 10:44:23 -0700421 }
422
423 goto end;
424 }
425 }
426
427 auto ipmbMessageReceived = IpmbRequest();
Dawid Fryckia642a942018-06-12 10:44:23 -0700428 ipmbMessageReceived.i2cToIpmbConstruct(ipmbFrame, r);
429
Kumar Thangavel8fe0abe2020-08-19 21:42:23 +0530430 int devId = getDevIndex();
431
Dawid Frycki8188d762019-04-01 18:03:48 -0700432 std::map<std::string, std::variant<int>> options{
Kumar Thangavel8fe0abe2020-08-19 21:42:23 +0530433 {"rqSA", ipmbAddressTo7BitSet(ipmbMessageReceived.rqSA)},
434 {"hostId", devId}};
435
Dawid Frycki8188d762019-04-01 18:03:48 -0700436 using IpmiDbusRspType = std::tuple<uint8_t, uint8_t, uint8_t, uint8_t,
437 std::vector<uint8_t>>;
438 conn->async_method_call(
439 [this, rqLun{ipmbMessageReceived.rqLun},
Qiang XUbbfd00a2019-06-27 21:10:06 +0800440 seq{ipmbMessageReceived.seq}, address{ipmbMessageReceived.rqSA}](
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500441 const boost::system::error_code& ec,
442 const IpmiDbusRspType& response) {
443 const auto& [netfn, lun, cmd, cc, payload] = response;
444 if (ec)
445 {
446 phosphor::logging::log<phosphor::logging::level::ERR>(
447 "processI2cEvent: error getting response from IPMI");
448 return;
449 }
Dawid Fryckia642a942018-06-12 10:44:23 -0700450
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500451 uint8_t bmcSlaveAddress = getBmcSlaveAddress();
Dawid Frycki8188d762019-04-01 18:03:48 -0700452
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500453 if (payload.size() > ipmbMaxDataSize)
454 {
455 phosphor::logging::log<phosphor::logging::level::ERR>(
456 "processI2cEvent: response exceeding maximum size");
Dawid Frycki8188d762019-04-01 18:03:48 -0700457
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500458 // prepare generic response
459 auto ipmbResponse = IpmbResponse(
460 address, netfn, rqLun, bmcSlaveAddress, seq, ipmbRsLun, cmd,
461 ipmbIpmiCmdRespNotProvided, {});
Dawid Frycki8188d762019-04-01 18:03:48 -0700462
463 auto buffer = ipmbResponse.ipmbToi2cConstruct();
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500464 if (buffer)
Dawid Frycki8188d762019-04-01 18:03:48 -0700465 {
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500466 ipmbSendI2cFrame(buffer);
Dawid Frycki8188d762019-04-01 18:03:48 -0700467 }
468
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500469 return;
470 }
471
472 if (!(netfn & ipmbNetFnResponseMask))
473 {
474 // we are not expecting request here
475 phosphor::logging::log<phosphor::logging::level::ERR>(
476 "processI2cEvent: got a request instead of response");
477 return;
478 }
479
480 // if command is not supported, add it to filter
481 if (cc == ipmbIpmiInvalidCmd)
482 {
483 addFilter(ipmbReqNetFnFromRespNetFn(netfn), cmd);
484 }
485
486 // payload is empty after constructor invocation
487 auto ipmbResponse = IpmbResponse(address, netfn, rqLun,
488 bmcSlaveAddress, seq, lun, cmd, cc,
489 payload);
490
491 auto buffer = ipmbResponse.ipmbToi2cConstruct();
492 if (!buffer)
493 {
494 phosphor::logging::log<phosphor::logging::level::ERR>(
495 "processI2cEvent: error constructing a request");
496 return;
497 }
498
499 ipmbSendI2cFrame(buffer);
Dawid Frycki8188d762019-04-01 18:03:48 -0700500 },
501 "xyz.openbmc_project.Ipmi.Host", "/xyz/openbmc_project/Ipmi",
502 "xyz.openbmc_project.Ipmi.Server", "execute",
503 ipmbMessageReceived.netFn, ipmbMessageReceived.rsLun,
504 ipmbMessageReceived.cmd, ipmbMessageReceived.data, options);
Dawid Fryckia642a942018-06-12 10:44:23 -0700505 }
506
507end:
Vijay Khemka37a7eac2019-12-06 13:52:28 -0800508 i2cSlaveDescriptor.async_wait(
509 boost::asio::posix::descriptor_base::wait_read,
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500510 [this](const boost::system::error_code& ec) {
511 if (ec)
512 {
513 phosphor::logging::log<phosphor::logging::level::ERR>(
514 "Error: processI2cEvent()");
515 return;
516 }
Dawid Fryckia642a942018-06-12 10:44:23 -0700517
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500518 processI2cEvent();
Dawid Fryckia642a942018-06-12 10:44:23 -0700519 });
520}
521
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500522IpmbChannel::IpmbChannel(boost::asio::io_context& io,
Dawid Fryckia642a942018-06-12 10:44:23 -0700523 uint8_t ipmbBmcSlaveAddress,
Kumar Thangavel950a2e82020-07-10 18:07:33 +0530524 uint8_t ipmbRqSlaveAddress, uint8_t channelIdx,
Dawid Fryckia642a942018-06-12 10:44:23 -0700525 std::shared_ptr<IpmbCommandFilter> commandFilter) :
Vijay Khemka37a7eac2019-12-06 13:52:28 -0800526 i2cSlaveDescriptor(io),
527 ipmbBmcSlaveAddress(ipmbBmcSlaveAddress),
Kumar Thangavel950a2e82020-07-10 18:07:33 +0530528 ipmbRqSlaveAddress(ipmbRqSlaveAddress), channelIdx(channelIdx),
Dawid Fryckia642a942018-06-12 10:44:23 -0700529 commandFilter(commandFilter)
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500530{}
Dawid Fryckia642a942018-06-12 10:44:23 -0700531
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500532int IpmbChannel::ipmbChannelInit(const char* ipmbI2cSlave)
Dawid Fryckia642a942018-06-12 10:44:23 -0700533{
Vijay Khemka37a7eac2019-12-06 13:52:28 -0800534 // extract bus id from slave path and save
535 std::string ipmbI2cSlaveStr(ipmbI2cSlave);
536 auto findHyphen = ipmbI2cSlaveStr.find("-");
537 std::string busStr = ipmbI2cSlaveStr.substr(findHyphen + 1);
Qiang XU8edcf1a2019-06-14 22:18:15 +0800538 try
539 {
540 ipmbBusId = std::stoi(busStr);
541 }
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500542 catch (const std::invalid_argument&)
Qiang XU8edcf1a2019-06-14 22:18:15 +0800543 {
544 phosphor::logging::log<phosphor::logging::level::ERR>(
Vijay Khemka37a7eac2019-12-06 13:52:28 -0800545 "ipmbChannelInit: invalid bus id in slave-path config");
Qiang XU8edcf1a2019-06-14 22:18:15 +0800546 return -1;
547 }
548
549 // Check if sysfs has device. If not, enable I2C slave driver by command
Vijay Khemka37a7eac2019-12-06 13:52:28 -0800550 // echo "ipmb-dev 0x1010" > /sys/bus/i2c/devices/i2c-0/new_device
Qiang XU8edcf1a2019-06-14 22:18:15 +0800551 bool hasSysfs = std::filesystem::exists(ipmbI2cSlave);
552 if (!hasSysfs)
553 {
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500554 std::string deviceFileName = "/sys/bus/i2c/devices/i2c-" + busStr +
555 "/new_device";
Vijay Khemka37a7eac2019-12-06 13:52:28 -0800556 std::string para = "ipmb-dev 0x1010"; // init with BMC addr 0x20
Qiang XU8edcf1a2019-06-14 22:18:15 +0800557 std::fstream deviceFile;
558 deviceFile.open(deviceFileName, std::ios::out);
559 if (!deviceFile.good())
560 {
561 phosphor::logging::log<phosphor::logging::level::ERR>(
562 "ipmbChannelInit: error opening deviceFile");
563 return -1;
564 }
565 deviceFile << para;
566 deviceFile.close();
567 }
568
Vijay Khemka37a7eac2019-12-06 13:52:28 -0800569 // open fd to i2c slave device for read write
570 ipmbi2cSlaveFd = open(ipmbI2cSlave, O_RDWR | O_NONBLOCK | O_CLOEXEC);
Dawid Fryckia642a942018-06-12 10:44:23 -0700571 if (ipmbi2cSlaveFd < 0)
572 {
573 phosphor::logging::log<phosphor::logging::level::ERR>(
574 "ipmbChannelInit: error opening ipmbI2cSlave");
575 return -1;
576 }
577
Vijay Khemka37a7eac2019-12-06 13:52:28 -0800578 i2cSlaveDescriptor.assign(ipmbi2cSlaveFd);
Dawid Fryckia642a942018-06-12 10:44:23 -0700579
Vijay Khemka37a7eac2019-12-06 13:52:28 -0800580 i2cSlaveDescriptor.async_wait(
581 boost::asio::posix::descriptor_base::wait_read,
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500582 [this](const boost::system::error_code& ec) {
583 if (ec)
584 {
585 phosphor::logging::log<phosphor::logging::level::ERR>(
586 "Error: processI2cEvent()");
587 return;
588 }
Dawid Fryckia642a942018-06-12 10:44:23 -0700589
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500590 processI2cEvent();
Dawid Fryckia642a942018-06-12 10:44:23 -0700591 });
592
593 return 0;
594}
595
Qiang XU8edcf1a2019-06-14 22:18:15 +0800596int IpmbChannel::ipmbChannelUpdateSlaveAddress(const uint8_t newBmcSlaveAddr)
597{
598 if (ipmbi2cSlaveFd > 0)
599 {
Vijay Khemka37a7eac2019-12-06 13:52:28 -0800600 i2cSlaveDescriptor.close();
Qiang XU8edcf1a2019-06-14 22:18:15 +0800601 close(ipmbi2cSlaveFd);
602 ipmbi2cSlaveFd = 0;
603 }
604
605 // disable old I2C slave driver by command:
606 // echo "0x1010" > /sys/bus/i2c/devices/i2c-0/delete_device
607 std::string deviceFileName;
608 std::string para;
609 std::fstream deviceFile;
610 deviceFileName = "/sys/bus/i2c/devices/i2c-" + std::to_string(ipmbBusId) +
611 "/delete_device";
612 para = "0x1010"; // align with removed ipmb0 definition in dts file
613 deviceFile.open(deviceFileName, std::ios::out);
614 if (!deviceFile.good())
615 {
616 phosphor::logging::log<phosphor::logging::level::ERR>(
617 "ipmbChannelUpdateSlaveAddress: error opening deviceFile to delete "
618 "sysfs");
619 return -1;
620 }
621 deviceFile << para;
622 deviceFile.close();
623
624 // enable new I2C slave driver by command:
Vijay Khemka37a7eac2019-12-06 13:52:28 -0800625 // echo "ipmb-dev 0x1012" > /sys/bus/i2c/devices/i2c-0/new_device
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500626 deviceFileName = "/sys/bus/i2c/devices/i2c-" + std::to_string(ipmbBusId) +
627 "/new_device";
Qiang XU8edcf1a2019-06-14 22:18:15 +0800628 std::ostringstream hex;
629 uint16_t addr = 0x1000 + (newBmcSlaveAddr >> 1);
630 hex << std::hex << static_cast<uint16_t>(addr);
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500631 const std::string& addressHexStr = hex.str();
Vijay Khemka37a7eac2019-12-06 13:52:28 -0800632 para = "ipmb-dev 0x" + addressHexStr;
Qiang XU8edcf1a2019-06-14 22:18:15 +0800633 deviceFile.open(deviceFileName, std::ios::out);
634 if (!deviceFile.good())
635 {
636 phosphor::logging::log<phosphor::logging::level::ERR>(
637 "ipmbChannelUpdateSlaveAddress: error opening deviceFile to create "
638 "sysfs");
639 return -1;
640 }
641 deviceFile << para;
642 deviceFile.close();
643
644 // open fd to i2c slave device
Vijay Khemka37a7eac2019-12-06 13:52:28 -0800645 std::string ipmbI2cSlaveStr = "/dev/ipmb-" + std::to_string(ipmbBusId);
646 ipmbi2cSlaveFd = open(ipmbI2cSlaveStr.c_str(), O_RDWR | O_NONBLOCK);
Qiang XU8edcf1a2019-06-14 22:18:15 +0800647 if (ipmbi2cSlaveFd < 0)
648 {
649 phosphor::logging::log<phosphor::logging::level::ERR>(
650 "ipmbChannelInit: error opening ipmbI2cSlave");
651 return -1;
652 }
653
654 // start to receive i2c data as slave
Vijay Khemka37a7eac2019-12-06 13:52:28 -0800655 i2cSlaveDescriptor.assign(ipmbi2cSlaveFd);
656 i2cSlaveDescriptor.async_wait(
657 boost::asio::posix::descriptor_base::wait_read,
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500658 [this](const boost::system::error_code& ec) {
659 if (ec)
660 {
661 phosphor::logging::log<phosphor::logging::level::ERR>(
662 "Error: processI2cEvent()");
663 return;
664 }
Qiang XU8edcf1a2019-06-14 22:18:15 +0800665
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500666 processI2cEvent();
Qiang XU8edcf1a2019-06-14 22:18:15 +0800667 });
668
Qiang XUbbfd00a2019-06-27 21:10:06 +0800669 ipmbBmcSlaveAddress = newBmcSlaveAddr;
670
Qiang XU8edcf1a2019-06-14 22:18:15 +0800671 return 0;
672}
673
674uint8_t IpmbChannel::getBusId()
675{
676 return ipmbBusId;
677}
678
Dawid Fryckia642a942018-06-12 10:44:23 -0700679uint8_t IpmbChannel::getBmcSlaveAddress()
680{
681 return ipmbBmcSlaveAddress;
682}
683
684uint8_t IpmbChannel::getRqSlaveAddress()
685{
686 return ipmbRqSlaveAddress;
687}
688
Kumar Thangavel950a2e82020-07-10 18:07:33 +0530689uint8_t IpmbChannel::getDevIndex()
690{
691 return channelIdx >> 2;
692}
693
694uint8_t IpmbChannel::getChannelIdx()
695{
696 return channelIdx;
697}
698
Dawid Fryckia642a942018-06-12 10:44:23 -0700699ipmbChannelType IpmbChannel::getChannelType()
700{
Kumar Thangavel950a2e82020-07-10 18:07:33 +0530701 return static_cast<ipmbChannelType>((channelIdx & 3));
Dawid Fryckia642a942018-06-12 10:44:23 -0700702}
703
704void IpmbChannel::addFilter(const uint8_t respNetFn, const uint8_t cmd)
705{
706 if (commandFilter)
707 {
708 commandFilter->addFilter(respNetFn, cmd);
709 }
710}
711
712std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500713 IpmbChannel::requestAdd(boost::asio::yield_context& yield,
Dawid Fryckia642a942018-06-12 10:44:23 -0700714 std::shared_ptr<IpmbRequest> request)
715{
716 makeRequestValid(request);
717
718 std::vector<uint8_t> buffer(0);
719 if (request->ipmbToi2cConstruct(buffer) != 0)
720 {
721 return returnStatus(ipmbResponseStatus::error);
722 }
723
724 for (int i = 0; i < ipmbNumberOfTries; i++)
725 {
726 boost::system::error_code ec;
Jae Hyun Yoo25e85c72019-03-05 14:28:13 -0800727 int i2cRetryCnt = 0;
Dawid Fryckia642a942018-06-12 10:44:23 -0700728
Jae Hyun Yoo25e85c72019-03-05 14:28:13 -0800729 for (; i2cRetryCnt < ipmbI2cNumberOfRetries; i2cRetryCnt++)
Dawid Fryckia642a942018-06-12 10:44:23 -0700730 {
Vijay Khemka37a7eac2019-12-06 13:52:28 -0800731 boost::asio::async_write(i2cSlaveDescriptor,
732 boost::asio::buffer(buffer), yield[ec]);
Dawid Fryckia642a942018-06-12 10:44:23 -0700733
734 if (ec)
735 {
Jae Hyun Yoo25e85c72019-03-05 14:28:13 -0800736 continue; // retry
Dawid Fryckia642a942018-06-12 10:44:23 -0700737 }
738 break;
739 }
740
Jae Hyun Yoo25e85c72019-03-05 14:28:13 -0800741 if (i2cRetryCnt == ipmbI2cNumberOfRetries)
742 {
Qiang XUbbfd00a2019-06-27 21:10:06 +0800743 std::string msgToLog =
744 "requestAdd: Sent to I2C failed after retries."
745 " busId=" +
746 std::to_string(ipmbBusId) + ", error=" + ec.message();
Jae Hyun Yoo25e85c72019-03-05 14:28:13 -0800747 phosphor::logging::log<phosphor::logging::level::INFO>(
Qiang XUbbfd00a2019-06-27 21:10:06 +0800748 msgToLog.c_str());
Jae Hyun Yoo25e85c72019-03-05 14:28:13 -0800749 }
750
Dawid Fryckia642a942018-06-12 10:44:23 -0700751 request->timer->expires_after(
752 std::chrono::milliseconds(ipmbRequestRetryTimeout));
753 request->timer->async_wait(yield[ec]);
754
755 if (ec && ec != boost::asio::error::operation_aborted)
756 {
757 // unexpected error - invalidate request and return generic error
758 phosphor::logging::log<phosphor::logging::level::ERR>(
759 "requestAdd: async_wait error");
760 makeRequestInvalid(*request);
761 return returnStatus(ipmbResponseStatus::error);
762 }
763
764 if (request->state == ipmbRequestState::matched)
765 {
766 // matched response, send it to client application
767 makeRequestInvalid(*request);
768 return request->returnMatchedResponse();
769 }
770 }
771
772 makeRequestInvalid(*request);
773 return returnStatus(ipmbResponseStatus::timeout);
774}
775
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500776static IpmbChannel* getChannel(uint8_t reqChannel)
Dawid Fryckia642a942018-06-12 10:44:23 -0700777{
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500778 auto channel = std::find_if(ipmbChannels.begin(), ipmbChannels.end(),
779 [reqChannel](IpmbChannel& channel) {
780 return channel.getChannelIdx() == reqChannel;
781 });
Dawid Fryckia642a942018-06-12 10:44:23 -0700782 if (channel != ipmbChannels.end())
783 {
784 return &(*channel);
785 }
786
787 return nullptr;
788}
789
790static int initializeChannels()
791{
792 std::shared_ptr<IpmbCommandFilter> commandFilter =
793 std::make_shared<IpmbCommandFilter>();
794
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500795 constexpr const char* configFilePath =
Amithash Prasad314862d2019-03-26 11:14:03 -0700796 "/usr/share/ipmbbridge/ipmb-channels.json";
797 std::ifstream configFile(configFilePath);
798 if (!configFile.is_open())
Dawid Fryckia642a942018-06-12 10:44:23 -0700799 {
Amithash Prasad314862d2019-03-26 11:14:03 -0700800 phosphor::logging::log<phosphor::logging::level::ERR>(
801 "initializeChannels: Cannot open config path");
802 return -1;
803 }
804 try
805 {
Kumar Thangavel950a2e82020-07-10 18:07:33 +0530806 uint8_t devIndex = 0;
Amithash Prasad314862d2019-03-26 11:14:03 -0700807 auto data = nlohmann::json::parse(configFile, nullptr);
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500808 for (const auto& channelConfig : data["channels"])
Dawid Fryckia642a942018-06-12 10:44:23 -0700809 {
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500810 const std::string& typeConfig = channelConfig["type"];
811 const std::string& slavePath = channelConfig["slave-path"];
Amithash Prasad314862d2019-03-26 11:14:03 -0700812 uint8_t bmcAddr = channelConfig["bmc-addr"];
813 uint8_t reqAddr = channelConfig["remote-addr"];
Kumar Thangavel950a2e82020-07-10 18:07:33 +0530814
Amithash Prasad314862d2019-03-26 11:14:03 -0700815 ipmbChannelType type = ipmbChannelTypeMap.at(typeConfig);
816
Kumar Thangavel950a2e82020-07-10 18:07:33 +0530817 if (channelConfig.contains("devIndex"))
818 {
819 devIndex = channelConfig["devIndex"];
820 }
821
822 auto channel = ipmbChannels.emplace(
823 ipmbChannels.end(), io, bmcAddr, reqAddr,
824 ((devIndex << 2) | static_cast<uint8_t>(type)), commandFilter);
Vijay Khemka37a7eac2019-12-06 13:52:28 -0800825 if (channel->ipmbChannelInit(slavePath.c_str()) < 0)
Amithash Prasad314862d2019-03-26 11:14:03 -0700826 {
827 phosphor::logging::log<phosphor::logging::level::ERR>(
828 "initializeChannels: channel initialization failed");
829 return -1;
830 }
Dawid Fryckia642a942018-06-12 10:44:23 -0700831 }
832 }
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500833 catch (const nlohmann::json::exception& e)
Amithash Prasad314862d2019-03-26 11:14:03 -0700834 {
835 phosphor::logging::log<phosphor::logging::level::ERR>(
836 "initializeChannels: Error parsing config file");
837 return -1;
838 }
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500839 catch (const std::out_of_range& e)
Amithash Prasad314862d2019-03-26 11:14:03 -0700840 {
841 phosphor::logging::log<phosphor::logging::level::ERR>(
842 "initializeChannels: Error invalid type");
843 return -1;
844 }
Dawid Fryckia642a942018-06-12 10:44:23 -0700845 return 0;
846}
847
Dawid Fryckia642a942018-06-12 10:44:23 -0700848auto ipmbHandleRequest = [](boost::asio::yield_context yield,
849 uint8_t reqChannel, uint8_t netfn, uint8_t lun,
850 uint8_t cmd, std::vector<uint8_t> dataReceived) {
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500851 IpmbChannel* channel = getChannel(reqChannel);
Kumar Thangavel950a2e82020-07-10 18:07:33 +0530852
Dawid Fryckia642a942018-06-12 10:44:23 -0700853 if (channel == nullptr)
854 {
855 phosphor::logging::log<phosphor::logging::level::ERR>(
856 "ipmbHandleRequest: requested channel does not exist");
857 return returnStatus(ipmbResponseStatus::invalid_param);
858 }
859
860 // check outstanding request list for valid sequence number
861 uint8_t seqNum = 0;
862 bool seqValid = channel->seqNumGet(seqNum);
863 if (!seqValid)
864 {
865 phosphor::logging::log<phosphor::logging::level::WARNING>(
866 "ipmbHandleRequest: cannot add more requests to the list");
867 return returnStatus(ipmbResponseStatus::busy);
868 }
869
870 uint8_t bmcSlaveAddress = channel->getBmcSlaveAddress();
871 uint8_t rqSlaveAddress = channel->getRqSlaveAddress();
872
873 // construct the request to add it to outstanding request list
874 std::shared_ptr<IpmbRequest> request = std::make_shared<IpmbRequest>(
875 rqSlaveAddress, netfn, ipmbRsLun, bmcSlaveAddress, seqNum, lun, cmd,
876 dataReceived);
877
878 if (!request->timer)
879 {
880 phosphor::logging::log<phosphor::logging::level::ERR>(
881 "ipmbHandleRequest: timer object does not exist");
882 return returnStatus(ipmbResponseStatus::error);
883 }
884
885 return channel->requestAdd(yield, request);
886};
887
Qiang XU8edcf1a2019-06-14 22:18:15 +0800888void addUpdateSlaveAddrHandler()
889{
890 // callback to handle dbus signal of updating slave addr
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500891 std::function<void(sdbusplus::message_t&)> updateSlaveAddrHandler =
892 [](sdbusplus::message_t& message) {
893 uint8_t reqChannel, busId, slaveAddr;
Qiang XU8edcf1a2019-06-14 22:18:15 +0800894
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500895 // valid source of signal, check whether from multi-node manager
896 std::string pathName = message.get_path();
897 if (pathName != "/xyz/openbmc_project/MultiNode/Status")
898 {
899 phosphor::logging::log<phosphor::logging::level::ERR>(
900 "addUpdateSlaveAddrHandler: invalid obj path");
901 return;
902 }
Qiang XU8edcf1a2019-06-14 22:18:15 +0800903
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500904 message.read(reqChannel, busId, slaveAddr);
Qiang XU8edcf1a2019-06-14 22:18:15 +0800905
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500906 IpmbChannel* channel = getChannel(reqChannel);
Kumar Thangavel950a2e82020-07-10 18:07:33 +0530907
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500908 if (channel == nullptr ||
909 channel->getChannelType() != ipmbChannelType::ipmb)
910 {
911 phosphor::logging::log<phosphor::logging::level::ERR>(
912 "addUpdateSlaveAddrHandler: invalid channel");
913 return;
914 }
915 if (busId != channel->getBusId())
916 {
917 phosphor::logging::log<phosphor::logging::level::ERR>(
918 "addUpdateSlaveAddrHandler: invalid busId");
919 return;
920 }
921 if (channel->getBmcSlaveAddress() == slaveAddr)
922 {
923 phosphor::logging::log<phosphor::logging::level::INFO>(
924 "addUpdateSlaveAddrHandler: channel bmc slave addr is "
925 "unchanged, do nothing");
926 return;
927 }
Qiang XU8edcf1a2019-06-14 22:18:15 +0800928
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500929 channel->ipmbChannelUpdateSlaveAddress(slaveAddr);
930 };
Qiang XU8edcf1a2019-06-14 22:18:15 +0800931
Patrick Williams3852f8e2022-07-22 19:26:56 -0500932 static auto match = std::make_unique<sdbusplus::bus::match_t>(
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500933 static_cast<sdbusplus::bus_t&>(*conn),
Qiang XU8edcf1a2019-06-14 22:18:15 +0800934 "type='signal',member='updateBmcSlaveAddr',", updateSlaveAddrHandler);
935}
936
Qiang XUbbfd00a2019-06-27 21:10:06 +0800937void addSendBroadcastHandler()
938{
939 // callback to handle dbus signal of sending broadcast message
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500940 std::function<void(sdbusplus::message_t&)> sendBroadcastHandler =
941 [](sdbusplus::message_t& message) {
942 uint8_t reqChannel, netFn, lun, cmd;
943 std::vector<uint8_t> dataReceived;
944 message.read(reqChannel, netFn, lun, cmd, dataReceived);
Qiang XUbbfd00a2019-06-27 21:10:06 +0800945
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500946 IpmbChannel* channel = getChannel(reqChannel);
Kumar Thangavel950a2e82020-07-10 18:07:33 +0530947
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500948 if (channel == nullptr)
949 {
950 phosphor::logging::log<phosphor::logging::level::ERR>(
951 "addSendBroadcastMsgHandler: requested channel does not "
952 "exist");
953 return;
954 }
Qiang XUbbfd00a2019-06-27 21:10:06 +0800955
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500956 uint8_t bmcSlaveAddress = channel->getBmcSlaveAddress();
957 uint8_t seqNum = 0; // seqNum is not used in broadcast msg
958 uint8_t targetAddr = broadcastAddress;
Qiang XUbbfd00a2019-06-27 21:10:06 +0800959
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500960 std::shared_ptr<IpmbRequest> request = std::make_shared<IpmbRequest>(
961 targetAddr, netFn, ipmbRsLun, bmcSlaveAddress, seqNum, lun, cmd,
962 dataReceived);
Qiang XUbbfd00a2019-06-27 21:10:06 +0800963
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500964 std::shared_ptr<std::vector<uint8_t>> buffer =
965 std::make_shared<std::vector<uint8_t>>();
Qiang XUbbfd00a2019-06-27 21:10:06 +0800966
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500967 if (request->ipmbToi2cConstruct(*buffer) != 0)
968 {
969 return;
970 }
Qiang XUbbfd00a2019-06-27 21:10:06 +0800971
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500972 channel->ipmbSendI2cFrame(buffer);
973 };
Qiang XUbbfd00a2019-06-27 21:10:06 +0800974
Patrick Williams3852f8e2022-07-22 19:26:56 -0500975 static auto match = std::make_unique<sdbusplus::bus::match_t>(
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500976 static_cast<sdbusplus::bus_t&>(*conn),
Qiang XUbbfd00a2019-06-27 21:10:06 +0800977 "type='signal',member='sendBroadcast',", sendBroadcastHandler);
978}
979
Dawid Fryckia642a942018-06-12 10:44:23 -0700980/**
981 * @brief Main
982 */
Patrick Williamsfe0d38a2023-03-30 14:51:33 -0500983int main(int argc, char* argv[])
Dawid Fryckia642a942018-06-12 10:44:23 -0700984{
985 conn->request_name(ipmbBus);
986
987 auto server = sdbusplus::asio::object_server(conn);
988
Dawid Fryckia642a942018-06-12 10:44:23 -0700989 std::shared_ptr<sdbusplus::asio::dbus_interface> ipmbIface =
990 server.add_interface(ipmbObj, ipmbDbusIntf);
991
Dawid Fryckia642a942018-06-12 10:44:23 -0700992 ipmbIface->register_method("sendRequest", std::move(ipmbHandleRequest));
Dawid Fryckia642a942018-06-12 10:44:23 -0700993 ipmbIface->initialize();
994
995 if (initializeChannels() < 0)
996 {
997 phosphor::logging::log<phosphor::logging::level::ERR>(
998 "Error initializeChannels");
999 return -1;
1000 }
1001
Qiang XU8edcf1a2019-06-14 22:18:15 +08001002 addUpdateSlaveAddrHandler();
1003
Qiang XUbbfd00a2019-06-27 21:10:06 +08001004 addSendBroadcastHandler();
1005
Dawid Fryckia642a942018-06-12 10:44:23 -07001006 io.run();
1007 return 0;
1008}