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 <errno.h> 18 #include <fcntl.h> 19 #include <limits.h> 20 #include <sys/stat.h> 21 #include <sys/types.h> 22 #include <unistd.h> 23 24 #include <commandutils.hpp> 25 #include <ipmid/api.hpp> 26 #include <ipmid/utils.hpp> 27 #include <oemcommands.hpp> 28 #include <phosphor-logging/log.hpp> 29 #include <sdbusplus/message/types.hpp> 30 #include <smbiosmdrv2handler.hpp> 31 #include <xyz/openbmc_project/Common/error.hpp> 32 33 #include <cstdint> 34 #include <fstream> 35 #include <string> 36 #include <vector> 37 38 std::unique_ptr<MDRV2> mdrv2 = nullptr; 39 static constexpr const uint8_t ccOemInvalidChecksum = 0x85; 40 static constexpr size_t dataInfoSize = 16; 41 static constexpr const uint8_t ccStorageLeak = 0xC4; 42 43 static void register_netfn_smbiosmdrv2_functions() __attribute__((constructor)); 44 45 int MDRV2::agentLookup(const uint16_t& agentId) 46 { 47 int agentIndex = -1; 48 49 if (lastAgentId == agentId) 50 { 51 return lastAgentIndex; 52 } 53 54 if (agentId == smbiosAgentId) 55 { 56 return firstAgentIndex; 57 } 58 59 return agentIndex; 60 } 61 62 int MDRV2::sdplusMdrv2GetProperty(const std::string& name, 63 std::variant<uint8_t>& value, 64 const std::string& service) 65 { 66 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus(); 67 sdbusplus::message_t method = 68 bus->new_method_call(service.c_str(), mdrv2Path, dbusProperties, "Get"); 69 method.append(mdrv2Interface, name); 70 71 sdbusplus::message_t reply = bus->call(method); 72 73 try 74 { 75 sdbusplus::message_t reply = bus->call(method); 76 reply.read(value); 77 } 78 catch (const sdbusplus::exception_t& e) 79 { 80 phosphor::logging::log<phosphor::logging::level::ERR>( 81 "Error get property, sdbusplus call failed", 82 phosphor::logging::entry("ERROR=%s", e.what())); 83 return -1; 84 } 85 86 return 0; 87 } 88 89 int MDRV2::syncDirCommonData(uint8_t idIndex, uint32_t size, 90 const std::string& service) 91 { 92 std::vector<uint32_t> commonData; 93 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus(); 94 sdbusplus::message_t method = 95 bus->new_method_call(service.c_str(), mdrv2Path, mdrv2Interface, 96 "SynchronizeDirectoryCommonData"); 97 method.append(idIndex, size); 98 99 try 100 { 101 sdbusplus::message_t reply = bus->call(method); 102 reply.read(commonData); 103 } 104 catch (const sdbusplus::exception_t& e) 105 { 106 phosphor::logging::log<phosphor::logging::level::ERR>( 107 "Error sync dir common data with service", 108 phosphor::logging::entry("ERROR=%s", e.what())); 109 return -1; 110 } 111 112 if (commonData.size() < syncDirCommonSize) 113 { 114 phosphor::logging::log<phosphor::logging::level::ERR>( 115 "Error sync dir common data - data length invalid"); 116 return -1; 117 } 118 smbiosDir.dir[idIndex].common.dataSetSize = commonData.at(0); 119 smbiosDir.dir[idIndex].common.dataVersion = commonData.at(1); 120 smbiosDir.dir[idIndex].common.timestamp = commonData.at(2); 121 122 return 0; 123 } 124 125 int MDRV2::findDataId(const uint8_t* dataInfo, const size_t& len, 126 const std::string& service) 127 { 128 int idIndex = -1; 129 130 if (dataInfo == nullptr) 131 { 132 phosphor::logging::log<phosphor::logging::level::ERR>( 133 "Error dataInfo, input is null point"); 134 return -1; 135 } 136 137 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus(); 138 sdbusplus::message_t method = bus->new_method_call( 139 service.c_str(), mdrv2Path, mdrv2Interface, "FindIdIndex"); 140 std::vector<uint8_t> info; 141 info.resize(len); 142 std::copy(dataInfo, dataInfo + len, info.data()); 143 method.append(info); 144 145 try 146 { 147 sdbusplus::message_t reply = bus->call(method); 148 reply.read(idIndex); 149 } 150 catch (const sdbusplus::exception_t& e) 151 { 152 phosphor::logging::log<phosphor::logging::level::ERR>( 153 "Error find id index", 154 phosphor::logging::entry("ERROR=%s", e.what()), 155 phosphor::logging::entry("SERVICE=%s", service.c_str()), 156 phosphor::logging::entry("PATH=%s", mdrv2Path)); 157 return -1; 158 } 159 160 return idIndex; 161 } 162 163 uint16_t MDRV2::getSessionHandle(Mdr2DirStruct* dir) 164 { 165 if (dir == NULL) 166 { 167 phosphor::logging::log<phosphor::logging::level::ERR>( 168 "Empty dir point"); 169 return 0; 170 } 171 dir->sessionHandle++; 172 if (dir->sessionHandle == 0) 173 { 174 dir->sessionHandle = 1; 175 } 176 177 return dir->sessionHandle; 178 } 179 180 int MDRV2::findLockHandle(const uint16_t& lockHandle) 181 { 182 int idIndex = -1; 183 184 for (int index = 0; index < smbiosDir.dirEntries; index++) 185 { 186 if (lockHandle == smbiosDir.dir[index].lockHandle) 187 { 188 return index; 189 } 190 } 191 192 return idIndex; 193 } 194 195 bool MDRV2::smbiosIsUpdating(uint8_t index) 196 { 197 if (index >= maxDirEntries) 198 { 199 return false; 200 } 201 if (smbiosDir.dir[index].stage == MDR2SMBIOSStatusEnum::mdr2Updating) 202 { 203 return true; 204 } 205 206 return false; 207 } 208 209 uint32_t MDRV2::calcChecksum32(uint8_t* buf, uint32_t len) 210 { 211 uint32_t sum = 0; 212 213 if (buf == nullptr) 214 { 215 return invalidChecksum; 216 } 217 218 for (uint32_t index = 0; index < len; index++) 219 { 220 sum += buf[index]; 221 } 222 223 return sum; 224 } 225 226 /** @brief implements mdr2 agent status command 227 * @param agentId 228 * @param dirVersion 229 * 230 * @returns IPMI completion code plus response data 231 * - mdrVersion 232 * - agentVersion 233 * - dirVersion 234 * - dirEntries 235 * - dataRequest 236 */ 237 ipmi::RspType<uint8_t, uint8_t, uint8_t, uint8_t, uint8_t> 238 mdr2AgentStatus(uint16_t agentId, uint8_t dirVersion) 239 { 240 if (mdrv2 == nullptr) 241 { 242 mdrv2 = std::make_unique<MDRV2>(); 243 } 244 245 int agentIndex = mdrv2->agentLookup(agentId); 246 if (agentIndex == -1) 247 { 248 phosphor::logging::log<phosphor::logging::level::ERR>( 249 "Unknown agent id", phosphor::logging::entry("ID=%x", agentId)); 250 return ipmi::responseParmOutOfRange(); 251 } 252 253 constexpr uint8_t mdrVersion = mdr2Version; 254 constexpr uint8_t agentVersion = smbiosAgentVersion; 255 uint8_t dirVersionResp = mdrv2->smbiosDir.dirVersion; 256 uint8_t dirEntries = mdrv2->smbiosDir.dirEntries; 257 uint8_t dataRequest; 258 259 if (mdrv2->smbiosDir.remoteDirVersion != dirVersion) 260 { 261 mdrv2->smbiosDir.remoteDirVersion = dirVersion; 262 dataRequest = 263 static_cast<uint8_t>(DirDataRequestEnum::dirDataRequested); 264 } 265 else 266 { 267 dataRequest = 268 static_cast<uint8_t>(DirDataRequestEnum::dirDataNotRequested); 269 } 270 271 return ipmi::responseSuccess(mdrVersion, agentVersion, dirVersionResp, 272 dirEntries, dataRequest); 273 } 274 275 /** @brief implements mdr2 get directory command 276 * @param agentId 277 * @param dirIndex 278 * @returns IPMI completion code plus response data 279 * - dataOut 280 */ 281 ipmi::RspType<std::vector<uint8_t>> mdr2GetDir(uint16_t agentId, 282 uint8_t dirIndex) 283 { 284 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus(); 285 std::string service = ipmi::getService(*bus, mdrv2Interface, mdrv2Path); 286 287 if (mdrv2 == nullptr) 288 { 289 mdrv2 = std::make_unique<MDRV2>(); 290 } 291 292 int agentIndex = mdrv2->agentLookup(agentId); 293 if (agentIndex == -1) 294 { 295 phosphor::logging::log<phosphor::logging::level::ERR>( 296 "Unknown agent id", phosphor::logging::entry("ID=%x", agentId)); 297 return ipmi::responseParmOutOfRange(); 298 } 299 300 std::variant<uint8_t> value = static_cast<uint8_t>(0); 301 if (0 != mdrv2->sdplusMdrv2GetProperty("DirectoryEntries", value, service)) 302 { 303 phosphor::logging::log<phosphor::logging::level::ERR>( 304 "Error getting DirEnries"); 305 return ipmi::responseUnspecifiedError(); 306 } 307 if (std::get<uint8_t>(value) == 0) 308 { 309 phosphor::logging::log<phosphor::logging::level::ERR>( 310 "Error getting directory entries", 311 phosphor::logging::entry("VALUE=%x", std::get<uint8_t>(value))); 312 return ipmi::responseUnspecifiedError(); 313 } 314 if (dirIndex > std::get<uint8_t>(value)) 315 { 316 return ipmi::responseParmOutOfRange(); 317 } 318 319 sdbusplus::message_t method = bus->new_method_call( 320 service.c_str(), mdrv2Path, mdrv2Interface, "GetDirectoryInformation"); 321 322 method.append(dirIndex); 323 324 std::vector<uint8_t> dataOut; 325 try 326 { 327 sdbusplus::message_t reply = bus->call(method); 328 reply.read(dataOut); 329 } 330 catch (const sdbusplus::exception_t& e) 331 { 332 phosphor::logging::log<phosphor::logging::level::ERR>( 333 "Error get dir", phosphor::logging::entry("ERROR=%s", e.what()), 334 phosphor::logging::entry("SERVICE=%s", service.c_str()), 335 phosphor::logging::entry("PATH=%s", mdrv2Path)); 336 return ipmi::responseResponseError(); 337 } 338 339 constexpr size_t getDirRespSize = 6; 340 if (dataOut.size() < getDirRespSize) 341 { 342 phosphor::logging::log<phosphor::logging::level::ERR>( 343 "Error get dir, response length invalid"); 344 return ipmi::responseUnspecifiedError(); 345 } 346 347 if (dataOut.size() > MAX_IPMI_BUFFER) // length + completion code should no 348 // more than MAX_IPMI_BUFFER 349 { 350 phosphor::logging::log<phosphor::logging::level::ERR>( 351 "Data length send from service is invalid"); 352 return ipmi::responseResponseError(); 353 } 354 355 return ipmi::responseSuccess(dataOut); 356 } 357 358 /** @brief implements mdr2 send directory info command 359 * @param agentId 360 * @param dirVersion 361 * @param dirIndex 362 * @param returnedEntries 363 * @param remainingEntries 364 * @param dataInfo 365 * dataInfo is 32 Bytes in size and contains below parameters 366 * - dataInfo, size, dataSetSize, dataVersion, timestamp 367 * 368 * @returns IPMI completion code plus response data 369 * - bool 370 */ 371 372 ipmi::RspType<bool> mdr2SendDir(uint16_t agentId, uint8_t dirVersion, 373 uint8_t dirIndex, uint8_t returnedEntries, 374 uint8_t remainingEntries, 375 std::vector<uint8_t> dataInfo) 376 { 377 if ((static_cast<size_t>(returnedEntries) * dataInfoSize) != 378 dataInfo.size()) 379 { 380 return ipmi::responseReqDataLenInvalid(); 381 } 382 383 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus(); 384 std::string service = ipmi::getService(*bus, mdrv2Interface, mdrv2Path); 385 386 if (mdrv2 == nullptr) 387 { 388 mdrv2 = std::make_unique<MDRV2>(); 389 } 390 391 int agentIndex = mdrv2->agentLookup(agentId); 392 if (agentIndex == -1) 393 { 394 phosphor::logging::log<phosphor::logging::level::ERR>( 395 "Unknown agent id", phosphor::logging::entry("ID=%x", agentId)); 396 return ipmi::responseParmOutOfRange(); 397 } 398 399 if ((dirIndex + returnedEntries) > maxDirEntries) 400 { 401 phosphor::logging::log<phosphor::logging::level::ERR>( 402 "Too many directory entries"); 403 return ipmi::response(ccStorageLeak); 404 } 405 406 sdbusplus::message_t method = bus->new_method_call( 407 service.c_str(), mdrv2Path, mdrv2Interface, "SendDirectoryInformation"); 408 method.append(dirVersion, dirIndex, returnedEntries, remainingEntries, 409 dataInfo); 410 411 bool terminate = false; 412 try 413 { 414 sdbusplus::message_t reply = bus->call(method); 415 reply.read(terminate); 416 } 417 catch (const sdbusplus::exception_t& e) 418 { 419 phosphor::logging::log<phosphor::logging::level::ERR>( 420 "Error send dir", phosphor::logging::entry("ERROR=%s", e.what()), 421 phosphor::logging::entry("SERVICE=%s", service.c_str()), 422 phosphor::logging::entry("PATH=%s", mdrv2Path)); 423 return ipmi::responseResponseError(); 424 } 425 426 return ipmi::responseSuccess(terminate); 427 } 428 429 /** @brief implements mdr2 get data info command 430 * @param agentId 431 * @param dataInfo 432 * 433 * @returns IPMI completion code plus response data 434 * - response - mdrVersion, data info, validFlag, 435 * dataLength, dataVersion, timeStamp 436 */ 437 ipmi::RspType<std::vector<uint8_t>> 438 mdr2GetDataInfo(uint16_t agentId, std::vector<uint8_t> dataInfo) 439 { 440 constexpr size_t getDataInfoReqSize = 16; 441 442 if (dataInfo.size() < getDataInfoReqSize) 443 { 444 return ipmi::responseReqDataLenInvalid(); 445 } 446 447 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus(); 448 std::string service = ipmi::getService(*bus, mdrv2Interface, mdrv2Path); 449 450 if (mdrv2 == nullptr) 451 { 452 mdrv2 = std::make_unique<MDRV2>(); 453 } 454 455 int agentIndex = mdrv2->agentLookup(agentId); 456 if (agentIndex == -1) 457 { 458 phosphor::logging::log<phosphor::logging::level::ERR>( 459 "Unknown agent id", phosphor::logging::entry("ID=%x", agentId)); 460 return ipmi::responseParmOutOfRange(); 461 } 462 463 int idIndex = mdrv2->findDataId(dataInfo.data(), dataInfo.size(), service); 464 465 if ((idIndex < 0) || (idIndex >= maxDirEntries)) 466 { 467 phosphor::logging::log<phosphor::logging::level::ERR>( 468 "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex)); 469 return ipmi::responseParmOutOfRange(); 470 } 471 472 sdbusplus::message_t method = bus->new_method_call( 473 service.c_str(), mdrv2Path, mdrv2Interface, "GetDataInformation"); 474 475 method.append(static_cast<uint8_t>(idIndex)); 476 477 std::vector<uint8_t> res; 478 try 479 { 480 sdbusplus::message_t reply = bus->call(method); 481 reply.read(res); 482 } 483 catch (const sdbusplus::exception_t& e) 484 { 485 phosphor::logging::log<phosphor::logging::level::ERR>( 486 "Error get data info", 487 phosphor::logging::entry("ERROR=%s", e.what()), 488 phosphor::logging::entry("SERVICE=%s", service.c_str()), 489 phosphor::logging::entry("PATH=%s", mdrv2Path)); 490 return ipmi::responseResponseError(); 491 } 492 493 if (res.size() != sizeof(MDRiiGetDataInfoResponse)) 494 { 495 phosphor::logging::log<phosphor::logging::level::ERR>( 496 "Get data info response length not invalid"); 497 return ipmi::responseResponseError(); 498 } 499 500 return ipmi::responseSuccess(res); 501 } 502 503 /** @brief implements mdr2 data info offer command 504 * @param agentId - Offer a agent ID to get the "Data Set ID" 505 * 506 * @returns IPMI completion code plus response data 507 * - dataOut - data Set Id 508 */ 509 ipmi::RspType<std::vector<uint8_t>> mdr2DataInfoOffer(uint16_t agentId) 510 { 511 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus(); 512 std::string service = ipmi::getService(*bus, mdrv2Interface, mdrv2Path); 513 514 if (mdrv2 == nullptr) 515 { 516 mdrv2 = std::make_unique<MDRV2>(); 517 } 518 519 int agentIndex = mdrv2->agentLookup(agentId); 520 if (agentIndex == -1) 521 { 522 phosphor::logging::log<phosphor::logging::level::ERR>( 523 "Unknown agent id", phosphor::logging::entry("ID=%x", agentId)); 524 return ipmi::responseParmOutOfRange(); 525 } 526 527 sdbusplus::message_t method = bus->new_method_call( 528 service.c_str(), mdrv2Path, mdrv2Interface, "GetDataOffer"); 529 530 std::vector<uint8_t> dataOut; 531 try 532 { 533 sdbusplus::message_t reply = bus->call(method); 534 reply.read(dataOut); 535 } 536 catch (const sdbusplus::exception_t& e) 537 { 538 phosphor::logging::log<phosphor::logging::level::ERR>( 539 "Error send data info offer", 540 phosphor::logging::entry("ERROR=%s", e.what()), 541 phosphor::logging::entry("SERVICE=%s", service.c_str()), 542 phosphor::logging::entry("PATH=%s", mdrv2Path)); 543 return ipmi::responseResponseError(); 544 } 545 546 constexpr size_t respInfoSize = 16; 547 if (dataOut.size() != respInfoSize) 548 { 549 phosphor::logging::log<phosphor::logging::level::ERR>( 550 "Error send data info offer, return length invalid"); 551 return ipmi::responseUnspecifiedError(); 552 } 553 554 return ipmi::responseSuccess(dataOut); 555 } 556 557 /** @brief implements mdr2 send data info command 558 * @param agentId 559 * @param dataInfo 560 * @param validFlag 561 * @param dataLength 562 * @param dataVersion 563 * @param timeStamp 564 * 565 * @returns IPMI completion code plus response data 566 * - bool 567 */ 568 ipmi::RspType<bool> mdr2SendDataInfo(uint16_t agentId, 569 std::array<uint8_t, dataInfoSize> dataInfo, 570 uint8_t validFlag, uint32_t dataLength, 571 uint32_t dataVersion, uint32_t timeStamp) 572 { 573 if (dataLength > smbiosTableStorageSize) 574 { 575 phosphor::logging::log<phosphor::logging::level::ERR>( 576 "Requested data length is out of SMBIOS Table storage size."); 577 return ipmi::responseParmOutOfRange(); 578 } 579 580 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus(); 581 std::string service = ipmi::getService(*bus, mdrv2Interface, mdrv2Path); 582 583 if (mdrv2 == nullptr) 584 { 585 mdrv2 = std::make_unique<MDRV2>(); 586 } 587 588 int agentIndex = mdrv2->agentLookup(agentId); 589 if (agentIndex == -1) 590 { 591 phosphor::logging::log<phosphor::logging::level::ERR>( 592 "Unknown agent id", phosphor::logging::entry("ID=%x", agentId)); 593 return ipmi::responseParmOutOfRange(); 594 } 595 596 int idIndex = mdrv2->findDataId(dataInfo.data(), dataInfo.size(), service); 597 598 if ((idIndex < 0) || (idIndex >= maxDirEntries)) 599 { 600 phosphor::logging::log<phosphor::logging::level::ERR>( 601 "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex)); 602 return ipmi::responseParmOutOfRange(); 603 } 604 605 sdbusplus::message_t method = bus->new_method_call( 606 service.c_str(), mdrv2Path, mdrv2Interface, "SendDataInformation"); 607 608 method.append((uint8_t)idIndex, validFlag, dataLength, dataVersion, 609 timeStamp); 610 611 bool entryChanged = true; 612 try 613 { 614 sdbusplus::message_t reply = bus->call(method); 615 reply.read(entryChanged); 616 } 617 catch (const sdbusplus::exception_t& e) 618 { 619 phosphor::logging::log<phosphor::logging::level::ERR>( 620 "Error send data info", 621 phosphor::logging::entry("ERROR=%s", e.what()), 622 phosphor::logging::entry("SERVICE=%s", service.c_str()), 623 phosphor::logging::entry("PATH=%s", mdrv2Path)); 624 return ipmi::responseResponseError(); 625 } 626 627 return ipmi::responseSuccess(entryChanged); 628 } 629 630 /** 631 @brief This command is MDR related get data block command. 632 633 @param - agentId 634 @param - lockHandle 635 @param - xferOffset 636 @param - xferLength 637 638 @return on success 639 - xferLength 640 - checksum 641 - data 642 **/ 643 ipmi::RspType<uint32_t, // xferLength 644 uint32_t, // Checksum 645 std::vector<uint8_t> // data 646 > 647 mdr2GetDataBlock(uint16_t agentId, uint16_t lockHandle, uint32_t xferOffset, 648 uint32_t xferLength) 649 { 650 if (mdrv2 == nullptr) 651 { 652 mdrv2 = std::make_unique<MDRV2>(); 653 } 654 655 int agentIndex = mdrv2->agentLookup(agentId); 656 if (agentIndex == -1) 657 { 658 phosphor::logging::log<phosphor::logging::level::ERR>( 659 "Unknown agent id", phosphor::logging::entry("ID=%x", agentId)); 660 return ipmi::responseParmOutOfRange(); 661 } 662 663 int idIndex = mdrv2->findLockHandle(lockHandle); 664 665 if ((idIndex < 0) || (idIndex >= maxDirEntries)) 666 { 667 phosphor::logging::log<phosphor::logging::level::ERR>( 668 "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex)); 669 return ipmi::responseParmOutOfRange(); 670 } 671 672 if (xferOffset >= mdrv2->smbiosDir.dir[idIndex].common.size) 673 { 674 phosphor::logging::log<phosphor::logging::level::ERR>( 675 "Offset is outside of range."); 676 return ipmi::responseParmOutOfRange(); 677 } 678 679 size_t outSize = (xferLength > mdrv2->smbiosDir.dir[idIndex].xferSize) 680 ? mdrv2->smbiosDir.dir[idIndex].xferSize 681 : xferLength; 682 if (outSize > UINT_MAX - xferOffset) 683 { 684 phosphor::logging::log<phosphor::logging::level::ERR>( 685 "Out size and offset are out of range"); 686 return ipmi::responseParmOutOfRange(); 687 } 688 if ((xferOffset + outSize) > mdrv2->smbiosDir.dir[idIndex].common.size) 689 { 690 outSize = mdrv2->smbiosDir.dir[idIndex].common.size - xferOffset; 691 } 692 693 uint32_t respXferLength = outSize; 694 695 if (respXferLength > xferLength) 696 { 697 phosphor::logging::log<phosphor::logging::level::ERR>( 698 "Get data block unexpected error."); 699 return ipmi::responseUnspecifiedError(); 700 } 701 702 if ((xferOffset + outSize) > 703 UINT_MAX - 704 reinterpret_cast<size_t>(mdrv2->smbiosDir.dir[idIndex].dataStorage)) 705 { 706 phosphor::logging::log<phosphor::logging::level::ERR>( 707 "Input data to calculate checksum is out of range"); 708 return ipmi::responseParmOutOfRange(); 709 } 710 711 uint32_t u32Checksum = mdrv2->calcChecksum32( 712 mdrv2->smbiosDir.dir[idIndex].dataStorage + xferOffset, outSize); 713 if (u32Checksum == invalidChecksum) 714 { 715 phosphor::logging::log<phosphor::logging::level::ERR>( 716 "Get data block failed - invalid checksum"); 717 return ipmi::response(ccOemInvalidChecksum); 718 } 719 std::vector<uint8_t> data(outSize); 720 721 std::copy(&mdrv2->smbiosDir.dir[idIndex].dataStorage[xferOffset], 722 &mdrv2->smbiosDir.dir[idIndex].dataStorage[xferOffset + outSize], 723 data.begin()); 724 725 return ipmi::responseSuccess(respXferLength, u32Checksum, data); 726 } 727 728 /** @brief implements mdr2 send data block command 729 * @param agentId 730 * @param lockHandle 731 * @param xferOffset 732 * @param xferLength 733 * @param checksum 734 * 735 * @returns IPMI completion code 736 */ 737 ipmi::RspType<> mdr2SendDataBlock(uint16_t agentId, uint16_t lockHandle, 738 uint32_t xferOffset, uint32_t xferLength, 739 uint32_t checksum) 740 { 741 742 if (mdrv2 == nullptr) 743 { 744 mdrv2 = std::make_unique<MDRV2>(); 745 } 746 747 int agentIndex = mdrv2->agentLookup(agentId); 748 if (agentIndex == -1) 749 { 750 phosphor::logging::log<phosphor::logging::level::ERR>( 751 "Unknown agent id", phosphor::logging::entry("ID=%x", agentId)); 752 return ipmi::responseParmOutOfRange(); 753 } 754 755 int idIndex = mdrv2->findLockHandle(lockHandle); 756 757 if ((idIndex < 0) || (idIndex >= maxDirEntries)) 758 { 759 phosphor::logging::log<phosphor::logging::level::ERR>( 760 "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex)); 761 return ipmi::responseParmOutOfRange(); 762 } 763 764 if (mdrv2->smbiosIsUpdating(idIndex)) 765 { 766 if (xferOffset > UINT_MAX - xferLength) 767 { 768 phosphor::logging::log<phosphor::logging::level::ERR>( 769 "Offset and length are out of range"); 770 return ipmi::responseParmOutOfRange(); 771 } 772 if (((xferOffset + xferLength) > 773 mdrv2->smbiosDir.dir[idIndex].maxDataSize) || 774 ((xferOffset + xferLength) > 775 mdrv2->smbiosDir.dir[idIndex].common.dataSetSize)) 776 { 777 phosphor::logging::log<phosphor::logging::level::ERR>( 778 "Send data block Invalid offset/length"); 779 return ipmi::responseReqDataLenExceeded(); 780 } 781 if (reinterpret_cast<size_t>( 782 mdrv2->smbiosDir.dir[idIndex].dataStorage) > 783 UINT_MAX - xferOffset) 784 { 785 phosphor::logging::log<phosphor::logging::level::ERR>( 786 "Offset is out of range"); 787 return ipmi::responseParmOutOfRange(); 788 } 789 uint8_t* destAddr = 790 mdrv2->smbiosDir.dir[idIndex].dataStorage + xferOffset; 791 uint8_t* sourceAddr = reinterpret_cast<uint8_t*>(mdrv2->area->vPtr); 792 uint32_t calcChecksum = mdrv2->calcChecksum32(sourceAddr, xferLength); 793 if (calcChecksum != checksum) 794 { 795 phosphor::logging::log<phosphor::logging::level::ERR>( 796 "Send data block Invalid checksum"); 797 return ipmi::response(ccOemInvalidChecksum); 798 } 799 else 800 { 801 if (reinterpret_cast<size_t>(sourceAddr) > UINT_MAX - xferLength) 802 { 803 phosphor::logging::log<phosphor::logging::level::ERR>( 804 "Length is out of range"); 805 return ipmi::responseParmOutOfRange(); 806 } 807 std::copy(sourceAddr, sourceAddr + xferLength, destAddr); 808 } 809 } 810 else 811 { 812 phosphor::logging::log<phosphor::logging::level::ERR>( 813 "Send data block failed, other data is updating"); 814 return ipmi::responseDestinationUnavailable(); 815 } 816 817 return ipmi::responseSuccess(); 818 } 819 820 bool MDRV2::storeDatatoFlash(MDRSMBIOSHeader* mdrHdr, uint8_t* data) 821 { 822 std::ofstream smbiosFile(mdrType2File, 823 std::ios_base::binary | std::ios_base::trunc); 824 if (!smbiosFile.good()) 825 { 826 phosphor::logging::log<phosphor::logging::level::ERR>( 827 "Write data from flash error - Open MDRV2 table file failure"); 828 return false; 829 } 830 831 try 832 { 833 smbiosFile.write(reinterpret_cast<char*>(mdrHdr), 834 sizeof(MDRSMBIOSHeader)); 835 smbiosFile.write(reinterpret_cast<char*>(data), mdrHdr->dataSize); 836 } 837 catch (const std::ofstream::failure& e) 838 { 839 phosphor::logging::log<phosphor::logging::level::ERR>( 840 "Write data from flash error - write data error", 841 phosphor::logging::entry("ERROR=%s", e.what())); 842 return false; 843 } 844 845 return true; 846 } 847 848 void SharedMemoryArea::Initialize(uint32_t addr, uint32_t areaSize) 849 { 850 int memDriver = 0; 851 852 // open mem driver for the system memory access 853 memDriver = open("/dev/vgasharedmem", O_RDONLY); 854 if (memDriver < 0) 855 { 856 phosphor::logging::log<phosphor::logging::level::ERR>( 857 "Cannot access mem driver"); 858 throw std::system_error(EIO, std::generic_category()); 859 } 860 861 // map the system memory 862 vPtr = mmap(NULL, // where to map to: don't mind 863 areaSize, // how many bytes ? 864 PROT_READ, // want to read and write 865 MAP_SHARED, // no copy on write 866 memDriver, // handle to /dev/mem 867 (physicalAddr & pageMask)); // hopefully the Text-buffer :-) 868 869 close(memDriver); 870 if (vPtr == MAP_FAILED) 871 { 872 phosphor::logging::log<phosphor::logging::level::ERR>( 873 "Failed to map share memory"); 874 throw std::system_error(EIO, std::generic_category()); 875 } 876 size = areaSize; 877 physicalAddr = addr; 878 } 879 880 bool MDRV2::smbiosUnlock(uint8_t index) 881 { 882 bool ret = false; 883 switch (smbiosDir.dir[index].stage) 884 { 885 case MDR2SMBIOSStatusEnum::mdr2Updating: 886 smbiosDir.dir[index].stage = MDR2SMBIOSStatusEnum::mdr2Updated; 887 smbiosDir.dir[index].lock = MDR2DirLockEnum::mdr2DirUnlock; 888 889 timer->stop(); 890 smbiosDir.dir[index].lockHandle = 0; 891 ret = true; 892 break; 893 894 case MDR2SMBIOSStatusEnum::mdr2Updated: 895 case MDR2SMBIOSStatusEnum::mdr2Loaded: 896 smbiosDir.dir[index].lock = MDR2DirLockEnum::mdr2DirUnlock; 897 898 timer->stop(); 899 900 smbiosDir.dir[index].lockHandle = 0; 901 ret = true; 902 break; 903 904 default: 905 break; 906 } 907 908 return ret; 909 } 910 911 bool MDRV2::smbiosTryLock(uint8_t flag, uint8_t index, uint16_t* session, 912 uint16_t timeout) 913 { 914 bool ret = false; 915 uint32_t u32Status = 0; 916 917 if (timeout == 0) 918 { 919 timeout = defaultTimeout; 920 } 921 std::chrono::microseconds usec(timeout * sysClock); 922 923 switch (smbiosDir.dir[index].stage) 924 { 925 case MDR2SMBIOSStatusEnum::mdr2Updating: 926 if (smbiosDir.dir[index].lock != MDR2DirLockEnum::mdr2DirLock) 927 { 928 smbiosDir.dir[index].lock = MDR2DirLockEnum::mdr2DirLock; 929 timer->start(usec); 930 lockIndex = index; 931 932 *session = getSessionHandle(&smbiosDir); 933 smbiosDir.dir[index].lockHandle = *session; 934 ret = true; 935 } 936 break; 937 case MDR2SMBIOSStatusEnum::mdr2Init: 938 if (flag) 939 { 940 smbiosDir.dir[index].stage = MDR2SMBIOSStatusEnum::mdr2Updating; 941 smbiosDir.dir[index].lock = MDR2DirLockEnum::mdr2DirUnlock; 942 timer->start(usec); 943 lockIndex = index; 944 945 *session = getSessionHandle(&smbiosDir); 946 smbiosDir.dir[index].lockHandle = *session; 947 ret = true; 948 } 949 break; 950 951 case MDR2SMBIOSStatusEnum::mdr2Updated: 952 case MDR2SMBIOSStatusEnum::mdr2Loaded: 953 if (smbiosDir.dir[index].lock != MDR2DirLockEnum::mdr2DirLock) 954 { 955 if (flag) 956 { 957 smbiosDir.dir[index].stage = 958 MDR2SMBIOSStatusEnum::mdr2Updating; 959 smbiosDir.dir[index].lock = MDR2DirLockEnum::mdr2DirUnlock; 960 } 961 else 962 { 963 smbiosDir.dir[index].lock = MDR2DirLockEnum::mdr2DirLock; 964 } 965 966 timer->start(usec); 967 lockIndex = index; 968 969 *session = getSessionHandle(&smbiosDir); 970 smbiosDir.dir[index].lockHandle = *session; 971 ret = true; 972 } 973 break; 974 975 default: 976 break; 977 } 978 return ret; 979 } 980 981 void MDRV2::timeoutHandler() 982 { 983 smbiosUnlock(lockIndex); 984 mdrv2->area.reset(nullptr); 985 } 986 987 /** @brief implements mdr2 lock data command 988 * @param agentId 989 * @param dataInfo 990 * @param timeout 991 * 992 * @returns IPMI completion code plus response data 993 * - mdr2Version 994 * - session 995 * - dataLength 996 * - xferAddress 997 * - xferLength 998 */ 999 ipmi::RspType<uint8_t, // mdr2Version 1000 uint16_t, // session 1001 uint32_t, // dataLength 1002 uint32_t, // xferAddress 1003 uint32_t // xferLength 1004 > 1005 mdr2LockData(uint16_t agentId, std::array<uint8_t, dataInfoSize> dataInfo, 1006 uint16_t timeout) 1007 { 1008 if (mdrv2 == nullptr) 1009 { 1010 mdrv2 = std::make_unique<MDRV2>(); 1011 } 1012 1013 int agentIndex = mdrv2->agentLookup(agentId); 1014 if (agentIndex == -1) 1015 { 1016 phosphor::logging::log<phosphor::logging::level::ERR>( 1017 "Unknown agent id", phosphor::logging::entry("ID=%x", agentId)); 1018 return ipmi::responseParmOutOfRange(); 1019 } 1020 1021 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus(); 1022 std::string service = ipmi::getService(*bus, mdrv2Interface, mdrv2Path); 1023 1024 int idIndex = mdrv2->findDataId(dataInfo.data(), dataInfo.size(), service); 1025 1026 if ((idIndex < 0) || (idIndex >= maxDirEntries)) 1027 { 1028 phosphor::logging::log<phosphor::logging::level::ERR>( 1029 "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex)); 1030 return ipmi::responseParmOutOfRange(); 1031 } 1032 1033 uint16_t session = 0; 1034 if (!mdrv2->smbiosTryLock(0, idIndex, &session, timeout)) 1035 { 1036 phosphor::logging::log<phosphor::logging::level::ERR>( 1037 "Lock Data failed - cannot lock idIndex"); 1038 return ipmi::responseCommandNotAvailable(); 1039 } 1040 1041 uint32_t dataLength = mdrv2->smbiosDir.dir[idIndex].common.size; 1042 uint32_t xferAddress = mdrv2->smbiosDir.dir[idIndex].xferBuff; 1043 uint32_t xferLength = mdrv2->smbiosDir.dir[idIndex].xferSize; 1044 1045 return ipmi::responseSuccess(mdr2Version, session, dataLength, xferAddress, 1046 xferLength); 1047 } 1048 1049 /** @brief implements mdr2 unlock data command 1050 * @param agentId 1051 * @param lockHandle 1052 * 1053 * @returns IPMI completion code 1054 */ 1055 ipmi::RspType<> mdr2UnlockData(uint16_t agentId, uint16_t lockHandle) 1056 { 1057 phosphor::logging::log<phosphor::logging::level::ERR>("unlock data"); 1058 1059 if (mdrv2 == nullptr) 1060 { 1061 mdrv2 = std::make_unique<MDRV2>(); 1062 } 1063 1064 int agentIndex = mdrv2->agentLookup(agentId); 1065 if (agentIndex == -1) 1066 { 1067 phosphor::logging::log<phosphor::logging::level::ERR>( 1068 "Unknown agent id", phosphor::logging::entry("ID=%x", agentId)); 1069 return ipmi::responseParmOutOfRange(); 1070 } 1071 1072 int idIndex = mdrv2->findLockHandle(lockHandle); 1073 1074 if ((idIndex < 0) || (idIndex >= maxDirEntries)) 1075 { 1076 phosphor::logging::log<phosphor::logging::level::ERR>( 1077 "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex)); 1078 return ipmi::responseParmOutOfRange(); 1079 } 1080 1081 if (!mdrv2->smbiosUnlock(idIndex)) 1082 { 1083 phosphor::logging::log<phosphor::logging::level::ERR>( 1084 "Unlock Data failed - cannot unlock idIndex"); 1085 return ipmi::responseCommandNotAvailable(); 1086 } 1087 1088 return ipmi::responseSuccess(); 1089 } 1090 1091 /** 1092 @brief This command is executed after POST BIOS to get the session info. 1093 1094 @param - agentId, dataInfo, dataLength, xferAddress, xferLength, timeout. 1095 1096 @return xferStartAck and session on success. 1097 **/ 1098 ipmi::RspType<uint8_t, uint16_t> 1099 cmd_mdr2_data_start(uint16_t agentId, std::array<uint8_t, 16> dataInfo, 1100 uint32_t dataLength, uint32_t xferAddress, 1101 uint32_t xferLength, uint16_t timeout) 1102 { 1103 uint16_t session = 0; 1104 1105 if (dataLength > smbiosTableStorageSize) 1106 { 1107 phosphor::logging::log<phosphor::logging::level::ERR>( 1108 "Requested data length is out of SMBIOS Table storage size."); 1109 return ipmi::responseParmOutOfRange(); 1110 } 1111 if ((xferLength + xferAddress) > mdriiSMSize) 1112 { 1113 phosphor::logging::log<phosphor::logging::level::ERR>( 1114 "Invalid data address and size"); 1115 return ipmi::responseParmOutOfRange(); 1116 } 1117 1118 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus(); 1119 std::string service = ipmi::getService(*bus, mdrv2Interface, mdrv2Path); 1120 1121 if (mdrv2 == nullptr) 1122 { 1123 mdrv2 = std::make_unique<MDRV2>(); 1124 } 1125 1126 int agentIndex = mdrv2->agentLookup(agentId); 1127 if (agentIndex == -1) 1128 { 1129 phosphor::logging::log<phosphor::logging::level::ERR>( 1130 "Unknown agent id", phosphor::logging::entry("ID=%x", agentId)); 1131 return ipmi::responseParmOutOfRange(); 1132 } 1133 1134 int idIndex = mdrv2->findDataId(dataInfo.data(), dataInfo.size(), service); 1135 1136 if ((idIndex < 0) || (idIndex >= maxDirEntries)) 1137 { 1138 phosphor::logging::log<phosphor::logging::level::ERR>( 1139 "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex)); 1140 return ipmi::responseParmOutOfRange(); 1141 } 1142 1143 if (mdrv2->smbiosTryLock(1, idIndex, &session, timeout)) 1144 { 1145 try 1146 { 1147 mdrv2->area = 1148 std::make_unique<SharedMemoryArea>(xferAddress, xferLength); 1149 } 1150 catch (const std::system_error& e) 1151 { 1152 mdrv2->smbiosUnlock(idIndex); 1153 phosphor::logging::log<phosphor::logging::level::ERR>( 1154 "Unable to access share memory", 1155 phosphor::logging::entry("ERROR=%s", e.what())); 1156 return ipmi::responseUnspecifiedError(); 1157 } 1158 mdrv2->smbiosDir.dir[idIndex].common.size = dataLength; 1159 mdrv2->smbiosDir.dir[idIndex].lockHandle = session; 1160 if (-1 == 1161 mdrv2->syncDirCommonData( 1162 idIndex, mdrv2->smbiosDir.dir[idIndex].common.size, service)) 1163 { 1164 phosphor::logging::log<phosphor::logging::level::ERR>( 1165 "Unable to sync data to service"); 1166 return ipmi::responseResponseError(); 1167 } 1168 } 1169 else 1170 { 1171 phosphor::logging::log<phosphor::logging::level::ERR>( 1172 "Canot lock smbios"); 1173 return ipmi::responseUnspecifiedError(); 1174 } 1175 1176 static constexpr uint8_t xferStartAck = 1; 1177 1178 return ipmi::responseSuccess(xferStartAck, session); 1179 } 1180 1181 /** 1182 @brief This command is executed to close the session. 1183 1184 @param - agentId, lockHandle. 1185 1186 @return completion code on success. 1187 **/ 1188 ipmi::RspType<> cmd_mdr2_data_done(uint16_t agentId, uint16_t lockHandle) 1189 { 1190 1191 if (mdrv2 == nullptr) 1192 { 1193 mdrv2 = std::make_unique<MDRV2>(); 1194 } 1195 1196 int agentIndex = mdrv2->agentLookup(agentId); 1197 if (agentIndex == -1) 1198 { 1199 phosphor::logging::log<phosphor::logging::level::ERR>( 1200 "Unknown agent id", phosphor::logging::entry("ID=%x", agentId)); 1201 return ipmi::responseParmOutOfRange(); 1202 } 1203 1204 int idIndex = mdrv2->findLockHandle(lockHandle); 1205 1206 if ((idIndex < 0) || (idIndex >= maxDirEntries)) 1207 { 1208 phosphor::logging::log<phosphor::logging::level::ERR>( 1209 "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex)); 1210 return ipmi::responseParmOutOfRange(); 1211 } 1212 1213 if (!mdrv2->smbiosUnlock(idIndex)) 1214 { 1215 phosphor::logging::log<phosphor::logging::level::ERR>( 1216 "Send data done failed - cannot unlock idIndex"); 1217 return ipmi::responseDestinationUnavailable(); 1218 } 1219 1220 mdrv2->area.reset(nullptr); 1221 MDRSMBIOSHeader mdr2Smbios; 1222 mdr2Smbios.mdrType = mdrTypeII; 1223 mdr2Smbios.dirVer = mdrv2->smbiosDir.dir[0].common.dataVersion; 1224 mdr2Smbios.timestamp = mdrv2->smbiosDir.dir[0].common.timestamp; 1225 mdr2Smbios.dataSize = mdrv2->smbiosDir.dir[0].common.size; 1226 1227 if (access(smbiosPath, 0) == -1) 1228 { 1229 int flag = mkdir(smbiosPath, S_IRWXU); 1230 if (flag != 0) 1231 { 1232 phosphor::logging::log<phosphor::logging::level::ERR>( 1233 "create folder failed for writting smbios file"); 1234 } 1235 } 1236 if (!mdrv2->storeDatatoFlash( 1237 &mdr2Smbios, mdrv2->smbiosDir.dir[smbiosDirIndex].dataStorage)) 1238 { 1239 phosphor::logging::log<phosphor::logging::level::ERR>( 1240 "MDR2 Store data to flash failed"); 1241 return ipmi::responseDestinationUnavailable(); 1242 } 1243 bool status = false; 1244 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus(); 1245 std::string service = ipmi::getService(*bus, mdrv2Interface, mdrv2Path); 1246 sdbusplus::message_t method = bus->new_method_call( 1247 service.c_str(), mdrv2Path, mdrv2Interface, "AgentSynchronizeData"); 1248 1249 try 1250 { 1251 sdbusplus::message_t reply = bus->call(method); 1252 reply.read(status); 1253 } 1254 catch (const sdbusplus::exception_t& e) 1255 { 1256 phosphor::logging::log<phosphor::logging::level::ERR>( 1257 "Error Sync data with service", 1258 phosphor::logging::entry("ERROR=%s", e.what()), 1259 phosphor::logging::entry("SERVICE=%s", service.c_str()), 1260 phosphor::logging::entry("PATH=%s", mdrv2Path)); 1261 return ipmi::responseResponseError(); 1262 } 1263 1264 if (!status) 1265 { 1266 phosphor::logging::log<phosphor::logging::level::ERR>( 1267 "Sync data with service failure"); 1268 return ipmi::responseUnspecifiedError(); 1269 } 1270 1271 return ipmi::responseSuccess(); 1272 } 1273 1274 static void register_netfn_smbiosmdrv2_functions(void) 1275 { 1276 // MDR V2 Command 1277 // <Get MDRII Status Command> 1278 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp, 1279 ipmi::intel::app::cmdMdrIIAgentStatus, 1280 ipmi::Privilege::Operator, mdr2AgentStatus); 1281 1282 // <Get MDRII Directory Command> 1283 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp, 1284 ipmi::intel::app::cmdMdrIIGetDir, 1285 ipmi::Privilege::Operator, mdr2GetDir); 1286 1287 // <Send MDRII Directory Command> 1288 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp, 1289 ipmi::intel::app::cmdMdrIISendDir, 1290 ipmi::Privilege::Operator, mdr2SendDir); 1291 1292 // <Get MDRII Data Info Command> 1293 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp, 1294 ipmi::intel::app::cmdMdrIIGetDataInfo, 1295 ipmi::Privilege::Operator, mdr2GetDataInfo); 1296 1297 // <Send MDRII Info Offer> 1298 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp, 1299 ipmi::intel::app::cmdMdrIISendDataInfoOffer, 1300 ipmi::Privilege::Operator, mdr2DataInfoOffer); 1301 1302 // <Send MDRII Data Info> 1303 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp, 1304 ipmi::intel::app::cmdMdrIISendDataInfo, 1305 ipmi::Privilege::Operator, mdr2SendDataInfo); 1306 1307 // <Get MDRII Data Block Command> 1308 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp, 1309 ipmi::intel::app::cmdMdrIIGetDataBlock, 1310 ipmi::Privilege::Operator, mdr2GetDataBlock); 1311 1312 // <Send MDRII Data Block> 1313 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp, 1314 ipmi::intel::app::cmdMdrIISendDataBlock, 1315 ipmi::Privilege::Operator, mdr2SendDataBlock); 1316 1317 // <Lock MDRII Data Command> 1318 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp, 1319 ipmi::intel::app::cmdMdrIILockData, 1320 ipmi::Privilege::Operator, mdr2LockData); 1321 1322 // <Unlock MDRII Data Command> 1323 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp, 1324 ipmi::intel::app::cmdMdrIIUnlockData, 1325 ipmi::Privilege::Operator, mdr2UnlockData); 1326 1327 // <Send MDRII Data Start> 1328 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp, 1329 ipmi::intel::app::cmdMdrIIDataStart, 1330 ipmi::Privilege::Operator, cmd_mdr2_data_start); 1331 1332 // <Send MDRII Data Done> 1333 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp, 1334 ipmi::intel::app::cmdMdrIIDataDone, 1335 ipmi::Privilege::Operator, cmd_mdr2_data_done); 1336 } 1337