blob: 2f78cd0d1ed47d87872226867104582ada94d195 [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
21#include <linux/i2c-dev-user.h>
22
23#include <phosphor-logging/log.hpp>
24#include <tuple>
25
26/**
27 * @brief Dbus
28 */
29static constexpr const char *ipmbBus = "xyz.openbmc_project.Ipmi.Channel.Ipmb";
30static constexpr const char *ipmbObj = "/xyz/openbmc_project/Ipmi/Channel/Ipmb";
31static constexpr const char *hostIpmiIntf = "org.openbmc.HostIpmi";
32static constexpr const char *ipmbDbusIntf = "org.openbmc.Ipmb";
33
34boost::asio::io_service io;
35auto conn = std::make_shared<sdbusplus::asio::connection>(io);
36
37/**
38 * @brief Channel configuration table
39 * TODO : move to user configuration as JSON file
40 */
41static const std::vector<IpmbChannelConfig> ipmbChannelsConfig = {
42 // ME channel
43 {ipmbChannelType::me, "/sys/bus/i2c/devices/5-1010/slave-mqueue",
44 "/dev/i2c-5", 0x20, 0x2C}, // 8 bit addresses
45 // IPMB header channel
46 {ipmbChannelType::ipmb, "/sys/bus/i2c/devices/0-1010/slave-mqueue",
47 "/dev/i2c-0", 0x20, 0x58}}; // 8 bit addresses
48
49static std::list<IpmbChannel> ipmbChannels;
50
51/**
52 * @brief Ipmb request class methods
53 */
54IpmbRequest::IpmbRequest()
55{
56 data.reserve(ipmbMaxDataSize);
57}
58
59IpmbRequest::IpmbRequest(uint8_t address, uint8_t netFn, uint8_t rsLun,
60 uint8_t rqSA, uint8_t seq, uint8_t rqLun, uint8_t cmd,
61 std::vector<uint8_t> &inputData) :
62 address(address),
63 netFn(netFn), rsLun(rsLun), rqSA(rqSA), seq(seq), rqLun(rqLun), cmd(cmd),
64 timer(io)
65{
66 data.reserve(ipmbMaxDataSize);
67 state = ipmbRequestState::invalid;
68
69 if (inputData.size() > 0)
70 {
71 data = std::move(inputData);
72 }
73}
74
75void IpmbRequest::incomingMessageHandler()
76{
77 sdbusplus::message::message mesg =
78 conn->new_signal(ipmbObj, hostIpmiIntf, "ReceivedMessage");
79 mesg.append(seq, netFn, rsLun, cmd, data);
80 mesg.signal_send();
81}
82
83void IpmbRequest::i2cToIpmbConstruct(IPMB_HEADER *ipmbBuffer,
84 size_t bufferLength)
85{
86 // constructing ipmb request from i2c buffer
87 netFn = ipmbNetFnGet(ipmbBuffer->Header.Req.rsNetFnLUN);
88 rsLun = ipmbLunFromNetFnLunGet(ipmbBuffer->Header.Req.rsNetFnLUN);
89 rqSA = ipmbBuffer->Header.Req.rqSA;
90 seq = ipmbSeqGet(ipmbBuffer->Header.Req.rqSeqLUN);
91 rqLun = ipmbLunFromSeqLunGet(ipmbBuffer->Header.Req.rqSeqLUN);
92 cmd = ipmbBuffer->Header.Req.cmd;
93
94 size_t dataLength =
95 bufferLength - (ipmbConnectionHeaderLength +
96 ipmbRequestDataHeaderLength + ipmbChecksumSize);
97
98 if (dataLength > 0)
99 {
100 data.insert(data.end(), ipmbBuffer->Header.Req.data,
101 &ipmbBuffer->Header.Req.data[dataLength]);
102 }
103}
104
105int IpmbRequest::ipmbToi2cConstruct(std::vector<uint8_t> &buffer)
106{
107 size_t bufferLength = data.size() + ipmbRequestDataHeaderLength +
108 ipmbConnectionHeaderLength + ipmbChecksumSize;
109
110 if (bufferLength > ipmbMaxFrameLength)
111 {
112 return -1;
113 }
114
115 buffer.resize(bufferLength);
116 static_assert(ipmbMaxFrameLength >= sizeof(IPMB_HEADER));
117 auto ipmbBuffer = reinterpret_cast<IPMB_HEADER *>(buffer.data());
118
119 // constructing buffer from ipmb request
120 ipmbBuffer->Header.Req.address = address;
121 ipmbBuffer->Header.Req.rsNetFnLUN = ipmbNetFnLunSet(netFn, rsLun);
122 ipmbBuffer->Header.Req.rqSA = rqSA;
123 ipmbBuffer->Header.Req.rqSeqLUN = ipmbSeqLunSet(seq, rqLun);
124 ipmbBuffer->Header.Req.cmd = cmd;
125
126 ipmbBuffer->Header.Resp.checksum1 = ipmbChecksumCompute(
127 buffer.data(), ipmbConnectionHeaderLength - ipmbChecksumSize);
128
129 if (data.size() > 0)
130 {
131 std::copy(data.begin(), data.end(), ipmbBuffer->Header.Req.data);
132 }
133
134 buffer[bufferLength - ipmbChecksumSize] =
135 ipmbChecksumCompute(buffer.data() + ipmbChecksum2StartOffset,
136 (ipmbRequestDataHeaderLength + data.size()));
137
138 return 0;
139}
140
141std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
142 IpmbRequest::returnMatchedResponse()
143{
144 return std::make_tuple(
145 static_cast<int>(ipmbResponseStatus::success), matchedResponse->netFn,
146 matchedResponse->rsLun, matchedResponse->cmd,
147 matchedResponse->completionCode, matchedResponse->data);
148}
149
150static std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
151 returnStatus(ipmbResponseStatus status)
152{
153 // we only want to send status here, other fields are not relevant
154 return std::make_tuple(static_cast<int>(status), 0, 0, 0, 0,
155 std::vector<uint8_t>(0));
156}
157
158// TODO w/a to differentiate channel origin of incoming IPMI response: saving
159// channel number at two oldest unused bits of seq
160void IpmbRequest::addChannelToSeq(const ipmbChannelType &channelType)
161{
162 uint8_t newSeq = (seq | ((static_cast<uint8_t>(channelType) & 0x3) << 6));
163 seq = newSeq;
164}
165
166/**
167 * @brief Ipmb response class methods
168 */
169IpmbResponse::IpmbResponse()
170{
171 data.reserve(ipmbMaxDataSize);
172}
173
174IpmbResponse::IpmbResponse(uint8_t address, uint8_t netFn, uint8_t rqLun,
175 uint8_t rsSA, uint8_t seq, uint8_t rsLun,
176 uint8_t cmd, uint8_t completionCode,
177 std::vector<uint8_t> &inputData) :
178 address(address),
179 netFn(netFn), rqLun(rqLun), rsSA(rsSA), seq(seq), rsLun(rsLun), cmd(cmd),
180 completionCode(completionCode)
181{
182 data.reserve(ipmbMaxDataSize);
183
184 if (inputData.size() > 0)
185 {
186 data = std::move(inputData);
187 }
188}
189
190void IpmbResponse::i2cToIpmbConstruct(IPMB_HEADER *ipmbBuffer,
191 size_t bufferLength)
192{
193 netFn = ipmbNetFnGet(ipmbBuffer->Header.Resp.rqNetFnLUN);
194 rqLun = ipmbLunFromNetFnLunGet(ipmbBuffer->Header.Resp.rqNetFnLUN);
195 rsSA = ipmbBuffer->Header.Resp.rsSA;
196 seq = ipmbSeqGet(ipmbBuffer->Header.Resp.rsSeqLUN);
197 rsLun = ipmbLunFromSeqLunGet(ipmbBuffer->Header.Resp.rsSeqLUN);
198 cmd = ipmbBuffer->Header.Resp.cmd;
199 completionCode = ipmbBuffer->Header.Resp.completionCode;
200
201 size_t dataLength =
202 bufferLength - (ipmbConnectionHeaderLength +
203 ipmbResponseDataHeaderLength + ipmbChecksumSize);
204
205 if (dataLength > 0)
206 {
207 data.insert(data.end(), ipmbBuffer->Header.Resp.data,
208 &ipmbBuffer->Header.Resp.data[dataLength]);
209 }
210}
211
212int IpmbResponse::ipmbToi2cConstruct(std::vector<uint8_t> &buffer)
213{
214 size_t bufferLength = data.size() + ipmbResponseDataHeaderLength +
215 ipmbConnectionHeaderLength + ipmbChecksumSize;
216
217 if (bufferLength > ipmbMaxFrameLength)
218 {
219 return -1;
220 }
221
222 buffer.resize(bufferLength);
223 auto ipmbBuffer = reinterpret_cast<IPMB_HEADER *>(buffer.data());
224
225 ipmbBuffer->Header.Resp.address = address;
226 ipmbBuffer->Header.Resp.rqNetFnLUN = ipmbNetFnLunSet(netFn, rqLun);
227 ipmbBuffer->Header.Resp.rsSA = rsSA;
228 ipmbBuffer->Header.Resp.rsSeqLUN = ipmbSeqLunSet(seq, rsLun);
229 ipmbBuffer->Header.Resp.cmd = cmd;
230 ipmbBuffer->Header.Resp.completionCode = completionCode;
231
232 ipmbBuffer->Header.Resp.checksum1 = ipmbChecksumCompute(
233 buffer.data(), ipmbConnectionHeaderLength - ipmbChecksumSize);
234
235 if (data.size() > 0)
236 {
237 std::copy(data.begin(), data.end(), ipmbBuffer->Header.Resp.data);
238 }
239
240 buffer[bufferLength - ipmbChecksumSize] =
241 ipmbChecksumCompute(buffer.data() + ipmbChecksum2StartOffset,
242 (ipmbResponseDataHeaderLength + data.size()));
243
244 return 0;
245}
246
247bool IpmbCommandFilter::isBlocked(const uint8_t reqNetFn, const uint8_t cmd)
248{
249 auto blockedCmd = unhandledCommands.find({reqNetFn, cmd});
250
251 if (blockedCmd != unhandledCommands.end())
252 {
253 return true;
254 }
255
256 return false;
257}
258
259void IpmbCommandFilter::addFilter(const uint8_t reqNetFn, const uint8_t cmd)
260{
261 if (unhandledCommands.insert({reqNetFn, cmd}).second)
262 {
263 phosphor::logging::log<phosphor::logging::level::INFO>(
264 "addFilter: added command to filter",
265 phosphor::logging::entry("netFn = %d", reqNetFn),
266 phosphor::logging::entry("cmd = %d", cmd));
267 }
268}
269
270/**
271 * @brief Ipmb channel
272 */
273void IpmbChannel::ipmbResponseSend(std::shared_ptr<std::vector<uint8_t>> buffer,
274 size_t retriesAttempted = 0)
275{
276 boost::asio::async_write(
277 i2cMasterSocket,
278 boost::asio::buffer(buffer->data() + ipmbAddressSize,
279 buffer->size() - ipmbAddressSize),
280 [this, buffer, retriesAttempted](const boost::system::error_code ec,
281 size_t bytesSent) {
282 if (ec)
283 {
284 size_t currentRetryCnt = retriesAttempted;
285
286 if (currentRetryCnt > ipmbI2cNumberOfRetries)
287 {
288 phosphor::logging::log<phosphor::logging::level::ERR>(
289 "ipmbResponseSend: sent to I2C failed after retries");
290 return;
291 }
292 currentRetryCnt++;
293 ipmbResponseSend(buffer, currentRetryCnt);
294 }
295 });
296}
297
298/**
299 * @brief Ipmb Outstanding Requests
300 */
301void IpmbChannel::makeRequestInvalid(IpmbRequest &request)
302{
303 // change request state to invalid and remove it from outstanding requests
304 // list
305 request.state = ipmbRequestState::invalid;
306 outstandingRequests[request.seq] = nullptr;
307}
308
309void IpmbChannel::makeRequestValid(std::shared_ptr<IpmbRequest> request)
310{
311 // change request state to valid and add it to outstanding requests list
312 request->state = ipmbRequestState::valid;
313 outstandingRequests[request->seq] = request;
314}
315
316bool IpmbChannel::seqNumGet(uint8_t &seq)
317{
318 static uint8_t seqNum = 0;
319
320 for (int i = 0; i < ipmbMaxOutstandingRequestsCount; i++)
321 {
322 seqNum = ++seqNum & ipmbSeqMask;
323 if (seqNum == ipmbMaxOutstandingRequestsCount)
324 {
325 seqNum = 0;
326 }
327
328 if (outstandingRequests[seqNum] == nullptr)
329 {
330 seq = seqNum;
331 return true;
332 }
333 }
334
335 return false;
336}
337
338void IpmbChannel::responseMatch(std::unique_ptr<IpmbResponse> &response)
339{
340 std::shared_ptr<IpmbRequest> request = outstandingRequests[response->seq];
341
342 if (request != nullptr)
343 {
344 if (((ipmbRespNetFn(request->netFn)) == (response->netFn)) &&
345 ((request->rqLun) == (response->rqLun)) &&
346 ((request->rsLun) == (response->rsLun)) &&
347 ((request->cmd) == (response->cmd)))
348 {
349 // match, response is corresponding to previously sent request
350 request->state = ipmbRequestState::matched;
351 request->timer->cancel();
352 request->matchedResponse = std::move(response);
353 }
354 }
355}
356
357void IpmbChannel::processI2cEvent()
358{
359 std::array<uint8_t, ipmbMaxFrameLength> buffer{};
360 auto ipmbFrame = reinterpret_cast<IPMB_HEADER *>(buffer.data());
361
362 lseek(ipmbi2cSlaveFd, 0, SEEK_SET);
363 int r = read(ipmbi2cSlaveFd, buffer.data(), ipmbMaxFrameLength);
364 if ((r < ipmbMinFrameLength) || (r > ipmbMaxFrameLength))
365 {
366 goto end;
367 }
368
369 // valiate the frame
370 if (!isFrameValid(ipmbFrame, r))
371 {
372 goto end;
373 }
374
375 // copy frame to ipmib message buffer
376 if (ipmbIsResponse(ipmbFrame))
377 {
378 std::unique_ptr<IpmbResponse> ipmbMessageReceived =
379 std::make_unique<IpmbResponse>();
380
381 ipmbMessageReceived->i2cToIpmbConstruct(ipmbFrame, r);
382
383 // try to match response with outstanding request
384 responseMatch(ipmbMessageReceived);
385 }
386 else
387 {
388 // if command is blocked - respond with 'invalid command'
389 // completion code
390 if (commandFilter)
391 {
392 uint8_t netFn = ipmbNetFnGet(ipmbFrame->Header.Req.rsNetFnLUN);
393 uint8_t cmd = ipmbFrame->Header.Req.cmd;
394
395 if (commandFilter->isBlocked(netFn, cmd))
396 {
397 uint8_t seq = ipmbSeqGet(ipmbFrame->Header.Req.rqSeqLUN);
398 uint8_t lun =
399 ipmbLunFromSeqLunGet(ipmbFrame->Header.Req.rqSeqLUN);
400 std::vector<uint8_t> data;
401
402 // prepare generic response
403 auto ipmbResponse =
404 IpmbResponse(ipmbRqSlaveAddress, ipmbRespNetFn(netFn), lun,
405 ipmbBmcSlaveAddress, seq, ipmbRsLun, cmd,
406 ipmbIpmiInvalidCommand, data);
407
408 std::shared_ptr<std::vector<uint8_t>> buffer =
409 std::make_shared<std::vector<uint8_t>>();
410
411 if (ipmbResponse.ipmbToi2cConstruct(*buffer) == 0)
412 {
413 ipmbResponseSend(buffer);
414 }
415
416 goto end;
417 }
418 }
419
420 auto ipmbMessageReceived = IpmbRequest();
421
422 ipmbMessageReceived.i2cToIpmbConstruct(ipmbFrame, r);
423
424 // TODO w/a to differentiate channel origin of incoming IPMI
425 // response: extracting channel number from seq
426 ipmbMessageReceived.addChannelToSeq(getChannelType());
427
428 // send request to the client
429 ipmbMessageReceived.incomingMessageHandler();
430 }
431
432end:
433 i2cSlaveSocket.async_wait(
434 boost::asio::ip::tcp::socket::wait_error,
435 [this](const boost::system::error_code &ec) {
436 if (ec)
437 {
438 phosphor::logging::log<phosphor::logging::level::ERR>(
439 "Error: processI2cEvent()");
440 return;
441 }
442
443 processI2cEvent();
444 });
445}
446
447IpmbChannel::IpmbChannel(boost::asio::io_service &io,
448 uint8_t ipmbBmcSlaveAddress,
449 uint8_t ipmbRqSlaveAddress, ipmbChannelType type,
450 std::shared_ptr<IpmbCommandFilter> commandFilter) :
451 i2cSlaveSocket(io),
452 i2cMasterSocket(io), ipmbBmcSlaveAddress(ipmbBmcSlaveAddress),
453 ipmbRqSlaveAddress(ipmbRqSlaveAddress), type(type),
454 commandFilter(commandFilter)
455{
456}
457
458int IpmbChannel::ipmbChannelInit(const char *ipmbI2cSlave,
459 const char *ipmbI2cMaster)
460{
461 // open fd to i2c slave device
462 ipmbi2cSlaveFd = open(ipmbI2cSlave, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
463 if (ipmbi2cSlaveFd < 0)
464 {
465 phosphor::logging::log<phosphor::logging::level::ERR>(
466 "ipmbChannelInit: error opening ipmbI2cSlave");
467 return -1;
468 }
469
470 // open fd to i2c master device
471 ipmbi2cMasterFd = open(ipmbI2cMaster, O_RDWR | O_NONBLOCK);
472 if (ipmbi2cMasterFd < 0)
473 {
474 phosphor::logging::log<phosphor::logging::level::ERR>(
475 "ipmbChannelInit: error opening ipmbI2cMaster");
476 close(ipmbi2cSlaveFd);
477 return -1;
478 }
479
480 // set slave address of recipient
481 if (ioctl(ipmbi2cMasterFd, I2C_SLAVE,
482 ipmbAddressTo7BitSet(ipmbRqSlaveAddress)) < 0)
483 {
484 phosphor::logging::log<phosphor::logging::level::ERR>(
485 "ipmbChannelInit: error setting ipmbi2cMasterFd slave address");
486 close(ipmbi2cSlaveFd);
487 close(ipmbi2cMasterFd);
488 return -1;
489 }
490
491 i2cMasterSocket.assign(ipmbi2cMasterFd);
492 i2cSlaveSocket.assign(boost::asio::ip::tcp::v4(), ipmbi2cSlaveFd);
493 i2cSlaveSocket.async_wait(
494 boost::asio::ip::tcp::socket::wait_error,
495 [this](const boost::system::error_code &ec) {
496 if (ec)
497 {
498 phosphor::logging::log<phosphor::logging::level::ERR>(
499 "Error: processI2cEvent()");
500 return;
501 }
502
503 processI2cEvent();
504 });
505
506 return 0;
507}
508
509uint8_t IpmbChannel::getBmcSlaveAddress()
510{
511 return ipmbBmcSlaveAddress;
512}
513
514uint8_t IpmbChannel::getRqSlaveAddress()
515{
516 return ipmbRqSlaveAddress;
517}
518
519ipmbChannelType IpmbChannel::getChannelType()
520{
521 return type;
522}
523
524void IpmbChannel::addFilter(const uint8_t respNetFn, const uint8_t cmd)
525{
526 if (commandFilter)
527 {
528 commandFilter->addFilter(respNetFn, cmd);
529 }
530}
531
532std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
533 IpmbChannel::requestAdd(boost::asio::yield_context &yield,
534 std::shared_ptr<IpmbRequest> request)
535{
536 makeRequestValid(request);
537
538 std::vector<uint8_t> buffer(0);
539 if (request->ipmbToi2cConstruct(buffer) != 0)
540 {
541 return returnStatus(ipmbResponseStatus::error);
542 }
543
544 for (int i = 0; i < ipmbNumberOfTries; i++)
545 {
546 boost::system::error_code ec;
547
548 for (int j = 0; j < ipmbI2cNumberOfRetries; j++)
549 {
550 boost::asio::async_write(
551 i2cMasterSocket,
552 boost::asio::buffer(buffer.data() + ipmbAddressSize,
553 buffer.size() - ipmbAddressSize),
554 yield[ec]);
555
556 if (ec)
557 {
558 phosphor::logging::log<phosphor::logging::level::INFO>(
559 "requestAdd: Sent to I2C failed");
560 continue;
561 }
562 break;
563 }
564
565 request->timer->expires_after(
566 std::chrono::milliseconds(ipmbRequestRetryTimeout));
567 request->timer->async_wait(yield[ec]);
568
569 if (ec && ec != boost::asio::error::operation_aborted)
570 {
571 // unexpected error - invalidate request and return generic error
572 phosphor::logging::log<phosphor::logging::level::ERR>(
573 "requestAdd: async_wait error");
574 makeRequestInvalid(*request);
575 return returnStatus(ipmbResponseStatus::error);
576 }
577
578 if (request->state == ipmbRequestState::matched)
579 {
580 // matched response, send it to client application
581 makeRequestInvalid(*request);
582 return request->returnMatchedResponse();
583 }
584 }
585
586 makeRequestInvalid(*request);
587 return returnStatus(ipmbResponseStatus::timeout);
588}
589
590static IpmbChannel *getChannel(ipmbChannelType channelType)
591{
592 auto channel =
593 std::find_if(ipmbChannels.begin(), ipmbChannels.end(),
594 [channelType](IpmbChannel &channel) {
595 return channel.getChannelType() == channelType;
596 });
597 if (channel != ipmbChannels.end())
598 {
599 return &(*channel);
600 }
601
602 return nullptr;
603}
604
605static int initializeChannels()
606{
607 std::shared_ptr<IpmbCommandFilter> commandFilter =
608 std::make_shared<IpmbCommandFilter>();
609
610 for (const auto &channelConfig : ipmbChannelsConfig)
611 {
612 auto channel = ipmbChannels.emplace(ipmbChannels.end(), io,
613 channelConfig.ipmbBmcSlaveAddress,
614 channelConfig.ipmbRqSlaveAddress,
615 channelConfig.type, commandFilter);
616
617 if (channel->ipmbChannelInit(channelConfig.ipmbI2cSlave,
618 channelConfig.ipmbI2cMaster) < 0)
619 {
620 phosphor::logging::log<phosphor::logging::level::ERR>(
621 "initializeChannels: channel initialization failed");
622 return -1;
623 }
624 }
625
626 return 0;
627}
628
629/**
630 * @brief Dbus callbacks
631 */
632auto ipmbSendMessage = [](uint8_t seq, uint8_t netfn, uint8_t lun, uint8_t cmd,
633 uint8_t cc, std::vector<uint8_t> &dataReceived) {
634 int64_t status = -1;
635 std::shared_ptr<std::vector<uint8_t>> buffer =
636 std::make_shared<std::vector<uint8_t>>();
637
638 if (dataReceived.size() > ipmbMaxDataSize)
639 {
640 return status;
641 }
642
643 if (netfn & ipmbNetFnResponseMask)
644 {
645 IpmbChannel *channel = getChannel(getChannelFromSeq(seq));
646 if (channel == nullptr)
647 {
648 phosphor::logging::log<phosphor::logging::level::ERR>(
649 "ipmbSendMessage: channel does not exist");
650 return status;
651 }
652
653 // if command is not supported, add it to filter
654 if (cc == ipmbIpmiInvalidCommand)
655 {
656 channel->addFilter(ipmbReqNetFnFromRespNetFn(netfn), cmd);
657 }
658
659 uint8_t rqSlaveAddress = channel->getRqSlaveAddress();
660 uint8_t bmcSlaveAddress = channel->getBmcSlaveAddress();
661
662 // response received
663 // dataReceived is empty after constructor invocation
664 std::unique_ptr<IpmbResponse> ipmbMessageReceived =
665 std::make_unique<IpmbResponse>(rqSlaveAddress, netfn, lun,
666 bmcSlaveAddress, seq, lun, cmd, cc,
667 dataReceived);
668
669 status = ipmbMessageReceived->ipmbToi2cConstruct(*buffer);
670 if (status != 0)
671 {
672 return status;
673 }
674
675 channel->ipmbResponseSend(buffer);
676 return status;
677 }
678
679 // we are not expecting request here
680 phosphor::logging::log<phosphor::logging::level::ERR>(
681 "ipmbSendMessage: got a request");
682 return status;
683};
684
685auto ipmbHandleRequest = [](boost::asio::yield_context yield,
686 uint8_t reqChannel, uint8_t netfn, uint8_t lun,
687 uint8_t cmd, std::vector<uint8_t> dataReceived) {
688 IpmbChannel *channel = getChannel(static_cast<ipmbChannelType>(reqChannel));
689 if (channel == nullptr)
690 {
691 phosphor::logging::log<phosphor::logging::level::ERR>(
692 "ipmbHandleRequest: requested channel does not exist");
693 return returnStatus(ipmbResponseStatus::invalid_param);
694 }
695
696 // check outstanding request list for valid sequence number
697 uint8_t seqNum = 0;
698 bool seqValid = channel->seqNumGet(seqNum);
699 if (!seqValid)
700 {
701 phosphor::logging::log<phosphor::logging::level::WARNING>(
702 "ipmbHandleRequest: cannot add more requests to the list");
703 return returnStatus(ipmbResponseStatus::busy);
704 }
705
706 uint8_t bmcSlaveAddress = channel->getBmcSlaveAddress();
707 uint8_t rqSlaveAddress = channel->getRqSlaveAddress();
708
709 // construct the request to add it to outstanding request list
710 std::shared_ptr<IpmbRequest> request = std::make_shared<IpmbRequest>(
711 rqSlaveAddress, netfn, ipmbRsLun, bmcSlaveAddress, seqNum, lun, cmd,
712 dataReceived);
713
714 if (!request->timer)
715 {
716 phosphor::logging::log<phosphor::logging::level::ERR>(
717 "ipmbHandleRequest: timer object does not exist");
718 return returnStatus(ipmbResponseStatus::error);
719 }
720
721 return channel->requestAdd(yield, request);
722};
723
724/**
725 * @brief Main
726 */
727int main(int argc, char *argv[])
728{
729 conn->request_name(ipmbBus);
730
731 auto server = sdbusplus::asio::object_server(conn);
732
733 std::shared_ptr<sdbusplus::asio::dbus_interface> ipmiIface =
734 server.add_interface(ipmbObj, hostIpmiIntf);
735 std::shared_ptr<sdbusplus::asio::dbus_interface> ipmbIface =
736 server.add_interface(ipmbObj, ipmbDbusIntf);
737
738 ipmiIface->register_method("sendMessage", std::move(ipmbSendMessage));
739 ipmbIface->register_method("sendRequest", std::move(ipmbHandleRequest));
740 ipmiIface->initialize();
741 ipmbIface->initialize();
742
743 if (initializeChannels() < 0)
744 {
745 phosphor::logging::log<phosphor::logging::level::ERR>(
746 "Error initializeChannels");
747 return -1;
748 }
749
750 io.run();
751 return 0;
752}