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 #include <user_channel/channel_layer.hpp> 27 28 #include <bitset> 29 #include <cstring> 30 #include <vector> 31 32 static constexpr const char* wdtService = "xyz.openbmc_project.Watchdog"; 33 static constexpr const char* wdtInterface = 34 "xyz.openbmc_project.State.Watchdog"; 35 static constexpr const char* wdtObjPath = "/xyz/openbmc_project/watchdog/host0"; 36 static constexpr const char* wdtInterruptFlagProp = 37 "PreTimeoutInterruptOccurFlag"; 38 39 static constexpr const char* ipmbBus = "xyz.openbmc_project.Ipmi.Channel.Ipmb"; 40 static constexpr const char* ipmbObj = "/xyz/openbmc_project/Ipmi/Channel/Ipmb"; 41 static constexpr const char* ipmbIntf = "org.openbmc.Ipmb"; 42 43 static Bridging bridging; 44 static bool eventMessageBufferFlag = false; 45 46 void Bridging::clearResponseQueue() 47 { 48 responseQueue.clear(); 49 } 50 51 /** 52 * @brief utils for checksum 53 */ 54 static bool ipmbChecksumValidate(const uint8_t* data, uint8_t length) 55 { 56 if (data == nullptr) 57 { 58 return false; 59 } 60 61 uint8_t checksum = 0; 62 63 for (uint8_t idx = 0; idx < length; idx++) 64 { 65 checksum += data[idx]; 66 } 67 68 if (0 == checksum) 69 { 70 return true; 71 } 72 73 return false; 74 } 75 76 static uint8_t ipmbChecksumCompute(uint8_t* data, uint8_t length) 77 { 78 if (data == nullptr) 79 { 80 return 0; 81 } 82 83 uint8_t checksum = 0; 84 85 for (uint8_t idx = 0; idx < length; idx++) 86 { 87 checksum += data[idx]; 88 } 89 90 checksum = (~checksum) + 1; 91 return checksum; 92 } 93 94 static inline bool 95 ipmbConnectionHeaderChecksumValidate(const ipmbHeader* ipmbHeader) 96 { 97 return ipmbChecksumValidate(reinterpret_cast<const uint8_t*>(ipmbHeader), 98 ipmbConnectionHeaderLength); 99 } 100 101 static inline bool 102 ipmbDataChecksumValidate(const ipmbHeader* ipmbHeader, size_t length) 103 { 104 return ipmbChecksumValidate((reinterpret_cast<const uint8_t*>(ipmbHeader) + 105 ipmbConnectionHeaderLength), 106 (length - ipmbConnectionHeaderLength)); 107 } 108 109 static bool isFrameValid(const ipmbHeader* frame, size_t length) 110 { 111 if ((length < ipmbMinFrameLength) || (length > ipmbMaxFrameLength)) 112 { 113 return false; 114 } 115 116 if (false == ipmbConnectionHeaderChecksumValidate(frame)) 117 { 118 return false; 119 } 120 121 if (false == ipmbDataChecksumValidate(frame, length)) 122 { 123 return false; 124 } 125 126 return true; 127 } 128 129 IpmbRequest::IpmbRequest(const ipmbHeader* ipmbBuffer, size_t bufferLength) 130 { 131 address = ipmbBuffer->Header.Req.address; 132 netFn = ipmbNetFnGet(ipmbBuffer->Header.Req.rsNetFnLUN); 133 rsLun = ipmbLunFromNetFnLunGet(ipmbBuffer->Header.Req.rsNetFnLUN); 134 rqSA = ipmbBuffer->Header.Req.rqSA; 135 seq = ipmbSeqGet(ipmbBuffer->Header.Req.rqSeqLUN); 136 rqLun = ipmbLunFromSeqLunGet(ipmbBuffer->Header.Req.rqSeqLUN); 137 cmd = ipmbBuffer->Header.Req.cmd; 138 139 size_t dataLength = 140 bufferLength - (ipmbConnectionHeaderLength + 141 ipmbRequestDataHeaderLength + ipmbChecksumSize); 142 143 if (dataLength > 0) 144 { 145 data.insert(data.end(), ipmbBuffer->Header.Req.data, 146 &ipmbBuffer->Header.Req.data[dataLength]); 147 } 148 } 149 150 IpmbResponse::IpmbResponse(uint8_t address, uint8_t netFn, uint8_t rqLun, 151 uint8_t rsSA, uint8_t seq, uint8_t rsLun, 152 uint8_t cmd, uint8_t completionCode, 153 std::vector<uint8_t>& inputData) : 154 address(address), netFn(netFn), rqLun(rqLun), rsSA(rsSA), seq(seq), 155 rsLun(rsLun), cmd(cmd), 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_t& 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 cmdMeOemSlotI2cControllerWriteRead = 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 Controller 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, cmdMeOemSlotI2cControllerWriteRead): 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( 243 ipmi::Context::ptr& ctx, const uint8_t tracking, 244 const std::vector<uint8_t>& msgData, std::vector<uint8_t>& rspData) 245 { 246 ipmi::Manufacturing mtm; 247 248 size_t msgLen = msgData.size(); 249 if ((msgLen < ipmbMinFrameLength) || (msgLen > ipmbMaxFrameLength)) 250 { 251 phosphor::logging::log<phosphor::logging::level::INFO>( 252 "handleIpmbChannel, IPMB data length is invalid"); 253 return ipmi::ccReqDataLenInvalid; 254 } 255 256 // Bridging to ME requires Administrator lvl 257 if ((ctx->priv) != ipmi::Privilege::Admin) 258 { 259 return ipmi::ccInsufficientPrivilege; 260 } 261 262 auto sendMsgReqData = reinterpret_cast<const ipmbHeader*>(msgData.data()); 263 264 // allow bridging to ME only 265 if (sendMsgReqData->Header.Req.address != ipmbMeTargetAddress) 266 { 267 phosphor::logging::log<phosphor::logging::level::INFO>( 268 "handleIpmbChannel, IPMB address invalid"); 269 return ipmi::ccParmOutOfRange; 270 } 271 272 constexpr uint8_t shiftLUN = 2; 273 if (mtm.getMfgMode() == ipmi::SpecialMode::none) 274 { 275 if (!isMeCmdAllowed((sendMsgReqData->Header.Req.rsNetFnLUN >> shiftLUN), 276 sendMsgReqData->Header.Req.cmd)) 277 { 278 constexpr ipmi::Cc ccCmdNotSupportedInPresentState = 0xD5; 279 return ccCmdNotSupportedInPresentState; 280 } 281 } 282 283 // check allowed modes 284 if (tracking != modeNoTracking && tracking != modeTrackRequest) 285 { 286 phosphor::logging::log<phosphor::logging::level::INFO>( 287 "handleIpmbChannel, mode not supported"); 288 return ipmi::ccParmOutOfRange; 289 } 290 291 // check if request contains valid IPMB frame 292 if (!isFrameValid(sendMsgReqData, msgLen)) 293 { 294 phosphor::logging::log<phosphor::logging::level::INFO>( 295 "handleIpmbChannel, IPMB frame invalid"); 296 return ipmi::ccParmOutOfRange; 297 } 298 299 auto ipmbRequest = IpmbRequest(sendMsgReqData, msgLen); 300 301 typedef std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, 302 std::vector<uint8_t>> 303 IPMBResponse; 304 305 // send request to IPMB 306 boost::system::error_code ec; 307 auto ipmbResponse = ctx->bus->yield_method_call<IPMBResponse>( 308 ctx->yield, ec, ipmbBus, ipmbObj, ipmbIntf, "sendRequest", 309 ipmbMeChannelNum, ipmbRequest.netFn, ipmbRequest.rqLun, ipmbRequest.cmd, 310 ipmbRequest.data); 311 if (ec) 312 { 313 phosphor::logging::log<phosphor::logging::level::ERR>( 314 "handleIpmbChannel, dbus call exception"); 315 return ipmi::ccUnspecifiedError; 316 } 317 318 std::vector<uint8_t> dataReceived(0); 319 int status = -1; 320 uint8_t netFn = 0, lun = 0, cmd = 0, cc = 0; 321 322 std::tie(status, netFn, lun, cmd, cc, dataReceived) = ipmbResponse; 323 324 auto respReceived = 325 IpmbResponse(ipmbRequest.rqSA, netFn, lun, ipmbRequest.address, 326 ipmbRequest.seq, lun, cmd, cc, dataReceived); 327 328 // check IPMB layer status 329 if (status) 330 { 331 phosphor::logging::log<phosphor::logging::level::WARNING>( 332 "handleIpmbChannel, ipmb returned non zero status"); 333 return ipmi::ccResponseError; 334 } 335 336 switch (tracking) 337 { 338 case modeNoTracking: 339 { 340 if (getResponseQueueSize() == responseQueueMaxSize) 341 { 342 return ipmi::ccBusy; 343 } 344 insertMessageInQueue(respReceived); 345 break; 346 } 347 case modeTrackRequest: 348 { 349 size_t dataLength = 0; 350 respReceived.ipmbToi2cConstruct(rspData.data(), &dataLength); 351 // resizing the rspData to its correct length 352 rspData.resize(dataLength); 353 break; 354 } 355 default: 356 { 357 phosphor::logging::log<phosphor::logging::level::INFO>( 358 "handleIpmbChannel, mode not supported"); 359 return ipmi::ccParmOutOfRange; 360 } 361 } 362 363 return ipmi::ccSuccess; 364 } 365 366 void Bridging::insertMessageInQueue(IpmbResponse msg) 367 { 368 responseQueue.insert(responseQueue.end(), std::move(msg)); 369 } 370 371 void Bridging::eraseMessageFromQueue() 372 { 373 responseQueue.erase(responseQueue.begin()); 374 } 375 376 IpmbResponse Bridging::getMessageFromQueue() 377 { 378 return responseQueue.front(); 379 } 380 381 /** 382 * @brief This command is used for bridging ipmi message between channels. 383 * @param channelNumber - channel number to send message to 384 * @param authenticationEnabled - authentication. 385 * @param encryptionEnabled - encryption 386 * @param Tracking - track request 387 * @param msg - message data 388 * 389 * @return IPMI completion code plus response data on success. 390 * - rspData - response data 391 **/ 392 ipmi::RspType<std::vector<uint8_t> // responseData 393 > 394 ipmiAppSendMessage(ipmi::Context::ptr& ctx, const uint4_t channelNumber, 395 const bool authenticationEnabled, 396 const bool encryptionEnabled, const uint2_t tracking, 397 ipmi::message::Payload& msg) 398 { 399 // check message fields: 400 // encryption not supported 401 if (encryptionEnabled) 402 { 403 phosphor::logging::log<phosphor::logging::level::INFO>( 404 "ipmiAppSendMessage, encryption not supported"); 405 return ipmi::responseParmOutOfRange(); 406 } 407 408 // authentication not supported 409 if (authenticationEnabled) 410 { 411 phosphor::logging::log<phosphor::logging::level::INFO>( 412 "ipmiAppSendMessage, authentication not supported"); 413 return ipmi::responseParmOutOfRange(); 414 } 415 416 ipmi::Cc returnVal; 417 std::vector<uint8_t> rspData(ipmbMaxFrameLength); 418 std::vector<uint8_t> unpackMsg; 419 420 auto channelNo = static_cast<uint8_t>(channelNumber); 421 // Get the channel number 422 switch (channelNo) 423 { 424 // we only handle ipmb for now 425 case targetChannelIpmb: 426 case targetChannelOtherLan: 427 if (msg.unpack(unpackMsg) || !msg.fullyUnpacked()) 428 { 429 return ipmi::responseReqDataLenInvalid(); 430 } 431 432 returnVal = bridging.handleIpmbChannel( 433 ctx, static_cast<uint8_t>(tracking), unpackMsg, rspData); 434 break; 435 // fall through to default 436 case targetChannelIcmb10: 437 case targetChannelIcmb09: 438 case targetChannelLan: 439 case targetChannelSerialModem: 440 case targetChannelPciSmbus: 441 case targetChannelSmbus10: 442 case targetChannelSmbus20: 443 case targetChannelSystemInterface: 444 default: 445 phosphor::logging::log<phosphor::logging::level::INFO>( 446 "ipmiAppSendMessage, TargetChannel invalid"); 447 return ipmi::responseParmOutOfRange(); 448 } 449 if (returnVal != ipmi::ccSuccess) 450 { 451 return ipmi::response(returnVal); 452 } 453 454 return ipmi::responseSuccess(rspData); 455 } 456 457 /** 458 * @brief This command is used to Get data from the receive message queue. 459 * This command should be executed executed via system interface only. 460 * 461 * @return IPMI completion code plus response data on success. 462 * - channelNumber 463 * - messageData 464 **/ 465 466 ipmi::RspType<uint8_t, // channelNumber 467 std::vector<uint8_t> // messageData 468 > 469 ipmiAppGetMessage(ipmi::Context::ptr& ctx) 470 { 471 ipmi::ChannelInfo chInfo; 472 473 try 474 { 475 getChannelInfo(ctx->channel, chInfo); 476 } 477 catch (const sdbusplus::exception_t& e) 478 { 479 phosphor::logging::log<phosphor::logging::level::ERR>( 480 "ipmiAppGetMessage: Failed to get Channel Info", 481 phosphor::logging::entry("MSG: %s", e.description())); 482 return ipmi::responseUnspecifiedError(); 483 } 484 if (chInfo.mediumType != 485 static_cast<uint8_t>(ipmi::EChannelMediumType::systemInterface)) 486 { 487 phosphor::logging::log<phosphor::logging::level::ERR>( 488 "ipmiAppGetMessage: Error - supported only in System(SMS) " 489 "interface"); 490 return ipmi::responseCommandNotAvailable(); 491 } 492 493 uint8_t channelData = 0; 494 std::vector<uint8_t> res(ipmbMaxFrameLength); 495 size_t dataLength = 0; 496 497 if (!bridging.getResponseQueueSize()) 498 { 499 constexpr ipmi::Cc ipmiGetMessageCmdDataNotAvailable = 0x80; 500 phosphor::logging::log<phosphor::logging::level::INFO>( 501 "ipmiAppGetMessage, no data available"); 502 return ipmi::response(ipmiGetMessageCmdDataNotAvailable); 503 } 504 505 // channel number set. 506 channelData |= static_cast<uint8_t>(targetChannelSystemInterface) & 0x0F; 507 508 // Priviledge level set. 509 channelData |= SYSTEM_INTERFACE & 0xF0; 510 511 // Get the first message from queue 512 auto respQueueItem = bridging.getMessageFromQueue(); 513 514 // construct response data. 515 respQueueItem.ipmbToi2cConstruct(res.data(), &dataLength); 516 517 // Remove the message from queue 518 bridging.eraseMessageFromQueue(); 519 520 // resizing the rspData to its correct length 521 res.resize(dataLength); 522 523 return ipmi::responseSuccess(channelData, res); 524 } 525 526 std::size_t Bridging::getResponseQueueSize() 527 { 528 return responseQueue.size(); 529 } 530 531 /** 532 @brief This command is used to retrive present message available states. 533 534 @return IPMI completion code plus Flags as response data on success. 535 **/ 536 ipmi::RspType<std::bitset<8>> ipmiAppGetMessageFlags(ipmi::Context::ptr& ctx) 537 { 538 ipmi::ChannelInfo chInfo; 539 540 try 541 { 542 getChannelInfo(ctx->channel, chInfo); 543 } 544 catch (const sdbusplus::exception_t& e) 545 { 546 phosphor::logging::log<phosphor::logging::level::ERR>( 547 "ipmiAppGetMessageFlags: Failed to get Channel Info", 548 phosphor::logging::entry("MSG: %s", e.description())); 549 return ipmi::responseUnspecifiedError(); 550 } 551 if (chInfo.mediumType != 552 static_cast<uint8_t>(ipmi::EChannelMediumType::systemInterface)) 553 { 554 phosphor::logging::log<phosphor::logging::level::ERR>( 555 "ipmiAppGetMessageFlags: Error - supported only in System(SMS) " 556 "interface"); 557 return ipmi::responseCommandNotAvailable(); 558 } 559 560 std::bitset<8> getMsgFlagsRes; 561 562 // set event message buffer bit 563 if (!eventMessageBufferFlag) 564 { 565 getMsgFlagsRes.set(getMsgFlagEventMessageBit); 566 } 567 else 568 { 569 getMsgFlagsRes.reset(getMsgFlagEventMessageBit); 570 } 571 572 // set message fields 573 if (bridging.getResponseQueueSize() > 0) 574 { 575 getMsgFlagsRes.set(getMsgFlagReceiveMessageBit); 576 } 577 else 578 { 579 getMsgFlagsRes.reset(getMsgFlagReceiveMessageBit); 580 } 581 582 try 583 { 584 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 585 ipmi::Value variant = ipmi::getDbusProperty( 586 *dbus, wdtService, wdtObjPath, wdtInterface, wdtInterruptFlagProp); 587 if (std::get<bool>(variant)) 588 { 589 getMsgFlagsRes.set(getMsgFlagWatchdogPreTimeOutBit); 590 } 591 } 592 catch (const sdbusplus::exception_t& e) 593 { 594 phosphor::logging::log<phosphor::logging::level::ERR>( 595 "ipmiAppGetMessageFlags, dbus call exception"); 596 return ipmi::responseUnspecifiedError(); 597 } 598 599 return ipmi::responseSuccess(getMsgFlagsRes); 600 } 601 602 /** @brief This command is used to flush unread data from the receive 603 * message queue 604 * @param receiveMessage - clear receive message queue 605 * @param eventMsgBufFull - clear event message buffer full 606 * @param reserved2 - reserved bit 607 * @param watchdogTimeout - clear watchdog pre-timeout interrupt flag 608 * @param reserved1 - reserved bit 609 * @param oem0 - clear OEM 0 data 610 * @param oem1 - clear OEM 1 data 611 * @param oem2 - clear OEM 2 data 612 613 * @return IPMI completion code on success 614 */ 615 ipmi::RspType<> ipmiAppClearMessageFlags( 616 ipmi::Context::ptr& ctx, bool receiveMessage, bool eventMsgBufFull, 617 bool reserved2, bool watchdogTimeout, bool reserved1, bool /* oem0 */, 618 bool /* oem1 */, bool /* oem2 */) 619 { 620 ipmi::ChannelInfo chInfo; 621 622 try 623 { 624 getChannelInfo(ctx->channel, chInfo); 625 } 626 catch (const sdbusplus::exception_t& e) 627 { 628 phosphor::logging::log<phosphor::logging::level::ERR>( 629 "ipmiAppClearMessageFlags: Failed to get Channel Info", 630 phosphor::logging::entry("MSG: %s", e.description())); 631 return ipmi::responseUnspecifiedError(); 632 } 633 if (chInfo.mediumType != 634 static_cast<uint8_t>(ipmi::EChannelMediumType::systemInterface)) 635 { 636 phosphor::logging::log<phosphor::logging::level::ERR>( 637 "ipmiAppClearMessageFlags: Error - supported only in System(SMS) " 638 "interface"); 639 return ipmi::responseCommandNotAvailable(); 640 } 641 642 if (reserved1 || reserved2) 643 { 644 return ipmi::responseInvalidFieldRequest(); 645 } 646 647 if (receiveMessage) 648 { 649 bridging.clearResponseQueue(); 650 } 651 652 if (eventMessageBufferFlag != true && eventMsgBufFull == true) 653 { 654 eventMessageBufferFlag = true; 655 } 656 657 try 658 { 659 if (watchdogTimeout) 660 { 661 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 662 ipmi::setDbusProperty(*dbus, wdtService, wdtObjPath, wdtInterface, 663 wdtInterruptFlagProp, false); 664 } 665 } 666 catch (const sdbusplus::exception_t& e) 667 { 668 phosphor::logging::log<phosphor::logging::level::ERR>( 669 "ipmiAppClearMessageFlags: can't Clear/Set " 670 "PreTimeoutInterruptOccurFlag"); 671 return ipmi::responseUnspecifiedError(); 672 } 673 674 return ipmi::responseSuccess(); 675 } 676 677 using systemEventType = std::tuple< 678 uint16_t, // Generator ID 679 uint32_t, // Timestamp 680 uint8_t, // Sensor Type 681 uint8_t, // EvM Rev 682 uint8_t, // Sensor Number 683 uint7_t, // Event Type 684 bool, // Event Direction 685 std::array<uint8_t, intel_oem::ipmi::sel::systemEventSize>>; // Event Data 686 using oemTsEventType = std::tuple< 687 uint32_t, // Timestamp 688 std::array<uint8_t, intel_oem::ipmi::sel::oemTsEventSize>>; // Event Data 689 using oemEventType = 690 std::array<uint8_t, intel_oem::ipmi::sel::oemEventSize>; // Event Data 691 692 /** @brief implements of Read event message buffer command 693 * 694 * @returns IPMI completion code plus response data 695 * - recordID - SEL Record ID 696 * - recordType - Record Type 697 * - generatorID - Generator ID 698 * - timeStamp - Timestamp 699 * - sensorType - Sensor Type 700 * - eventMsgFormatRev - Event Message format version 701 * - sensorNumber - Sensor Number 702 * - eventType - Event Type 703 * - eventDir - Event Direction 704 * - eventData - Event Data field 705 */ 706 ipmi::RspType<uint16_t, // Record ID 707 uint8_t, // Record Type 708 std::variant<systemEventType, oemTsEventType, 709 oemEventType>> // Record Content 710 ipmiAppReadEventMessageBuffer(ipmi::Context::ptr& ctx) 711 { 712 ipmi::ChannelInfo chInfo; 713 714 try 715 { 716 getChannelInfo(ctx->channel, chInfo); 717 } 718 catch (const sdbusplus::exception_t& e) 719 { 720 phosphor::logging::log<phosphor::logging::level::ERR>( 721 "ipmiAppReadEventMessageBuffer: Failed to get Channel Info", 722 phosphor::logging::entry("MSG: %s", e.description())); 723 return ipmi::responseUnspecifiedError(); 724 } 725 if (chInfo.mediumType != 726 static_cast<uint8_t>(ipmi::EChannelMediumType::systemInterface)) 727 { 728 phosphor::logging::log<phosphor::logging::level::ERR>( 729 "ipmiAppReadEventMessageBuffer: Error - supported only in " 730 "System(SMS) interface"); 731 return ipmi::responseCommandNotAvailable(); 732 } 733 734 uint16_t recordId = 735 static_cast<uint16_t>(0x5555); // recordId: 0x55 << 8 | 0x55 736 uint16_t generatorId = 737 static_cast<uint16_t>(0xA741); // generatorId: 0xA7 << 8 | 0x41 738 constexpr uint8_t recordType = 0xC0; 739 constexpr uint8_t eventMsgFormatRev = 0x3A; 740 constexpr uint8_t sensorNumber = 0xFF; 741 742 // TODO need to be implemented. 743 std::array<uint8_t, intel_oem::ipmi::sel::systemEventSize> eventData{}; 744 // All '0xFF' since unused. 745 eventData.fill(0xFF); 746 747 // Set the event message buffer flag 748 eventMessageBufferFlag = true; 749 750 return ipmi::responseSuccess( 751 recordId, recordType, 752 systemEventType{generatorId, 0, 0, eventMsgFormatRev, sensorNumber, 753 static_cast<uint7_t>(0), false, eventData}); 754 } 755 756 static void register_bridging_functions() __attribute__((constructor)); 757 static void register_bridging_functions() 758 { 759 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnApp, 760 ipmi::app::cmdClearMessageFlags, 761 ipmi::Privilege::User, ipmiAppClearMessageFlags); 762 763 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnApp, 764 ipmi::app::cmdGetMessageFlags, ipmi::Privilege::User, 765 ipmiAppGetMessageFlags); 766 767 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnApp, 768 ipmi::app::cmdGetMessage, ipmi::Privilege::User, 769 ipmiAppGetMessage); 770 771 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnApp, 772 ipmi::app::cmdSendMessage, ipmi::Privilege::User, 773 ipmiAppSendMessage); 774 775 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnApp, 776 ipmi::app::cmdReadEventMessageBuffer, 777 ipmi::Privilege::User, ipmiAppReadEventMessageBuffer); 778 779 return; 780 } 781