1 /* 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 17 #include <bridgingcommands.hpp> 18 #include <ipmid/api.hpp> 19 #include <ipmid/utils.hpp> 20 #include <manufacturingcommands.hpp> 21 #include <phosphor-logging/log.hpp> 22 #include <sdbusplus/bus.hpp> 23 #include <sdbusplus/bus/match.hpp> 24 #include <sdbusplus/message.hpp> 25 #include <storagecommands.hpp> 26 27 #include <bitset> 28 #include <cstring> 29 #include <vector> 30 31 static constexpr const char* wdtService = "xyz.openbmc_project.Watchdog"; 32 static constexpr const char* wdtInterface = 33 "xyz.openbmc_project.State.Watchdog"; 34 static constexpr const char* wdtObjPath = "/xyz/openbmc_project/watchdog/host0"; 35 static constexpr const char* wdtInterruptFlagProp = 36 "PreTimeoutInterruptOccurFlag"; 37 38 static constexpr const char* ipmbBus = "xyz.openbmc_project.Ipmi.Channel.Ipmb"; 39 static constexpr const char* ipmbObj = "/xyz/openbmc_project/Ipmi/Channel/Ipmb"; 40 static constexpr const char* ipmbIntf = "org.openbmc.Ipmb"; 41 42 static Bridging bridging; 43 static bool eventMessageBufferFlag = false; 44 45 void Bridging::clearResponseQueue() 46 { 47 responseQueue.clear(); 48 } 49 50 /** 51 * @brief utils for checksum 52 */ 53 static bool ipmbChecksumValidate(const uint8_t* data, uint8_t length) 54 { 55 if (data == nullptr) 56 { 57 return false; 58 } 59 60 uint8_t checksum = 0; 61 62 for (uint8_t idx = 0; idx < length; idx++) 63 { 64 checksum += data[idx]; 65 } 66 67 if (0 == checksum) 68 { 69 return true; 70 } 71 72 return false; 73 } 74 75 static uint8_t ipmbChecksumCompute(uint8_t* data, uint8_t length) 76 { 77 if (data == nullptr) 78 { 79 return 0; 80 } 81 82 uint8_t checksum = 0; 83 84 for (uint8_t idx = 0; idx < length; idx++) 85 { 86 checksum += data[idx]; 87 } 88 89 checksum = (~checksum) + 1; 90 return checksum; 91 } 92 93 static inline bool 94 ipmbConnectionHeaderChecksumValidate(const ipmbHeader* ipmbHeader) 95 { 96 return ipmbChecksumValidate(reinterpret_cast<const uint8_t*>(ipmbHeader), 97 ipmbConnectionHeaderLength); 98 } 99 100 static inline bool ipmbDataChecksumValidate(const ipmbHeader* ipmbHeader, 101 uint8_t length) 102 { 103 return ipmbChecksumValidate((reinterpret_cast<const uint8_t*>(ipmbHeader) + 104 ipmbConnectionHeaderLength), 105 (length - ipmbConnectionHeaderLength)); 106 } 107 108 static bool isFrameValid(const ipmbHeader* frame, uint8_t length) 109 { 110 if ((length < ipmbMinFrameLength) || (length > ipmbMaxFrameLength)) 111 { 112 return false; 113 } 114 115 if (false == ipmbConnectionHeaderChecksumValidate(frame)) 116 { 117 return false; 118 } 119 120 if (false == ipmbDataChecksumValidate(frame, length)) 121 { 122 return false; 123 } 124 125 return true; 126 } 127 128 IpmbRequest::IpmbRequest(const ipmbHeader* ipmbBuffer, size_t bufferLength) 129 { 130 address = ipmbBuffer->Header.Req.address; 131 netFn = ipmbNetFnGet(ipmbBuffer->Header.Req.rsNetFnLUN); 132 rsLun = ipmbLunFromNetFnLunGet(ipmbBuffer->Header.Req.rsNetFnLUN); 133 rqSA = ipmbBuffer->Header.Req.rqSA; 134 seq = ipmbSeqGet(ipmbBuffer->Header.Req.rqSeqLUN); 135 rqLun = ipmbLunFromSeqLunGet(ipmbBuffer->Header.Req.rqSeqLUN); 136 cmd = ipmbBuffer->Header.Req.cmd; 137 138 size_t dataLength = 139 bufferLength - (ipmbConnectionHeaderLength + 140 ipmbRequestDataHeaderLength + ipmbChecksumSize); 141 142 if (dataLength > 0) 143 { 144 data.insert(data.end(), ipmbBuffer->Header.Req.data, 145 &ipmbBuffer->Header.Req.data[dataLength]); 146 } 147 } 148 149 IpmbResponse::IpmbResponse(uint8_t address, uint8_t netFn, uint8_t rqLun, 150 uint8_t rsSA, uint8_t seq, uint8_t rsLun, 151 uint8_t cmd, uint8_t completionCode, 152 std::vector<uint8_t>& inputData) : 153 address(address), 154 netFn(netFn), rqLun(rqLun), rsSA(rsSA), seq(seq), rsLun(rsLun), cmd(cmd), 155 completionCode(completionCode) 156 { 157 data.reserve(ipmbMaxDataSize); 158 159 if (inputData.size() > 0) 160 { 161 data = std::move(inputData); 162 } 163 } 164 165 void IpmbResponse::ipmbToi2cConstruct(uint8_t* buffer, size_t* bufferLength) 166 { 167 ipmbHeader* ipmbBuffer = (ipmbHeader*)buffer; 168 169 ipmbBuffer->Header.Resp.address = address; 170 ipmbBuffer->Header.Resp.rqNetFnLUN = ipmbNetFnLunSet(netFn, rqLun); 171 ipmbBuffer->Header.Resp.rsSA = rsSA; 172 ipmbBuffer->Header.Resp.rsSeqLUN = ipmbSeqLunSet(seq, rsLun); 173 ipmbBuffer->Header.Resp.cmd = cmd; 174 ipmbBuffer->Header.Resp.completionCode = completionCode; 175 176 ipmbBuffer->Header.Resp.checksum1 = ipmbChecksumCompute( 177 buffer, ipmbConnectionHeaderLength - ipmbChecksumSize); 178 179 if (data.size() > 0) 180 { 181 std::copy( 182 data.begin(), data.end(), 183 &buffer[ipmbConnectionHeaderLength + ipmbResponseDataHeaderLength]); 184 } 185 186 *bufferLength = data.size() + ipmbResponseDataHeaderLength + 187 ipmbConnectionHeaderLength + ipmbChecksumSize; 188 189 buffer[*bufferLength - ipmbChecksumSize] = 190 ipmbChecksumCompute(&buffer[ipmbChecksum2StartOffset], 191 (ipmbResponseDataHeaderLength + data.size())); 192 } 193 194 void IpmbRequest::prepareRequest(sdbusplus::message::message& mesg) 195 { 196 mesg.append(ipmbMeChannelNum, netFn, rqLun, cmd, data); 197 } 198 199 static constexpr unsigned int makeCmdKey(unsigned int netFn, unsigned int cmd) 200 { 201 return (netFn << 8) | cmd; 202 } 203 204 static constexpr bool isMeCmdAllowed(uint8_t netFn, uint8_t cmd) 205 { 206 constexpr uint8_t netFnMeOEM = 0x2E; 207 constexpr uint8_t netFnMeOEMGeneral = 0x3E; 208 constexpr uint8_t cmdMeOemSendRawPeci = 0x40; 209 constexpr uint8_t cmdMeOemAggSendRawPeci = 0x41; 210 constexpr uint8_t cmdMeOemCpuPkgConfWrite = 0x43; 211 constexpr uint8_t cmdMeOemCpuPciConfWrite = 0x45; 212 constexpr uint8_t cmdMeOemReadMemSmbus = 0x47; 213 constexpr uint8_t cmdMeOemWriteMemSmbus = 0x48; 214 constexpr uint8_t cmdMeOemSlotIpmb = 0x51; 215 constexpr uint8_t cmdMeOemSlotI2cMasterWriteRead = 0x52; 216 constexpr uint8_t cmdMeOemSendRawPmbus = 0xD9; 217 constexpr uint8_t cmdMeOemUnlockMeRegion = 0xE7; 218 constexpr uint8_t cmdMeOemAggSendRawPmbus = 0xEC; 219 220 switch (makeCmdKey(netFn, cmd)) 221 { 222 // Restrict ME Master write command 223 case makeCmdKey(ipmi::netFnApp, ipmi::app::cmdMasterWriteRead): 224 // Restrict ME OEM commands 225 case makeCmdKey(netFnMeOEM, cmdMeOemSendRawPeci): 226 case makeCmdKey(netFnMeOEM, cmdMeOemAggSendRawPeci): 227 case makeCmdKey(netFnMeOEM, cmdMeOemCpuPkgConfWrite): 228 case makeCmdKey(netFnMeOEM, cmdMeOemCpuPciConfWrite): 229 case makeCmdKey(netFnMeOEM, cmdMeOemReadMemSmbus): 230 case makeCmdKey(netFnMeOEM, cmdMeOemWriteMemSmbus): 231 case makeCmdKey(netFnMeOEMGeneral, cmdMeOemSlotIpmb): 232 case makeCmdKey(netFnMeOEMGeneral, cmdMeOemSlotI2cMasterWriteRead): 233 case makeCmdKey(netFnMeOEM, cmdMeOemSendRawPmbus): 234 case makeCmdKey(netFnMeOEM, cmdMeOemUnlockMeRegion): 235 case makeCmdKey(netFnMeOEM, cmdMeOemAggSendRawPmbus): 236 return false; 237 default: 238 return true; 239 } 240 } 241 242 ipmi::Cc Bridging::handleIpmbChannel(ipmi::Context::ptr ctx, 243 const uint8_t tracking, 244 const std::vector<uint8_t>& msgData, 245 std::vector<uint8_t>& rspData) 246 { 247 ipmi::Manufacturing mtm; 248 249 size_t msgLen = msgData.size(); 250 if ((msgLen < ipmbMinFrameLength) || (msgLen > ipmbMaxFrameLength)) 251 { 252 phosphor::logging::log<phosphor::logging::level::INFO>( 253 "handleIpmbChannel, IPMB data length is invalid"); 254 return ipmi::ccReqDataLenInvalid; 255 } 256 257 // Bridging to ME requires Administrator lvl 258 if ((ctx->priv) != ipmi::Privilege::Admin) 259 { 260 return ipmi::ccInsufficientPrivilege; 261 } 262 263 auto sendMsgReqData = reinterpret_cast<const ipmbHeader*>(msgData.data()); 264 265 // allow bridging to ME only 266 if (sendMsgReqData->Header.Req.address != ipmbMeSlaveAddress) 267 { 268 phosphor::logging::log<phosphor::logging::level::INFO>( 269 "handleIpmbChannel, IPMB address invalid"); 270 return ipmi::ccParmOutOfRange; 271 } 272 273 constexpr uint8_t shiftLUN = 2; 274 if (mtm.getMfgMode() == ipmi::SpecialMode::none) 275 { 276 if (!isMeCmdAllowed((sendMsgReqData->Header.Req.rsNetFnLUN >> shiftLUN), 277 sendMsgReqData->Header.Req.cmd)) 278 { 279 constexpr ipmi::Cc ccCmdNotSupportedInPresentState = 0xD5; 280 return ccCmdNotSupportedInPresentState; 281 } 282 } 283 284 // check allowed modes 285 if (tracking != modeNoTracking && tracking != modeTrackRequest) 286 { 287 phosphor::logging::log<phosphor::logging::level::INFO>( 288 "handleIpmbChannel, mode not supported"); 289 return ipmi::ccParmOutOfRange; 290 } 291 292 // check if request contains valid IPMB frame 293 if (!isFrameValid(sendMsgReqData, msgLen)) 294 { 295 phosphor::logging::log<phosphor::logging::level::INFO>( 296 "handleIpmbChannel, IPMB frame invalid"); 297 return ipmi::ccParmOutOfRange; 298 } 299 300 auto ipmbRequest = IpmbRequest(sendMsgReqData, msgLen); 301 302 typedef std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, 303 std::vector<uint8_t>> 304 IPMBResponse; 305 306 // send request to IPMB 307 boost::system::error_code ec; 308 auto ipmbResponse = ctx->bus->yield_method_call<IPMBResponse>( 309 ctx->yield, ec, ipmbBus, ipmbObj, ipmbIntf, "sendRequest", 310 ipmbMeChannelNum, ipmbRequest.netFn, ipmbRequest.rqLun, ipmbRequest.cmd, 311 ipmbRequest.data); 312 if (ec) 313 { 314 phosphor::logging::log<phosphor::logging::level::ERR>( 315 "handleIpmbChannel, dbus call exception"); 316 return ipmi::ccUnspecifiedError; 317 } 318 319 std::vector<uint8_t> dataReceived(0); 320 int status = -1; 321 uint8_t netFn = 0, lun = 0, cmd = 0, cc = 0; 322 323 std::tie(status, netFn, lun, cmd, cc, dataReceived) = ipmbResponse; 324 325 auto respReceived = 326 IpmbResponse(ipmbRequest.rqSA, netFn, lun, ipmbRequest.address, 327 ipmbRequest.seq, lun, cmd, cc, dataReceived); 328 329 // check IPMB layer status 330 if (status) 331 { 332 phosphor::logging::log<phosphor::logging::level::WARNING>( 333 "handleIpmbChannel, ipmb returned non zero status"); 334 return ipmi::ccResponseError; 335 } 336 337 switch (tracking) 338 { 339 case modeNoTracking: 340 { 341 if (getResponseQueueSize() == responseQueueMaxSize) 342 { 343 return ipmi::ccBusy; 344 } 345 insertMessageInQueue(respReceived); 346 break; 347 } 348 case modeTrackRequest: 349 { 350 size_t dataLength = 0; 351 respReceived.ipmbToi2cConstruct(rspData.data(), &dataLength); 352 // resizing the rspData to its correct length 353 rspData.resize(dataLength); 354 break; 355 } 356 default: 357 { 358 phosphor::logging::log<phosphor::logging::level::INFO>( 359 "handleIpmbChannel, mode not supported"); 360 return ipmi::ccParmOutOfRange; 361 } 362 } 363 364 return ipmi::ccSuccess; 365 } 366 367 void Bridging::insertMessageInQueue(IpmbResponse msg) 368 { 369 responseQueue.insert(responseQueue.end(), std::move(msg)); 370 } 371 372 void Bridging::eraseMessageFromQueue() 373 { 374 responseQueue.erase(responseQueue.begin()); 375 } 376 377 IpmbResponse Bridging::getMessageFromQueue() 378 { 379 return responseQueue.front(); 380 } 381 382 /** 383 * @brief This command is used for bridging ipmi message between channels. 384 * @param channelNumber - channel number to send message to 385 * @param authenticationEnabled - authentication. 386 * @param encryptionEnabled - encryption 387 * @param Tracking - track request 388 * @param msg - message data 389 * 390 * @return IPMI completion code plus response data on success. 391 * - rspData - response data 392 **/ 393 ipmi::RspType<std::vector<uint8_t> // responseData 394 > 395 ipmiAppSendMessage(ipmi::Context::ptr ctx, const uint4_t channelNumber, 396 const bool authenticationEnabled, 397 const bool encryptionEnabled, const uint2_t tracking, 398 ipmi::message::Payload& msg) 399 { 400 // check message fields: 401 // encryption not supported 402 if (encryptionEnabled) 403 { 404 phosphor::logging::log<phosphor::logging::level::INFO>( 405 "ipmiAppSendMessage, encryption not supported"); 406 return ipmi::responseParmOutOfRange(); 407 } 408 409 // authentication not supported 410 if (authenticationEnabled) 411 { 412 phosphor::logging::log<phosphor::logging::level::INFO>( 413 "ipmiAppSendMessage, authentication not supported"); 414 return ipmi::responseParmOutOfRange(); 415 } 416 417 ipmi::Cc returnVal; 418 std::vector<uint8_t> rspData(ipmbMaxFrameLength); 419 size_t dataLength = 0; 420 std::vector<uint8_t> unpackMsg; 421 422 auto channelNo = static_cast<const uint8_t>(channelNumber); 423 // Get the channel number 424 switch (channelNo) 425 { 426 // we only handle ipmb for now 427 case targetChannelIpmb: 428 case targetChannelOtherLan: 429 if (msg.unpack(unpackMsg) || !msg.fullyUnpacked()) 430 { 431 return ipmi::responseReqDataLenInvalid(); 432 } 433 434 returnVal = bridging.handleIpmbChannel( 435 ctx, static_cast<const uint8_t>(tracking), unpackMsg, rspData); 436 break; 437 // fall through to default 438 case targetChannelIcmb10: 439 case targetChannelIcmb09: 440 case targetChannelLan: 441 case targetChannelSerialModem: 442 case targetChannelPciSmbus: 443 case targetChannelSmbus10: 444 case targetChannelSmbus20: 445 case targetChannelSystemInterface: 446 default: 447 phosphor::logging::log<phosphor::logging::level::INFO>( 448 "ipmiAppSendMessage, TargetChannel invalid"); 449 return ipmi::responseParmOutOfRange(); 450 } 451 if (returnVal != ipmi::ccSuccess) 452 { 453 return ipmi::response(returnVal); 454 } 455 456 return ipmi::responseSuccess(rspData); 457 } 458 459 /** 460 * @brief This command is used to Get data from the receive message queue. 461 * This command should be executed executed via system interface only. 462 * 463 * @return IPMI completion code plus response data on success. 464 * - channelNumber 465 * - messageData 466 **/ 467 468 ipmi::RspType<uint8_t, // channelNumber 469 std::vector<uint8_t> // messageData 470 > 471 ipmiAppGetMessage() 472 { 473 uint8_t channelData = 0; 474 std::vector<uint8_t> res(ipmbMaxFrameLength); 475 size_t dataLength = 0; 476 477 if (!bridging.getResponseQueueSize()) 478 { 479 constexpr ipmi::Cc ipmiGetMessageCmdDataNotAvailable = 0x80; 480 phosphor::logging::log<phosphor::logging::level::INFO>( 481 "ipmiAppGetMessage, no data available"); 482 return ipmi::response(ipmiGetMessageCmdDataNotAvailable); 483 } 484 485 // channel number set. 486 channelData |= static_cast<uint8_t>(targetChannelSystemInterface) & 0x0F; 487 488 // Priviledge level set. 489 channelData |= SYSTEM_INTERFACE & 0xF0; 490 491 // Get the first message from queue 492 auto respQueueItem = bridging.getMessageFromQueue(); 493 494 // construct response data. 495 respQueueItem.ipmbToi2cConstruct(res.data(), &dataLength); 496 497 // Remove the message from queue 498 bridging.eraseMessageFromQueue(); 499 500 // resizing the rspData to its correct length 501 res.resize(dataLength); 502 503 return ipmi::responseSuccess(channelData, res); 504 } 505 506 std::size_t Bridging::getResponseQueueSize() 507 { 508 return responseQueue.size(); 509 } 510 511 /** 512 @brief This command is used to retrive present message available states. 513 514 @return IPMI completion code plus Flags as response data on success. 515 **/ 516 ipmi::RspType<std::bitset<8>> ipmiAppGetMessageFlags() 517 { 518 std::bitset<8> getMsgFlagsRes; 519 520 // set event message buffer bit 521 if (!eventMessageBufferFlag) 522 { 523 getMsgFlagsRes.set(getMsgFlagEventMessageBit); 524 } 525 else 526 { 527 getMsgFlagsRes.reset(getMsgFlagEventMessageBit); 528 } 529 530 // set message fields 531 if (bridging.getResponseQueueSize() > 0) 532 { 533 getMsgFlagsRes.set(getMsgFlagReceiveMessageBit); 534 } 535 else 536 { 537 getMsgFlagsRes.reset(getMsgFlagReceiveMessageBit); 538 } 539 540 try 541 { 542 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 543 ipmi::Value variant = ipmi::getDbusProperty( 544 *dbus, wdtService, wdtObjPath, wdtInterface, wdtInterruptFlagProp); 545 if (std::get<bool>(variant)) 546 { 547 getMsgFlagsRes.set(getMsgFlagWatchdogPreTimeOutBit); 548 } 549 } 550 catch (sdbusplus::exception::SdBusError& e) 551 { 552 phosphor::logging::log<phosphor::logging::level::ERR>( 553 "ipmiAppGetMessageFlags, dbus call exception"); 554 return ipmi::responseUnspecifiedError(); 555 } 556 557 return ipmi::responseSuccess(getMsgFlagsRes); 558 } 559 560 /** @brief This command is used to flush unread data from the receive 561 * message queue 562 * @param receiveMessage - clear receive message queue 563 * @param eventMsgBufFull - clear event message buffer full 564 * @param reserved2 - reserved bit 565 * @param watchdogTimeout - clear watchdog pre-timeout interrupt flag 566 * @param reserved1 - reserved bit 567 * @param oem0 - clear OEM 0 data 568 * @param oem1 - clear OEM 1 data 569 * @param oem2 - clear OEM 2 data 570 571 * @return IPMI completion code on success 572 */ 573 ipmi::RspType<> ipmiAppClearMessageFlags(bool receiveMessage, 574 bool eventMsgBufFull, bool reserved2, 575 bool watchdogTimeout, bool reserved1, 576 bool oem0, bool oem1, bool oem2) 577 { 578 if (reserved1 || reserved2) 579 { 580 return ipmi::responseInvalidFieldRequest(); 581 } 582 583 if (receiveMessage) 584 { 585 bridging.clearResponseQueue(); 586 } 587 588 if (eventMessageBufferFlag != true && eventMsgBufFull == true) 589 { 590 eventMessageBufferFlag = true; 591 } 592 593 try 594 { 595 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 596 ipmi::setDbusProperty(*dbus, wdtService, wdtObjPath, wdtInterface, 597 wdtInterruptFlagProp, false); 598 } 599 catch (const sdbusplus::exception::SdBusError& e) 600 { 601 phosphor::logging::log<phosphor::logging::level::ERR>( 602 "ipmiAppClearMessageFlags: can't Clear/Set " 603 "PreTimeoutInterruptOccurFlag"); 604 return ipmi::responseUnspecifiedError(); 605 } 606 607 return ipmi::responseSuccess(); 608 } 609 610 using systemEventType = std::tuple< 611 uint16_t, // Generator ID 612 uint32_t, // Timestamp 613 uint8_t, // Sensor Type 614 uint8_t, // EvM Rev 615 uint8_t, // Sensor Number 616 uint7_t, // Event Type 617 bool, // Event Direction 618 std::array<uint8_t, intel_oem::ipmi::sel::systemEventSize>>; // Event Data 619 using oemTsEventType = std::tuple< 620 uint32_t, // Timestamp 621 std::array<uint8_t, intel_oem::ipmi::sel::oemTsEventSize>>; // Event Data 622 using oemEventType = 623 std::array<uint8_t, intel_oem::ipmi::sel::oemEventSize>; // Event Data 624 625 /** @brief implements of Read event message buffer command 626 * 627 * @returns IPMI completion code plus response data 628 * - recordID - SEL Record ID 629 * - recordType - Record Type 630 * - generatorID - Generator ID 631 * - timeStamp - Timestamp 632 * - sensorType - Sensor Type 633 * - eventMsgFormatRev - Event Message format version 634 * - sensorNumber - Sensor Number 635 * - eventType - Event Type 636 * - eventDir - Event Direction 637 * - eventData - Event Data field 638 */ 639 ipmi::RspType<uint16_t, // Record ID 640 uint8_t, // Record Type 641 std::variant<systemEventType, oemTsEventType, 642 oemEventType>> // Record Content 643 ipmiAppReadEventMessageBuffer() 644 { 645 uint16_t recordId = 646 static_cast<uint16_t>(0x5555); // recordId: 0x55 << 8 | 0x55 647 uint16_t generatorId = 648 static_cast<uint16_t>(0xA741); // generatorId: 0xA7 << 8 | 0x41 649 constexpr uint8_t recordType = 0xC0; 650 constexpr uint8_t eventMsgFormatRev = 0x3A; 651 constexpr uint8_t sensorNumber = 0xFF; 652 653 // TODO need to be implemented. 654 std::array<uint8_t, intel_oem::ipmi::sel::systemEventSize> eventData{}; 655 // All '0xFF' since unused. 656 eventData.fill(0xFF); 657 658 // Set the event message buffer flag 659 eventMessageBufferFlag = true; 660 661 return ipmi::responseSuccess( 662 recordId, recordType, 663 systemEventType{generatorId, 0, 0, eventMsgFormatRev, sensorNumber, 664 static_cast<uint7_t>(0), false, eventData}); 665 } 666 667 static void register_bridging_functions() __attribute__((constructor)); 668 static void register_bridging_functions() 669 { 670 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnApp, 671 ipmi::app::cmdClearMessageFlags, 672 ipmi::Privilege::User, ipmiAppClearMessageFlags); 673 674 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnApp, 675 ipmi::app::cmdGetMessageFlags, ipmi::Privilege::User, 676 ipmiAppGetMessageFlags); 677 678 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnApp, 679 ipmi::app::cmdGetMessage, ipmi::Privilege::User, 680 ipmiAppGetMessage); 681 682 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnApp, 683 ipmi::app::cmdSendMessage, ipmi::Privilege::User, 684 ipmiAppSendMessage); 685 686 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnApp, 687 ipmi::app::cmdReadEventMessageBuffer, 688 ipmi::Privilege::User, ipmiAppReadEventMessageBuffer); 689 690 return; 691 } 692