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 ipmbDataChecksumValidate(const ipmbHeader* ipmbHeader, 102 uint8_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, uint8_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), 155 netFn(netFn), rqLun(rqLun), rsSA(rsSA), seq(seq), rsLun(rsLun), cmd(cmd), 156 completionCode(completionCode) 157 { 158 data.reserve(ipmbMaxDataSize); 159 160 if (inputData.size() > 0) 161 { 162 data = std::move(inputData); 163 } 164 } 165 166 void IpmbResponse::ipmbToi2cConstruct(uint8_t* buffer, size_t* bufferLength) 167 { 168 ipmbHeader* ipmbBuffer = (ipmbHeader*)buffer; 169 170 ipmbBuffer->Header.Resp.address = address; 171 ipmbBuffer->Header.Resp.rqNetFnLUN = ipmbNetFnLunSet(netFn, rqLun); 172 ipmbBuffer->Header.Resp.rsSA = rsSA; 173 ipmbBuffer->Header.Resp.rsSeqLUN = ipmbSeqLunSet(seq, rsLun); 174 ipmbBuffer->Header.Resp.cmd = cmd; 175 ipmbBuffer->Header.Resp.completionCode = completionCode; 176 177 ipmbBuffer->Header.Resp.checksum1 = ipmbChecksumCompute( 178 buffer, ipmbConnectionHeaderLength - ipmbChecksumSize); 179 180 if (data.size() > 0) 181 { 182 std::copy( 183 data.begin(), data.end(), 184 &buffer[ipmbConnectionHeaderLength + ipmbResponseDataHeaderLength]); 185 } 186 187 *bufferLength = data.size() + ipmbResponseDataHeaderLength + 188 ipmbConnectionHeaderLength + ipmbChecksumSize; 189 190 buffer[*bufferLength - ipmbChecksumSize] = 191 ipmbChecksumCompute(&buffer[ipmbChecksum2StartOffset], 192 (ipmbResponseDataHeaderLength + data.size())); 193 } 194 195 void IpmbRequest::prepareRequest(sdbusplus::message_t& mesg) 196 { 197 mesg.append(ipmbMeChannelNum, netFn, rqLun, cmd, data); 198 } 199 200 static constexpr unsigned int makeCmdKey(unsigned int netFn, unsigned int cmd) 201 { 202 return (netFn << 8) | cmd; 203 } 204 205 static constexpr bool isMeCmdAllowed(uint8_t netFn, uint8_t cmd) 206 { 207 constexpr uint8_t netFnMeOEM = 0x2E; 208 constexpr uint8_t netFnMeOEMGeneral = 0x3E; 209 constexpr uint8_t cmdMeOemSendRawPeci = 0x40; 210 constexpr uint8_t cmdMeOemAggSendRawPeci = 0x41; 211 constexpr uint8_t cmdMeOemCpuPkgConfWrite = 0x43; 212 constexpr uint8_t cmdMeOemCpuPciConfWrite = 0x45; 213 constexpr uint8_t cmdMeOemReadMemSmbus = 0x47; 214 constexpr uint8_t cmdMeOemWriteMemSmbus = 0x48; 215 constexpr uint8_t cmdMeOemSlotIpmb = 0x51; 216 constexpr uint8_t cmdMeOemSlotI2cControllerWriteRead = 0x52; 217 constexpr uint8_t cmdMeOemSendRawPmbus = 0xD9; 218 constexpr uint8_t cmdMeOemUnlockMeRegion = 0xE7; 219 constexpr uint8_t cmdMeOemAggSendRawPmbus = 0xEC; 220 221 switch (makeCmdKey(netFn, cmd)) 222 { 223 // Restrict ME Controller write command 224 case makeCmdKey(ipmi::netFnApp, ipmi::app::cmdMasterWriteRead): 225 // Restrict ME OEM commands 226 case makeCmdKey(netFnMeOEM, cmdMeOemSendRawPeci): 227 case makeCmdKey(netFnMeOEM, cmdMeOemAggSendRawPeci): 228 case makeCmdKey(netFnMeOEM, cmdMeOemCpuPkgConfWrite): 229 case makeCmdKey(netFnMeOEM, cmdMeOemCpuPciConfWrite): 230 case makeCmdKey(netFnMeOEM, cmdMeOemReadMemSmbus): 231 case makeCmdKey(netFnMeOEM, cmdMeOemWriteMemSmbus): 232 case makeCmdKey(netFnMeOEMGeneral, cmdMeOemSlotIpmb): 233 case makeCmdKey(netFnMeOEMGeneral, cmdMeOemSlotI2cControllerWriteRead): 234 case makeCmdKey(netFnMeOEM, cmdMeOemSendRawPmbus): 235 case makeCmdKey(netFnMeOEM, cmdMeOemUnlockMeRegion): 236 case makeCmdKey(netFnMeOEM, cmdMeOemAggSendRawPmbus): 237 return false; 238 default: 239 return true; 240 } 241 } 242 243 ipmi::Cc Bridging::handleIpmbChannel(ipmi::Context::ptr ctx, 244 const uint8_t tracking, 245 const std::vector<uint8_t>& msgData, 246 std::vector<uint8_t>& rspData) 247 { 248 ipmi::Manufacturing mtm; 249 250 size_t msgLen = msgData.size(); 251 if ((msgLen < ipmbMinFrameLength) || (msgLen > ipmbMaxFrameLength)) 252 { 253 phosphor::logging::log<phosphor::logging::level::INFO>( 254 "handleIpmbChannel, IPMB data length is invalid"); 255 return ipmi::ccReqDataLenInvalid; 256 } 257 258 // Bridging to ME requires Administrator lvl 259 if ((ctx->priv) != ipmi::Privilege::Admin) 260 { 261 return ipmi::ccInsufficientPrivilege; 262 } 263 264 auto sendMsgReqData = reinterpret_cast<const ipmbHeader*>(msgData.data()); 265 266 // allow bridging to ME only 267 if (sendMsgReqData->Header.Req.address != ipmbMeTargetAddress) 268 { 269 phosphor::logging::log<phosphor::logging::level::INFO>( 270 "handleIpmbChannel, IPMB address invalid"); 271 return ipmi::ccParmOutOfRange; 272 } 273 274 constexpr uint8_t shiftLUN = 2; 275 if (mtm.getMfgMode() == ipmi::SpecialMode::none) 276 { 277 if (!isMeCmdAllowed((sendMsgReqData->Header.Req.rsNetFnLUN >> shiftLUN), 278 sendMsgReqData->Header.Req.cmd)) 279 { 280 constexpr ipmi::Cc ccCmdNotSupportedInPresentState = 0xD5; 281 return ccCmdNotSupportedInPresentState; 282 } 283 } 284 285 // check allowed modes 286 if (tracking != modeNoTracking && tracking != modeTrackRequest) 287 { 288 phosphor::logging::log<phosphor::logging::level::INFO>( 289 "handleIpmbChannel, mode not supported"); 290 return ipmi::ccParmOutOfRange; 291 } 292 293 // check if request contains valid IPMB frame 294 if (!isFrameValid(sendMsgReqData, msgLen)) 295 { 296 phosphor::logging::log<phosphor::logging::level::INFO>( 297 "handleIpmbChannel, IPMB frame invalid"); 298 return ipmi::ccParmOutOfRange; 299 } 300 301 auto ipmbRequest = IpmbRequest(sendMsgReqData, msgLen); 302 303 typedef std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, 304 std::vector<uint8_t>> 305 IPMBResponse; 306 307 // send request to IPMB 308 boost::system::error_code ec; 309 auto ipmbResponse = ctx->bus->yield_method_call<IPMBResponse>( 310 ctx->yield, ec, ipmbBus, ipmbObj, ipmbIntf, "sendRequest", 311 ipmbMeChannelNum, ipmbRequest.netFn, ipmbRequest.rqLun, ipmbRequest.cmd, 312 ipmbRequest.data); 313 if (ec) 314 { 315 phosphor::logging::log<phosphor::logging::level::ERR>( 316 "handleIpmbChannel, dbus call exception"); 317 return ipmi::ccUnspecifiedError; 318 } 319 320 std::vector<uint8_t> dataReceived(0); 321 int status = -1; 322 uint8_t netFn = 0, lun = 0, cmd = 0, cc = 0; 323 324 std::tie(status, netFn, lun, cmd, cc, dataReceived) = ipmbResponse; 325 326 auto respReceived = 327 IpmbResponse(ipmbRequest.rqSA, netFn, lun, ipmbRequest.address, 328 ipmbRequest.seq, lun, cmd, cc, dataReceived); 329 330 // check IPMB layer status 331 if (status) 332 { 333 phosphor::logging::log<phosphor::logging::level::WARNING>( 334 "handleIpmbChannel, ipmb returned non zero status"); 335 return ipmi::ccResponseError; 336 } 337 338 switch (tracking) 339 { 340 case modeNoTracking: 341 { 342 if (getResponseQueueSize() == responseQueueMaxSize) 343 { 344 return ipmi::ccBusy; 345 } 346 insertMessageInQueue(respReceived); 347 break; 348 } 349 case modeTrackRequest: 350 { 351 size_t dataLength = 0; 352 respReceived.ipmbToi2cConstruct(rspData.data(), &dataLength); 353 // resizing the rspData to its correct length 354 rspData.resize(dataLength); 355 break; 356 } 357 default: 358 { 359 phosphor::logging::log<phosphor::logging::level::INFO>( 360 "handleIpmbChannel, mode not supported"); 361 return ipmi::ccParmOutOfRange; 362 } 363 } 364 365 return ipmi::ccSuccess; 366 } 367 368 void Bridging::insertMessageInQueue(IpmbResponse msg) 369 { 370 responseQueue.insert(responseQueue.end(), std::move(msg)); 371 } 372 373 void Bridging::eraseMessageFromQueue() 374 { 375 responseQueue.erase(responseQueue.begin()); 376 } 377 378 IpmbResponse Bridging::getMessageFromQueue() 379 { 380 return responseQueue.front(); 381 } 382 383 /** 384 * @brief This command is used for bridging ipmi message between channels. 385 * @param channelNumber - channel number to send message to 386 * @param authenticationEnabled - authentication. 387 * @param encryptionEnabled - encryption 388 * @param Tracking - track request 389 * @param msg - message data 390 * 391 * @return IPMI completion code plus response data on success. 392 * - rspData - response data 393 **/ 394 ipmi::RspType<std::vector<uint8_t> // responseData 395 > 396 ipmiAppSendMessage(ipmi::Context::ptr ctx, const uint4_t channelNumber, 397 const bool authenticationEnabled, 398 const bool encryptionEnabled, const uint2_t tracking, 399 ipmi::message::Payload& msg) 400 { 401 // check message fields: 402 // encryption not supported 403 if (encryptionEnabled) 404 { 405 phosphor::logging::log<phosphor::logging::level::INFO>( 406 "ipmiAppSendMessage, encryption not supported"); 407 return ipmi::responseParmOutOfRange(); 408 } 409 410 // authentication not supported 411 if (authenticationEnabled) 412 { 413 phosphor::logging::log<phosphor::logging::level::INFO>( 414 "ipmiAppSendMessage, authentication not supported"); 415 return ipmi::responseParmOutOfRange(); 416 } 417 418 ipmi::Cc returnVal; 419 std::vector<uint8_t> rspData(ipmbMaxFrameLength); 420 size_t dataLength = 0; 421 std::vector<uint8_t> unpackMsg; 422 423 auto channelNo = static_cast<const uint8_t>(channelNumber); 424 // Get the channel number 425 switch (channelNo) 426 { 427 // we only handle ipmb for now 428 case targetChannelIpmb: 429 case targetChannelOtherLan: 430 if (msg.unpack(unpackMsg) || !msg.fullyUnpacked()) 431 { 432 return ipmi::responseReqDataLenInvalid(); 433 } 434 435 returnVal = bridging.handleIpmbChannel( 436 ctx, static_cast<const uint8_t>(tracking), unpackMsg, rspData); 437 break; 438 // fall through to default 439 case targetChannelIcmb10: 440 case targetChannelIcmb09: 441 case targetChannelLan: 442 case targetChannelSerialModem: 443 case targetChannelPciSmbus: 444 case targetChannelSmbus10: 445 case targetChannelSmbus20: 446 case targetChannelSystemInterface: 447 default: 448 phosphor::logging::log<phosphor::logging::level::INFO>( 449 "ipmiAppSendMessage, TargetChannel invalid"); 450 return ipmi::responseParmOutOfRange(); 451 } 452 if (returnVal != ipmi::ccSuccess) 453 { 454 return ipmi::response(returnVal); 455 } 456 457 return ipmi::responseSuccess(rspData); 458 } 459 460 /** 461 * @brief This command is used to Get data from the receive message queue. 462 * This command should be executed executed via system interface only. 463 * 464 * @return IPMI completion code plus response data on success. 465 * - channelNumber 466 * - messageData 467 **/ 468 469 ipmi::RspType<uint8_t, // channelNumber 470 std::vector<uint8_t> // messageData 471 > 472 ipmiAppGetMessage(ipmi::Context::ptr ctx) 473 { 474 ipmi::ChannelInfo chInfo; 475 476 try 477 { 478 getChannelInfo(ctx->channel, chInfo); 479 } 480 catch (const sdbusplus::exception_t& e) 481 { 482 phosphor::logging::log<phosphor::logging::level::ERR>( 483 "ipmiAppGetMessage: Failed to get Channel Info", 484 phosphor::logging::entry("MSG: %s", e.description())); 485 return ipmi::responseUnspecifiedError(); 486 } 487 if (chInfo.mediumType != 488 static_cast<uint8_t>(ipmi::EChannelMediumType::systemInterface)) 489 { 490 phosphor::logging::log<phosphor::logging::level::ERR>( 491 "ipmiAppGetMessage: Error - supported only in System(SMS) " 492 "interface"); 493 return ipmi::responseCommandNotAvailable(); 494 } 495 496 uint8_t channelData = 0; 497 std::vector<uint8_t> res(ipmbMaxFrameLength); 498 size_t dataLength = 0; 499 500 if (!bridging.getResponseQueueSize()) 501 { 502 constexpr ipmi::Cc ipmiGetMessageCmdDataNotAvailable = 0x80; 503 phosphor::logging::log<phosphor::logging::level::INFO>( 504 "ipmiAppGetMessage, no data available"); 505 return ipmi::response(ipmiGetMessageCmdDataNotAvailable); 506 } 507 508 // channel number set. 509 channelData |= static_cast<uint8_t>(targetChannelSystemInterface) & 0x0F; 510 511 // Priviledge level set. 512 channelData |= SYSTEM_INTERFACE & 0xF0; 513 514 // Get the first message from queue 515 auto respQueueItem = bridging.getMessageFromQueue(); 516 517 // construct response data. 518 respQueueItem.ipmbToi2cConstruct(res.data(), &dataLength); 519 520 // Remove the message from queue 521 bridging.eraseMessageFromQueue(); 522 523 // resizing the rspData to its correct length 524 res.resize(dataLength); 525 526 return ipmi::responseSuccess(channelData, res); 527 } 528 529 std::size_t Bridging::getResponseQueueSize() 530 { 531 return responseQueue.size(); 532 } 533 534 /** 535 @brief This command is used to retrive present message available states. 536 537 @return IPMI completion code plus Flags as response data on success. 538 **/ 539 ipmi::RspType<std::bitset<8>> ipmiAppGetMessageFlags(ipmi::Context::ptr ctx) 540 { 541 ipmi::ChannelInfo chInfo; 542 543 try 544 { 545 getChannelInfo(ctx->channel, chInfo); 546 } 547 catch (const sdbusplus::exception_t& e) 548 { 549 phosphor::logging::log<phosphor::logging::level::ERR>( 550 "ipmiAppGetMessageFlags: Failed to get Channel Info", 551 phosphor::logging::entry("MSG: %s", e.description())); 552 return ipmi::responseUnspecifiedError(); 553 } 554 if (chInfo.mediumType != 555 static_cast<uint8_t>(ipmi::EChannelMediumType::systemInterface)) 556 { 557 phosphor::logging::log<phosphor::logging::level::ERR>( 558 "ipmiAppGetMessageFlags: Error - supported only in System(SMS) " 559 "interface"); 560 return ipmi::responseCommandNotAvailable(); 561 } 562 563 std::bitset<8> getMsgFlagsRes; 564 565 // set event message buffer bit 566 if (!eventMessageBufferFlag) 567 { 568 getMsgFlagsRes.set(getMsgFlagEventMessageBit); 569 } 570 else 571 { 572 getMsgFlagsRes.reset(getMsgFlagEventMessageBit); 573 } 574 575 // set message fields 576 if (bridging.getResponseQueueSize() > 0) 577 { 578 getMsgFlagsRes.set(getMsgFlagReceiveMessageBit); 579 } 580 else 581 { 582 getMsgFlagsRes.reset(getMsgFlagReceiveMessageBit); 583 } 584 585 try 586 { 587 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 588 ipmi::Value variant = ipmi::getDbusProperty( 589 *dbus, wdtService, wdtObjPath, wdtInterface, wdtInterruptFlagProp); 590 if (std::get<bool>(variant)) 591 { 592 getMsgFlagsRes.set(getMsgFlagWatchdogPreTimeOutBit); 593 } 594 } 595 catch (const sdbusplus::exception_t& e) 596 { 597 phosphor::logging::log<phosphor::logging::level::ERR>( 598 "ipmiAppGetMessageFlags, dbus call exception"); 599 return ipmi::responseUnspecifiedError(); 600 } 601 602 return ipmi::responseSuccess(getMsgFlagsRes); 603 } 604 605 /** @brief This command is used to flush unread data from the receive 606 * message queue 607 * @param receiveMessage - clear receive message queue 608 * @param eventMsgBufFull - clear event message buffer full 609 * @param reserved2 - reserved bit 610 * @param watchdogTimeout - clear watchdog pre-timeout interrupt flag 611 * @param reserved1 - reserved bit 612 * @param oem0 - clear OEM 0 data 613 * @param oem1 - clear OEM 1 data 614 * @param oem2 - clear OEM 2 data 615 616 * @return IPMI completion code on success 617 */ 618 ipmi::RspType<> ipmiAppClearMessageFlags(ipmi::Context::ptr ctx, 619 bool receiveMessage, 620 bool eventMsgBufFull, bool reserved2, 621 bool watchdogTimeout, bool reserved1, 622 bool oem0, bool oem1, bool oem2) 623 { 624 ipmi::ChannelInfo chInfo; 625 626 try 627 { 628 getChannelInfo(ctx->channel, chInfo); 629 } 630 catch (const sdbusplus::exception_t& e) 631 { 632 phosphor::logging::log<phosphor::logging::level::ERR>( 633 "ipmiAppClearMessageFlags: Failed to get Channel Info", 634 phosphor::logging::entry("MSG: %s", e.description())); 635 return ipmi::responseUnspecifiedError(); 636 } 637 if (chInfo.mediumType != 638 static_cast<uint8_t>(ipmi::EChannelMediumType::systemInterface)) 639 { 640 phosphor::logging::log<phosphor::logging::level::ERR>( 641 "ipmiAppClearMessageFlags: Error - supported only in System(SMS) " 642 "interface"); 643 return ipmi::responseCommandNotAvailable(); 644 } 645 646 if (reserved1 || reserved2) 647 { 648 return ipmi::responseInvalidFieldRequest(); 649 } 650 651 if (receiveMessage) 652 { 653 bridging.clearResponseQueue(); 654 } 655 656 if (eventMessageBufferFlag != true && eventMsgBufFull == true) 657 { 658 eventMessageBufferFlag = true; 659 } 660 661 try 662 { 663 if (watchdogTimeout) 664 { 665 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 666 ipmi::setDbusProperty(*dbus, wdtService, wdtObjPath, wdtInterface, 667 wdtInterruptFlagProp, false); 668 } 669 } 670 catch (const sdbusplus::exception_t& e) 671 { 672 phosphor::logging::log<phosphor::logging::level::ERR>( 673 "ipmiAppClearMessageFlags: can't Clear/Set " 674 "PreTimeoutInterruptOccurFlag"); 675 return ipmi::responseUnspecifiedError(); 676 } 677 678 return ipmi::responseSuccess(); 679 } 680 681 using systemEventType = std::tuple< 682 uint16_t, // Generator ID 683 uint32_t, // Timestamp 684 uint8_t, // Sensor Type 685 uint8_t, // EvM Rev 686 uint8_t, // Sensor Number 687 uint7_t, // Event Type 688 bool, // Event Direction 689 std::array<uint8_t, intel_oem::ipmi::sel::systemEventSize>>; // Event Data 690 using oemTsEventType = std::tuple< 691 uint32_t, // Timestamp 692 std::array<uint8_t, intel_oem::ipmi::sel::oemTsEventSize>>; // Event Data 693 using oemEventType = 694 std::array<uint8_t, intel_oem::ipmi::sel::oemEventSize>; // Event Data 695 696 /** @brief implements of Read event message buffer command 697 * 698 * @returns IPMI completion code plus response data 699 * - recordID - SEL Record ID 700 * - recordType - Record Type 701 * - generatorID - Generator ID 702 * - timeStamp - Timestamp 703 * - sensorType - Sensor Type 704 * - eventMsgFormatRev - Event Message format version 705 * - sensorNumber - Sensor Number 706 * - eventType - Event Type 707 * - eventDir - Event Direction 708 * - eventData - Event Data field 709 */ 710 ipmi::RspType<uint16_t, // Record ID 711 uint8_t, // Record Type 712 std::variant<systemEventType, oemTsEventType, 713 oemEventType>> // Record Content 714 ipmiAppReadEventMessageBuffer(ipmi::Context::ptr ctx) 715 { 716 ipmi::ChannelInfo chInfo; 717 718 try 719 { 720 getChannelInfo(ctx->channel, chInfo); 721 } 722 catch (const sdbusplus::exception_t& e) 723 { 724 phosphor::logging::log<phosphor::logging::level::ERR>( 725 "ipmiAppReadEventMessageBuffer: Failed to get Channel Info", 726 phosphor::logging::entry("MSG: %s", e.description())); 727 return ipmi::responseUnspecifiedError(); 728 } 729 if (chInfo.mediumType != 730 static_cast<uint8_t>(ipmi::EChannelMediumType::systemInterface)) 731 { 732 phosphor::logging::log<phosphor::logging::level::ERR>( 733 "ipmiAppReadEventMessageBuffer: Error - supported only in " 734 "System(SMS) interface"); 735 return ipmi::responseCommandNotAvailable(); 736 } 737 738 uint16_t recordId = 739 static_cast<uint16_t>(0x5555); // recordId: 0x55 << 8 | 0x55 740 uint16_t generatorId = 741 static_cast<uint16_t>(0xA741); // generatorId: 0xA7 << 8 | 0x41 742 constexpr uint8_t recordType = 0xC0; 743 constexpr uint8_t eventMsgFormatRev = 0x3A; 744 constexpr uint8_t sensorNumber = 0xFF; 745 746 // TODO need to be implemented. 747 std::array<uint8_t, intel_oem::ipmi::sel::systemEventSize> eventData{}; 748 // All '0xFF' since unused. 749 eventData.fill(0xFF); 750 751 // Set the event message buffer flag 752 eventMessageBufferFlag = true; 753 754 return ipmi::responseSuccess( 755 recordId, recordType, 756 systemEventType{generatorId, 0, 0, eventMsgFormatRev, sensorNumber, 757 static_cast<uint7_t>(0), false, eventData}); 758 } 759 760 static void register_bridging_functions() __attribute__((constructor)); 761 static void register_bridging_functions() 762 { 763 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnApp, 764 ipmi::app::cmdClearMessageFlags, 765 ipmi::Privilege::User, ipmiAppClearMessageFlags); 766 767 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnApp, 768 ipmi::app::cmdGetMessageFlags, ipmi::Privilege::User, 769 ipmiAppGetMessageFlags); 770 771 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnApp, 772 ipmi::app::cmdGetMessage, ipmi::Privilege::User, 773 ipmiAppGetMessage); 774 775 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnApp, 776 ipmi::app::cmdSendMessage, ipmi::Privilege::User, 777 ipmiAppSendMessage); 778 779 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnApp, 780 ipmi::app::cmdReadEventMessageBuffer, 781 ipmi::Privilege::User, ipmiAppReadEventMessageBuffer); 782 783 return; 784 } 785