blob: 6749b00e6fd4a85dd9ec3bb8bceb5279f0d34047 [file] [log] [blame]
Vernon Mauerya3702c12019-05-22 13:20:59 -07001/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16
Yong Lic3580e92019-08-15 14:36:47 +080017#include <bitset>
Vernon Mauerya3702c12019-05-22 13:20:59 -070018#include <bridgingcommands.hpp>
19#include <cstring>
Vernon Mauery15419dd2019-05-24 09:40:30 -070020#include <ipmid/api.hpp>
Yong Lic3580e92019-08-15 14:36:47 +080021#include <ipmid/utils.hpp>
Vernon Mauerya3702c12019-05-22 13:20:59 -070022#include <phosphor-logging/log.hpp>
23#include <sdbusplus/bus.hpp>
24#include <sdbusplus/bus/match.hpp>
25#include <sdbusplus/message.hpp>
jayaprakash Mutyala5ba46872019-11-20 00:02:48 +000026#include <storagecommands.hpp>
Vernon Mauerya3702c12019-05-22 13:20:59 -070027#include <vector>
28
Yong Lic3580e92019-08-15 14:36:47 +080029static constexpr const char *wdtService = "xyz.openbmc_project.Watchdog";
30static constexpr const char *wdtInterface =
31 "xyz.openbmc_project.State.Watchdog";
32static constexpr const char *wdtObjPath = "/xyz/openbmc_project/watchdog/host0";
33static constexpr const char *wdtInterruptFlagProp =
34 "PreTimeoutInterruptOccurFlag";
35
Vernon Mauerya3702c12019-05-22 13:20:59 -070036static 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 *ipmbIntf = "org.openbmc.Ipmb";
39
40static Bridging bridging;
jayaprakash Mutyala5ba46872019-11-20 00:02:48 +000041static bool eventMessageBufferFlag = false;
Vernon Mauerya3702c12019-05-22 13:20:59 -070042
jayaprakash Mutyala405f54a2019-10-18 18:23:27 +000043void Bridging::clearResponseQueue()
44{
45 responseQueue.clear();
46}
47
Vernon Mauerya3702c12019-05-22 13:20:59 -070048/**
49 * @brief utils for checksum
50 */
51static bool ipmbChecksumValidate(uint8_t *data, uint8_t length)
52{
53 if (data == nullptr)
54 {
55 return false;
56 }
57
58 uint8_t checksum = 0;
59
60 for (uint8_t idx = 0; idx < length; idx++)
61 {
62 checksum += data[idx];
63 }
64
65 if (0 == checksum)
66 {
67 return true;
68 }
69
70 return false;
71}
72
73static uint8_t ipmbChecksumCompute(uint8_t *data, uint8_t length)
74{
75 if (data == nullptr)
76 {
77 return 0;
78 }
79
80 uint8_t checksum = 0;
81
82 for (uint8_t idx = 0; idx < length; idx++)
83 {
84 checksum += data[idx];
85 }
86
87 checksum = (~checksum) + 1;
88 return checksum;
89}
90
91static inline bool ipmbConnectionHeaderChecksumValidate(ipmbHeader *ipmbHeader)
92{
93 return ipmbChecksumValidate(reinterpret_cast<uint8_t *>(ipmbHeader),
94 ipmbConnectionHeaderLength);
95}
96
97static inline bool ipmbDataChecksumValidate(ipmbHeader *ipmbHeader,
98 uint8_t length)
99{
100 return ipmbChecksumValidate(
101 (reinterpret_cast<uint8_t *>(ipmbHeader) + ipmbConnectionHeaderLength),
102 (length - ipmbConnectionHeaderLength));
103}
104
105static bool isFrameValid(ipmbHeader *frame, uint8_t length)
106{
107 if ((length < ipmbMinFrameLength) || (length > ipmbMaxFrameLength))
108 {
109 return false;
110 }
111
112 if (false == ipmbConnectionHeaderChecksumValidate(frame))
113 {
114 return false;
115 }
116
117 if (false == ipmbDataChecksumValidate(frame, length))
118 {
119 return false;
120 }
121
122 return true;
123}
124
125IpmbRequest::IpmbRequest(const ipmbHeader *ipmbBuffer, size_t bufferLength)
126{
127 address = ipmbBuffer->Header.Req.address;
128 netFn = ipmbNetFnGet(ipmbBuffer->Header.Req.rsNetFnLUN);
129 rsLun = ipmbLunFromNetFnLunGet(ipmbBuffer->Header.Req.rsNetFnLUN);
130 rqSA = ipmbBuffer->Header.Req.rqSA;
131 seq = ipmbSeqGet(ipmbBuffer->Header.Req.rqSeqLUN);
132 rqLun = ipmbLunFromSeqLunGet(ipmbBuffer->Header.Req.rqSeqLUN);
133 cmd = ipmbBuffer->Header.Req.cmd;
134
135 size_t dataLength =
136 bufferLength - (ipmbConnectionHeaderLength +
137 ipmbRequestDataHeaderLength + ipmbChecksumSize);
138
139 if (dataLength > 0)
140 {
141 data.insert(data.end(), ipmbBuffer->Header.Req.data,
142 &ipmbBuffer->Header.Req.data[dataLength]);
143 }
144}
145
146IpmbResponse::IpmbResponse(uint8_t address, uint8_t netFn, uint8_t rqLun,
147 uint8_t rsSA, uint8_t seq, uint8_t rsLun,
148 uint8_t cmd, uint8_t completionCode,
149 std::vector<uint8_t> &inputData) :
150 address(address),
151 netFn(netFn), rqLun(rqLun), rsSA(rsSA), seq(seq), rsLun(rsLun), cmd(cmd),
152 completionCode(completionCode)
153{
154 data.reserve(ipmbMaxDataSize);
155
156 if (inputData.size() > 0)
157 {
158 data = std::move(inputData);
159 }
160}
161
162void IpmbResponse::ipmbToi2cConstruct(uint8_t *buffer, size_t *bufferLength)
163{
164 ipmbHeader *ipmbBuffer = (ipmbHeader *)buffer;
165
166 ipmbBuffer->Header.Resp.address = address;
167 ipmbBuffer->Header.Resp.rqNetFnLUN = ipmbNetFnLunSet(netFn, rqLun);
168 ipmbBuffer->Header.Resp.rsSA = rsSA;
169 ipmbBuffer->Header.Resp.rsSeqLUN = ipmbSeqLunSet(seq, rsLun);
170 ipmbBuffer->Header.Resp.cmd = cmd;
171 ipmbBuffer->Header.Resp.completionCode = completionCode;
172
173 ipmbBuffer->Header.Resp.checksum1 = ipmbChecksumCompute(
174 buffer, ipmbConnectionHeaderLength - ipmbChecksumSize);
175
176 if (data.size() > 0)
177 {
178 std::copy(
179 data.begin(), data.end(),
180 &buffer[ipmbConnectionHeaderLength + ipmbResponseDataHeaderLength]);
181 }
182
183 *bufferLength = data.size() + ipmbResponseDataHeaderLength +
184 ipmbConnectionHeaderLength + ipmbChecksumSize;
185
186 buffer[*bufferLength - ipmbChecksumSize] =
187 ipmbChecksumCompute(&buffer[ipmbChecksum2StartOffset],
188 (ipmbResponseDataHeaderLength + data.size()));
189}
190
191void IpmbRequest::prepareRequest(sdbusplus::message::message &mesg)
192{
193 mesg.append(ipmbMeChannelNum, netFn, rqLun, cmd, data);
194}
195
Richard Marian Thomaiyare646a252019-11-20 22:54:03 +0530196static constexpr unsigned int makeCmdKey(unsigned int netFn, unsigned int cmd)
197{
198 return (netFn << 8) | cmd;
199}
200
201static constexpr bool isMeCmdAllowed(uint8_t netFn, uint8_t cmd)
202{
203 constexpr uint8_t netFnMeOEM = 0x2E;
204 constexpr uint8_t cmdMeOemSendRawPeci = 0x40;
205 constexpr uint8_t cmdMeOemAggSendRawPeci = 0x41;
206 constexpr uint8_t cmdMeOemCpuPkgConfWrite = 0x43;
207 constexpr uint8_t cmdMeOemCpuPciConfWrite = 0x45;
208 constexpr uint8_t cmdMeOemReadMemSmbus = 0x47;
209 constexpr uint8_t cmdMeOemWriteMemSmbus = 0x48;
210 constexpr uint8_t cmdMeOemSlotIpmb = 0x51;
211 constexpr uint8_t cmdMeOemSlotI2cMasterWriteRead = 0x52;
212 constexpr uint8_t cmdMeOemSendRawPmbus = 0xD9;
213 constexpr uint8_t cmdMeOemUnlockMeRegion = 0xE7;
214 constexpr uint8_t cmdMeOemAggSendRawPmbus = 0xEC;
215
216 switch (makeCmdKey(netFn, cmd))
217 {
218 // Restrict ME Master write command
219 case makeCmdKey(ipmi::netFnApp, ipmi::app::cmdMasterWriteRead):
220 // Restrict ME OEM commands
221 case makeCmdKey(netFnMeOEM, cmdMeOemSendRawPeci):
222 case makeCmdKey(netFnMeOEM, cmdMeOemAggSendRawPeci):
223 case makeCmdKey(netFnMeOEM, cmdMeOemCpuPkgConfWrite):
224 case makeCmdKey(netFnMeOEM, cmdMeOemCpuPciConfWrite):
225 case makeCmdKey(netFnMeOEM, cmdMeOemReadMemSmbus):
226 case makeCmdKey(netFnMeOEM, cmdMeOemWriteMemSmbus):
227 case makeCmdKey(netFnMeOEM, cmdMeOemSlotIpmb):
228 case makeCmdKey(netFnMeOEM, cmdMeOemSlotI2cMasterWriteRead):
229 case makeCmdKey(netFnMeOEM, cmdMeOemSendRawPmbus):
230 case makeCmdKey(netFnMeOEM, cmdMeOemUnlockMeRegion):
231 case makeCmdKey(netFnMeOEM, cmdMeOemAggSendRawPmbus):
232 return false;
233 default:
234 return true;
235 }
236}
237
Vernon Mauerya3702c12019-05-22 13:20:59 -0700238ipmi_return_codes Bridging::handleIpmbChannel(sSendMessageReq *sendMsgReq,
239 ipmi_response_t response,
240 ipmi_data_len_t dataLen)
241{
242 if ((*dataLen < (sizeof(sSendMessageReq) + ipmbMinFrameLength)) ||
243 (*dataLen > (sizeof(sSendMessageReq) + ipmbMaxFrameLength)))
244 {
245 *dataLen = 0;
246 return IPMI_CC_REQ_DATA_LEN_INVALID;
247 }
248
249 auto sendMsgReqData = reinterpret_cast<ipmbHeader *>(sendMsgReq->data);
250
251 // TODO: check privilege lvl. Bridging to ME requires Administrator lvl
252
253 // allow bridging to ME only
254 if (sendMsgReqData->Header.Req.address != ipmbMeSlaveAddress)
255 {
256 phosphor::logging::log<phosphor::logging::level::INFO>(
257 "handleIpmbChannel, IPMB address invalid");
258 *dataLen = 0;
259 return IPMI_CC_PARM_OUT_OF_RANGE;
260 }
261
Richard Marian Thomaiyare646a252019-11-20 22:54:03 +0530262 constexpr uint8_t shiftLUN = 2;
263 if (!isMeCmdAllowed((sendMsgReqData->Header.Req.rsNetFnLUN >> shiftLUN),
264 sendMsgReqData->Header.Req.cmd))
265 {
266 return IPMI_CC_INVALID_FIELD_REQUEST;
267 }
268
Vernon Mauerya3702c12019-05-22 13:20:59 -0700269 // check allowed modes
270 if (sendMsgReq->modeGet() != modeNoTracking &&
271 sendMsgReq->modeGet() != modeTrackRequest)
272 {
273 phosphor::logging::log<phosphor::logging::level::INFO>(
274 "handleIpmbChannel, mode not supported");
275 *dataLen = 0;
276 return IPMI_CC_PARM_OUT_OF_RANGE;
277 }
278
279 // check if request contains valid IPMB frame
280 if (!isFrameValid(sendMsgReqData, (*dataLen - sizeof(sSendMessageReq))))
281 {
282 phosphor::logging::log<phosphor::logging::level::INFO>(
283 "handleIpmbChannel, IPMB frame invalid");
284 *dataLen = 0;
285 return IPMI_CC_PARM_OUT_OF_RANGE;
286 }
287
288 auto ipmbRequest =
289 IpmbRequest(sendMsgReqData, (*dataLen - sizeof(sSendMessageReq)));
290
291 std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>
292 ipmbResponse;
293
294 // send request to IPMB
295 try
296 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700297 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Vernon Mauerya3702c12019-05-22 13:20:59 -0700298 auto mesg =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700299 dbus->new_method_call(ipmbBus, ipmbObj, ipmbIntf, "sendRequest");
Vernon Mauerya3702c12019-05-22 13:20:59 -0700300 ipmbRequest.prepareRequest(mesg);
Vernon Mauery15419dd2019-05-24 09:40:30 -0700301 auto ret = dbus->call(mesg);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700302 ret.read(ipmbResponse);
303 }
304 catch (sdbusplus::exception::SdBusError &e)
305 {
306 phosphor::logging::log<phosphor::logging::level::ERR>(
307 "handleIpmbChannel, dbus call exception");
308 *dataLen = 0;
309 return IPMI_CC_UNSPECIFIED_ERROR;
310 }
311
312 std::vector<uint8_t> dataReceived(0);
313 int status = -1;
314 uint8_t netFn = 0, lun = 0, cmd = 0, cc = 0;
315
316 std::tie(status, netFn, lun, cmd, cc, dataReceived) = ipmbResponse;
317
318 auto respReceived =
319 IpmbResponse(ipmbRequest.rqSA, netFn, lun, ipmbRequest.address,
320 ipmbRequest.seq, lun, cmd, cc, dataReceived);
321
322 // check IPMB layer status
323 if (status)
324 {
325 phosphor::logging::log<phosphor::logging::level::WARNING>(
326 "handleIpmbChannel, ipmb returned non zero status");
327 *dataLen = 0;
328 return IPMI_CC_RESPONSE_ERROR;
329 }
330
331 auto sendMsgRes = reinterpret_cast<uint8_t *>(response);
332
333 switch (sendMsgReq->modeGet())
334 {
335 case modeNoTracking:
336 if (responseQueue.size() == responseQueueMaxSize)
337 {
338 *dataLen = 0;
339 return IPMI_CC_BUSY;
340 }
341 responseQueue.insert(responseQueue.end(), std::move(respReceived));
342 *dataLen = 0;
343 return IPMI_CC_OK;
344
345 break;
346 case modeTrackRequest:
347 respReceived.ipmbToi2cConstruct(sendMsgRes, dataLen);
348 return IPMI_CC_OK;
349
350 break;
351 default:
352 phosphor::logging::log<phosphor::logging::level::INFO>(
353 "handleIpmbChannel, mode not supported");
354 *dataLen = 0;
355 return IPMI_CC_PARM_OUT_OF_RANGE;
356 }
357
358 *dataLen = 0;
359 return IPMI_CC_UNSPECIFIED_ERROR;
360}
361
362ipmi_return_codes Bridging::sendMessageHandler(ipmi_request_t request,
363 ipmi_response_t response,
364 ipmi_data_len_t dataLen)
365{
366 ipmi_return_codes retCode = IPMI_CC_OK;
367
368 if (*dataLen < sizeof(sSendMessageReq))
369 {
370 *dataLen = 0;
371 return IPMI_CC_REQ_DATA_LEN_INVALID;
372 }
373
374 auto sendMsgReq = reinterpret_cast<sSendMessageReq *>(request);
375
376 // check message fields:
377 // encryption not supported
378 if (sendMsgReq->encryptionGet() != 0)
379 {
380 phosphor::logging::log<phosphor::logging::level::INFO>(
381 "sendMessageHandler, encryption not supported");
382 *dataLen = 0;
383 return IPMI_CC_PARM_OUT_OF_RANGE;
384 }
385
386 // authentication not supported
387 if (sendMsgReq->authenticationGet() != 0)
388 {
389 phosphor::logging::log<phosphor::logging::level::INFO>(
390 "sendMessageHandler, authentication not supported");
391 *dataLen = 0;
392 return IPMI_CC_PARM_OUT_OF_RANGE;
393 }
394
395 switch (sendMsgReq->channelNumGet())
396 {
397 // we only handle ipmb for now
398 case targetChannelIpmb:
399 case targetChannelOtherLan:
400 retCode = handleIpmbChannel(sendMsgReq, response, dataLen);
401 break;
402 // fall through to default
403 case targetChannelIcmb10:
404 case targetChannelIcmb09:
405 case targetChannelLan:
406 case targetChannelSerialModem:
407 case targetChannelPciSmbus:
408 case targetChannelSmbus10:
409 case targetChannelSmbus20:
410 case targetChannelSystemInterface:
411 default:
412 phosphor::logging::log<phosphor::logging::level::INFO>(
413 "sendMessageHandler, TargetChannel invalid");
414 *dataLen = 0;
415 return IPMI_CC_PARM_OUT_OF_RANGE;
416 }
417
418 return retCode;
419}
420
421ipmi_return_codes Bridging::getMessageHandler(ipmi_request_t request,
422 ipmi_response_t response,
423 ipmi_data_len_t dataLen)
424{
425 if (*dataLen != 0)
426 {
427 *dataLen = 0;
428 return IPMI_CC_REQ_DATA_LEN_INVALID;
429 }
430
431 auto getMsgRes = reinterpret_cast<sGetMessageRes *>(response);
432 auto getMsgResData = static_cast<uint8_t *>(getMsgRes->data);
433
434 std::memset(getMsgRes, 0, sizeof(sGetMessageRes));
435
436 auto respQueueItem = responseQueue.begin();
437
438 if (respQueueItem == responseQueue.end())
439 {
440 phosphor::logging::log<phosphor::logging::level::INFO>(
441 "getMessageHandler, no data available");
442 *dataLen = 0;
443 return ipmiGetMessageCmdDataNotAvailable;
444 }
445
446 // set message fields
447 getMsgRes->privilegeLvlSet(SYSTEM_INTERFACE);
448 getMsgRes->channelNumSet(targetChannelSystemInterface);
449
450 // construct response
451 respQueueItem->ipmbToi2cConstruct(getMsgResData, dataLen);
452 responseQueue.erase(respQueueItem);
453
454 *dataLen = *dataLen + sizeof(sGetMessageRes);
455 return IPMI_CC_OK;
456}
457
Vernon Mauerya3702c12019-05-22 13:20:59 -0700458ipmi_ret_t ipmiAppSendMessage(ipmi_netfn_t netFn, ipmi_cmd_t cmd,
459 ipmi_request_t request, ipmi_response_t response,
460 ipmi_data_len_t dataLen, ipmi_context_t context)
461{
462 ipmi_ret_t retCode = IPMI_CC_OK;
463 retCode = bridging.sendMessageHandler(request, response, dataLen);
464
465 return retCode;
466}
467
468ipmi_ret_t ipmiAppGetMessage(ipmi_netfn_t netFn, ipmi_cmd_t cmd,
469 ipmi_request_t request, ipmi_response_t response,
470 ipmi_data_len_t dataLen, ipmi_context_t context)
471{
472 ipmi_ret_t retCode = IPMI_CC_OK;
473 retCode = bridging.getMessageHandler(request, response, dataLen);
474
475 return retCode;
476}
477
Yong Lic3580e92019-08-15 14:36:47 +0800478std::size_t Bridging::getResponseQueueSize()
Vernon Mauerya3702c12019-05-22 13:20:59 -0700479{
Yong Lic3580e92019-08-15 14:36:47 +0800480 return responseQueue.size();
481}
Vernon Mauerya3702c12019-05-22 13:20:59 -0700482
Yong Lic3580e92019-08-15 14:36:47 +0800483/**
484@brief This command is used to retrive present message available states.
485
486@return IPMI completion code plus Flags as response data on success.
487**/
488ipmi::RspType<std::bitset<8>> ipmiAppGetMessageFlags()
489{
490 std::bitset<8> getMsgFlagsRes;
491
jayaprakash Mutyala5ba46872019-11-20 00:02:48 +0000492 // set event message buffer bit
493 if (!eventMessageBufferFlag)
494 {
495 getMsgFlagsRes.set(getMsgFlagEventMessageBit);
496 }
497 else
498 {
499 getMsgFlagsRes.reset(getMsgFlagEventMessageBit);
500 }
Yong Lic3580e92019-08-15 14:36:47 +0800501
502 // set message fields
503 if (bridging.getResponseQueueSize() > 0)
504 {
505 getMsgFlagsRes.set(getMsgFlagReceiveMessageBit);
506 }
507 else
508 {
509 getMsgFlagsRes.reset(getMsgFlagReceiveMessageBit);
510 }
511
512 try
513 {
514 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
515 ipmi::Value variant = ipmi::getDbusProperty(
516 *dbus, wdtService, wdtObjPath, wdtInterface, wdtInterruptFlagProp);
517 if (std::get<bool>(variant))
518 {
519 getMsgFlagsRes.set(getMsgFlagWatchdogPreTimeOutBit);
520 }
521 }
522 catch (sdbusplus::exception::SdBusError &e)
523 {
524 phosphor::logging::log<phosphor::logging::level::ERR>(
525 "ipmiAppGetMessageFlags, dbus call exception");
526 return ipmi::responseUnspecifiedError();
527 }
528
529 return ipmi::responseSuccess(getMsgFlagsRes);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700530}
531
jayaprakash Mutyala405f54a2019-10-18 18:23:27 +0000532/** @brief This command is used to flush unread data from the receive
533 * message queue
534 * @param receiveMessage - clear receive message queue
535 * @param eventMsgBufFull - clear event message buffer full
536 * @param reserved2 - reserved bit
537 * @param watchdogTimeout - clear watchdog pre-timeout interrupt flag
538 * @param reserved1 - reserved bit
539 * @param oem0 - clear OEM 0 data
540 * @param oem1 - clear OEM 1 data
541 * @param oem2 - clear OEM 2 data
542
543 * @return IPMI completion code on success
544 */
545ipmi::RspType<> ipmiAppClearMessageFlags(bool receiveMessage,
546 bool eventMsgBufFull, bool reserved2,
547 bool watchdogTimeout, bool reserved1,
548 bool oem0, bool oem1, bool oem2)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700549{
jayaprakash Mutyala405f54a2019-10-18 18:23:27 +0000550 if (reserved1 || reserved2)
551 {
552 return ipmi::responseInvalidFieldRequest();
553 }
Vernon Mauerya3702c12019-05-22 13:20:59 -0700554
jayaprakash Mutyala405f54a2019-10-18 18:23:27 +0000555 if (receiveMessage)
556 {
557 bridging.clearResponseQueue();
558 }
jayaprakash Mutyala5ba46872019-11-20 00:02:48 +0000559
560 if (eventMessageBufferFlag != true && eventMsgBufFull == true)
561 {
562 eventMessageBufferFlag = true;
563 }
564
jayaprakash Mutyala43539cb2019-11-25 12:37:27 +0000565 try
566 {
567 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
568 ipmi::setDbusProperty(*dbus, wdtService, wdtObjPath, wdtInterface,
569 wdtInterruptFlagProp, false);
570 }
571 catch (const sdbusplus::exception::SdBusError &e)
572 {
573 phosphor::logging::log<phosphor::logging::level::ERR>(
574 "ipmiAppClearMessageFlags: can't Clear/Set "
575 "PreTimeoutInterruptOccurFlag");
576 return ipmi::responseUnspecifiedError();
577 }
578
jayaprakash Mutyala405f54a2019-10-18 18:23:27 +0000579 return ipmi::responseSuccess();
Vernon Mauerya3702c12019-05-22 13:20:59 -0700580}
581
jayaprakash Mutyala5ba46872019-11-20 00:02:48 +0000582using systemEventType = std::tuple<
583 uint16_t, // Generator ID
584 uint32_t, // Timestamp
585 uint8_t, // Sensor Type
586 uint8_t, // EvM Rev
587 uint8_t, // Sensor Number
588 uint7_t, // Event Type
589 bool, // Event Direction
590 std::array<uint8_t, intel_oem::ipmi::sel::systemEventSize>>; // Event Data
591using oemTsEventType = std::tuple<
592 uint32_t, // Timestamp
593 std::array<uint8_t, intel_oem::ipmi::sel::oemTsEventSize>>; // Event Data
594using oemEventType =
595 std::array<uint8_t, intel_oem::ipmi::sel::oemEventSize>; // Event Data
596
597/** @brief implements of Read event message buffer command
598 *
599 * @returns IPMI completion code plus response data
600 * - recordID - SEL Record ID
601 * - recordType - Record Type
602 * - generatorID - Generator ID
603 * - timeStamp - Timestamp
604 * - sensorType - Sensor Type
605 * - eventMsgFormatRev - Event Message format version
606 * - sensorNumber - Sensor Number
607 * - eventType - Event Type
608 * - eventDir - Event Direction
609 * - eventData - Event Data field
610 */
611ipmi::RspType<uint16_t, // Record ID
612 uint8_t, // Record Type
613 std::variant<systemEventType, oemTsEventType,
614 oemEventType>> // Record Content
615 ipmiAppReadEventMessageBuffer()
616{
617 uint16_t recordId =
618 static_cast<uint16_t>(0x5555); // recordId: 0x55 << 8 | 0x55
619 uint16_t generatorId =
620 static_cast<uint16_t>(0xA741); // generatorId: 0xA7 << 8 | 0x41
621 constexpr uint8_t recordType = 0xC0;
622 constexpr uint8_t eventMsgFormatRev = 0x3A;
623 constexpr uint8_t sensorNumber = 0xFF;
624
625 // TODO need to be implemented.
626 std::array<uint8_t, intel_oem::ipmi::sel::systemEventSize> eventData{};
627 // All '0xFF' since unused.
628 eventData.fill(0xFF);
629
630 // Set the event message buffer flag
631 eventMessageBufferFlag = true;
632
633 return ipmi::responseSuccess(
634 recordId, recordType,
635 systemEventType{generatorId, 0, 0, eventMsgFormatRev, sensorNumber,
636 static_cast<uint7_t>(0), false, eventData});
637}
638
Vernon Mauerya3702c12019-05-22 13:20:59 -0700639static void register_bridging_functions() __attribute__((constructor));
640static void register_bridging_functions()
641{
jayaprakash Mutyala405f54a2019-10-18 18:23:27 +0000642 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnApp,
643 ipmi::app::cmdClearMessageFlags,
644 ipmi::Privilege::User, ipmiAppClearMessageFlags);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700645
Yong Lic3580e92019-08-15 14:36:47 +0800646 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnApp,
647 ipmi::app::cmdGetMessageFlags, ipmi::Privilege::User,
648 ipmiAppGetMessageFlags);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700649
650 ipmi_register_callback(NETFUN_APP,
651 Bridging::IpmiAppBridgingCmds::ipmiCmdGetMessage,
652 NULL, ipmiAppGetMessage, PRIVILEGE_USER);
653
654 ipmi_register_callback(NETFUN_APP,
655 Bridging::IpmiAppBridgingCmds::ipmiCmdSendMessage,
656 NULL, ipmiAppSendMessage, PRIVILEGE_USER);
657
jayaprakash Mutyala5ba46872019-11-20 00:02:48 +0000658 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnApp,
659 ipmi::app::cmdReadEventMessageBuffer,
660 ipmi::Privilege::User, ipmiAppReadEventMessageBuffer);
661
Vernon Mauerya3702c12019-05-22 13:20:59 -0700662 return;
663}