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