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
agentLookup(const uint16_t & agentId)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
sdplusMdrv2GetProperty(const std::string & name,ipmi::DbusVariant & value,const std::string & service)62 int MDRV2::sdplusMdrv2GetProperty(const std::string& name,
63 ipmi::DbusVariant& 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
syncDirCommonData(uint8_t idIndex,uint32_t size,const std::string & service)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
findDataId(const uint8_t * dataInfo,const size_t & len,const std::string & service)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
getSessionHandle(Mdr2DirStruct * dir)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
findLockHandle(const uint16_t & lockHandle)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
smbiosIsUpdating(uint8_t index)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
calcChecksum32(uint8_t * buf,uint32_t len)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>
mdr2AgentStatus(uint16_t agentId,uint8_t dirVersion)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,uint8_t dirIndex)282 mdr2GetDir(uint16_t agentId, 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 ipmi::DbusVariant 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,uint8_t dirIndex,uint8_t returnedEntries,uint8_t remainingEntries,std::vector<uint8_t> dataInfo)373 mdr2SendDir(uint16_t agentId, uint8_t dirVersion, uint8_t dirIndex,
374 uint8_t returnedEntries, 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>>
mdr2GetDataInfo(uint16_t agentId,std::vector<uint8_t> dataInfo)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 */
mdr2DataInfoOffer(uint16_t agentId)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 */
mdr2SendDataInfo(uint16_t agentId,std::array<uint8_t,dataInfoSize> dataInfo,uint8_t validFlag,uint32_t dataLength,uint32_t dataVersion,uint32_t timeStamp)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 >
mdr2GetDataBlock(uint16_t agentId,uint16_t lockHandle,uint32_t xferOffset,uint32_t xferLength)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 */
mdr2SendDataBlock(uint16_t agentId,uint16_t lockHandle,uint32_t xferOffset,uint32_t xferLength,uint32_t checksum)737 ipmi::RspType<> mdr2SendDataBlock(uint16_t agentId, uint16_t lockHandle,
738 uint32_t xferOffset, uint32_t xferLength,
739 uint32_t checksum)
740 {
741 if (mdrv2 == nullptr)
742 {
743 mdrv2 = std::make_unique<MDRV2>();
744 }
745
746 int agentIndex = mdrv2->agentLookup(agentId);
747 if (agentIndex == -1)
748 {
749 phosphor::logging::log<phosphor::logging::level::ERR>(
750 "Unknown agent id", phosphor::logging::entry("ID=%x", agentId));
751 return ipmi::responseParmOutOfRange();
752 }
753
754 int idIndex = mdrv2->findLockHandle(lockHandle);
755
756 if ((idIndex < 0) || (idIndex >= maxDirEntries))
757 {
758 phosphor::logging::log<phosphor::logging::level::ERR>(
759 "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex));
760 return ipmi::responseParmOutOfRange();
761 }
762
763 if (mdrv2->smbiosIsUpdating(idIndex))
764 {
765 if (xferOffset > UINT_MAX - xferLength)
766 {
767 phosphor::logging::log<phosphor::logging::level::ERR>(
768 "Offset and length are out of range");
769 return ipmi::responseParmOutOfRange();
770 }
771 if (((xferOffset + xferLength) >
772 mdrv2->smbiosDir.dir[idIndex].maxDataSize) ||
773 ((xferOffset + xferLength) >
774 mdrv2->smbiosDir.dir[idIndex].common.dataSetSize))
775 {
776 phosphor::logging::log<phosphor::logging::level::ERR>(
777 "Send data block Invalid offset/length");
778 return ipmi::responseReqDataLenExceeded();
779 }
780 if (reinterpret_cast<size_t>(
781 mdrv2->smbiosDir.dir[idIndex].dataStorage) >
782 UINT_MAX - xferOffset)
783 {
784 phosphor::logging::log<phosphor::logging::level::ERR>(
785 "Offset is out of range");
786 return ipmi::responseParmOutOfRange();
787 }
788 uint8_t* destAddr =
789 mdrv2->smbiosDir.dir[idIndex].dataStorage + xferOffset;
790 uint8_t* sourceAddr = reinterpret_cast<uint8_t*>(mdrv2->area->vPtr);
791 uint32_t calcChecksum = mdrv2->calcChecksum32(sourceAddr, xferLength);
792 if (calcChecksum != checksum)
793 {
794 phosphor::logging::log<phosphor::logging::level::ERR>(
795 "Send data block Invalid checksum");
796 return ipmi::response(ccOemInvalidChecksum);
797 }
798 else
799 {
800 if (reinterpret_cast<size_t>(sourceAddr) > UINT_MAX - xferLength)
801 {
802 phosphor::logging::log<phosphor::logging::level::ERR>(
803 "Length is out of range");
804 return ipmi::responseParmOutOfRange();
805 }
806 std::copy(sourceAddr, sourceAddr + xferLength, destAddr);
807 }
808 }
809 else
810 {
811 phosphor::logging::log<phosphor::logging::level::ERR>(
812 "Send data block failed, other data is updating");
813 return ipmi::responseDestinationUnavailable();
814 }
815
816 return ipmi::responseSuccess();
817 }
818
storeDatatoFlash(MDRSMBIOSHeader * mdrHdr,uint8_t * data)819 bool MDRV2::storeDatatoFlash(MDRSMBIOSHeader* mdrHdr, uint8_t* data)
820 {
821 std::ofstream smbiosFile(mdrType2File,
822 std::ios_base::binary | std::ios_base::trunc);
823 if (!smbiosFile.good())
824 {
825 phosphor::logging::log<phosphor::logging::level::ERR>(
826 "Write data from flash error - Open MDRV2 table file failure");
827 return false;
828 }
829
830 try
831 {
832 smbiosFile.write(reinterpret_cast<char*>(mdrHdr),
833 sizeof(MDRSMBIOSHeader));
834 smbiosFile.write(reinterpret_cast<char*>(data), mdrHdr->dataSize);
835 }
836 catch (const std::ofstream::failure& e)
837 {
838 phosphor::logging::log<phosphor::logging::level::ERR>(
839 "Write data from flash error - write data error",
840 phosphor::logging::entry("ERROR=%s", e.what()));
841 return false;
842 }
843
844 return true;
845 }
846
Initialize(uint32_t addr,uint32_t areaSize)847 void SharedMemoryArea::Initialize(uint32_t addr, uint32_t areaSize)
848 {
849 int memDriver = 0;
850
851 // open mem driver for the system memory access
852 memDriver = open("/dev/vgasharedmem", O_RDONLY);
853 if (memDriver < 0)
854 {
855 phosphor::logging::log<phosphor::logging::level::ERR>(
856 "Cannot access mem driver");
857 throw std::system_error(EIO, std::generic_category());
858 }
859
860 // map the system memory
861 vPtr = mmap(NULL, // where to map to: don't mind
862 areaSize, // how many bytes ?
863 PROT_READ, // want to read and write
864 MAP_SHARED, // no copy on write
865 memDriver, // handle to /dev/mem
866 (physicalAddr & pageMask)); // hopefully the Text-buffer :-)
867
868 close(memDriver);
869 if (vPtr == MAP_FAILED)
870 {
871 phosphor::logging::log<phosphor::logging::level::ERR>(
872 "Failed to map share memory");
873 throw std::system_error(EIO, std::generic_category());
874 }
875 size = areaSize;
876 physicalAddr = addr;
877 }
878
smbiosUnlock(uint8_t index)879 bool MDRV2::smbiosUnlock(uint8_t index)
880 {
881 bool ret = false;
882 switch (smbiosDir.dir[index].stage)
883 {
884 case MDR2SMBIOSStatusEnum::mdr2Updating:
885 smbiosDir.dir[index].stage = MDR2SMBIOSStatusEnum::mdr2Updated;
886 smbiosDir.dir[index].lock = MDR2DirLockEnum::mdr2DirUnlock;
887
888 timer->stop();
889 smbiosDir.dir[index].lockHandle = 0;
890 ret = true;
891 break;
892
893 case MDR2SMBIOSStatusEnum::mdr2Updated:
894 case MDR2SMBIOSStatusEnum::mdr2Loaded:
895 smbiosDir.dir[index].lock = MDR2DirLockEnum::mdr2DirUnlock;
896
897 timer->stop();
898
899 smbiosDir.dir[index].lockHandle = 0;
900 ret = true;
901 break;
902
903 default:
904 break;
905 }
906
907 return ret;
908 }
909
smbiosTryLock(uint8_t flag,uint8_t index,uint16_t * session,uint16_t timeout)910 bool MDRV2::smbiosTryLock(uint8_t flag, uint8_t index, uint16_t* session,
911 uint16_t timeout)
912 {
913 bool ret = false;
914
915 if (timeout == 0)
916 {
917 timeout = defaultTimeout;
918 }
919 std::chrono::microseconds usec(timeout * sysClock);
920
921 switch (smbiosDir.dir[index].stage)
922 {
923 case MDR2SMBIOSStatusEnum::mdr2Updating:
924 if (smbiosDir.dir[index].lock != MDR2DirLockEnum::mdr2DirLock)
925 {
926 smbiosDir.dir[index].lock = MDR2DirLockEnum::mdr2DirLock;
927 timer->start(usec);
928 lockIndex = index;
929
930 *session = getSessionHandle(&smbiosDir);
931 smbiosDir.dir[index].lockHandle = *session;
932 ret = true;
933 }
934 break;
935 case MDR2SMBIOSStatusEnum::mdr2Init:
936 if (flag)
937 {
938 smbiosDir.dir[index].stage = MDR2SMBIOSStatusEnum::mdr2Updating;
939 smbiosDir.dir[index].lock = MDR2DirLockEnum::mdr2DirUnlock;
940 timer->start(usec);
941 lockIndex = index;
942
943 *session = getSessionHandle(&smbiosDir);
944 smbiosDir.dir[index].lockHandle = *session;
945 ret = true;
946 }
947 break;
948
949 case MDR2SMBIOSStatusEnum::mdr2Updated:
950 case MDR2SMBIOSStatusEnum::mdr2Loaded:
951 if (smbiosDir.dir[index].lock != MDR2DirLockEnum::mdr2DirLock)
952 {
953 if (flag)
954 {
955 smbiosDir.dir[index].stage =
956 MDR2SMBIOSStatusEnum::mdr2Updating;
957 smbiosDir.dir[index].lock = MDR2DirLockEnum::mdr2DirUnlock;
958 }
959 else
960 {
961 smbiosDir.dir[index].lock = MDR2DirLockEnum::mdr2DirLock;
962 }
963
964 timer->start(usec);
965 lockIndex = index;
966
967 *session = getSessionHandle(&smbiosDir);
968 smbiosDir.dir[index].lockHandle = *session;
969 ret = true;
970 }
971 break;
972
973 default:
974 break;
975 }
976 return ret;
977 }
978
timeoutHandler()979 void MDRV2::timeoutHandler()
980 {
981 smbiosUnlock(lockIndex);
982 mdrv2->area.reset(nullptr);
983 }
984
985 /** @brief implements mdr2 lock data command
986 * @param agentId
987 * @param dataInfo
988 * @param timeout
989 *
990 * @returns IPMI completion code plus response data
991 * - mdr2Version
992 * - session
993 * - dataLength
994 * - xferAddress
995 * - xferLength
996 */
997 ipmi::RspType<uint8_t, // mdr2Version
998 uint16_t, // session
999 uint32_t, // dataLength
1000 uint32_t, // xferAddress
1001 uint32_t // xferLength
1002 >
mdr2LockData(uint16_t agentId,std::array<uint8_t,dataInfoSize> dataInfo,uint16_t timeout)1003 mdr2LockData(uint16_t agentId, std::array<uint8_t, dataInfoSize> dataInfo,
1004 uint16_t timeout)
1005 {
1006 if (mdrv2 == nullptr)
1007 {
1008 mdrv2 = std::make_unique<MDRV2>();
1009 }
1010
1011 int agentIndex = mdrv2->agentLookup(agentId);
1012 if (agentIndex == -1)
1013 {
1014 phosphor::logging::log<phosphor::logging::level::ERR>(
1015 "Unknown agent id", phosphor::logging::entry("ID=%x", agentId));
1016 return ipmi::responseParmOutOfRange();
1017 }
1018
1019 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
1020 std::string service = ipmi::getService(*bus, mdrv2Interface, mdrv2Path);
1021
1022 int idIndex = mdrv2->findDataId(dataInfo.data(), dataInfo.size(), service);
1023
1024 if ((idIndex < 0) || (idIndex >= maxDirEntries))
1025 {
1026 phosphor::logging::log<phosphor::logging::level::ERR>(
1027 "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex));
1028 return ipmi::responseParmOutOfRange();
1029 }
1030
1031 uint16_t session = 0;
1032 if (!mdrv2->smbiosTryLock(0, idIndex, &session, timeout))
1033 {
1034 phosphor::logging::log<phosphor::logging::level::ERR>(
1035 "Lock Data failed - cannot lock idIndex");
1036 return ipmi::responseCommandNotAvailable();
1037 }
1038
1039 uint32_t dataLength = mdrv2->smbiosDir.dir[idIndex].common.size;
1040 uint32_t xferAddress = mdrv2->smbiosDir.dir[idIndex].xferBuff;
1041 uint32_t xferLength = mdrv2->smbiosDir.dir[idIndex].xferSize;
1042
1043 return ipmi::responseSuccess(mdr2Version, session, dataLength, xferAddress,
1044 xferLength);
1045 }
1046
1047 /** @brief implements mdr2 unlock data command
1048 * @param agentId
1049 * @param lockHandle
1050 *
1051 * @returns IPMI completion code
1052 */
mdr2UnlockData(uint16_t agentId,uint16_t lockHandle)1053 ipmi::RspType<> mdr2UnlockData(uint16_t agentId, uint16_t lockHandle)
1054 {
1055 phosphor::logging::log<phosphor::logging::level::ERR>("unlock data");
1056
1057 if (mdrv2 == nullptr)
1058 {
1059 mdrv2 = std::make_unique<MDRV2>();
1060 }
1061
1062 int agentIndex = mdrv2->agentLookup(agentId);
1063 if (agentIndex == -1)
1064 {
1065 phosphor::logging::log<phosphor::logging::level::ERR>(
1066 "Unknown agent id", phosphor::logging::entry("ID=%x", agentId));
1067 return ipmi::responseParmOutOfRange();
1068 }
1069
1070 int idIndex = mdrv2->findLockHandle(lockHandle);
1071
1072 if ((idIndex < 0) || (idIndex >= maxDirEntries))
1073 {
1074 phosphor::logging::log<phosphor::logging::level::ERR>(
1075 "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex));
1076 return ipmi::responseParmOutOfRange();
1077 }
1078
1079 if (!mdrv2->smbiosUnlock(idIndex))
1080 {
1081 phosphor::logging::log<phosphor::logging::level::ERR>(
1082 "Unlock Data failed - cannot unlock idIndex");
1083 return ipmi::responseCommandNotAvailable();
1084 }
1085
1086 return ipmi::responseSuccess();
1087 }
1088
1089 /**
1090 @brief This command is executed after POST BIOS to get the session info.
1091
1092 @param - agentId, dataInfo, dataLength, xferAddress, xferLength, timeout.
1093
1094 @return xferStartAck and session on success.
1095 **/
cmd_mdr2_data_start(uint16_t agentId,std::array<uint8_t,16> dataInfo,uint32_t dataLength,uint32_t xferAddress,uint32_t xferLength,uint16_t timeout)1096 ipmi::RspType<uint8_t, uint16_t> cmd_mdr2_data_start(
1097 uint16_t agentId, std::array<uint8_t, 16> dataInfo, uint32_t dataLength,
1098 uint32_t xferAddress, uint32_t xferLength, uint16_t timeout)
1099 {
1100 uint16_t session = 0;
1101
1102 if (dataLength > smbiosTableStorageSize)
1103 {
1104 phosphor::logging::log<phosphor::logging::level::ERR>(
1105 "Requested data length is out of SMBIOS Table storage size.");
1106 return ipmi::responseParmOutOfRange();
1107 }
1108 if ((xferLength + xferAddress) > mdriiSMSize)
1109 {
1110 phosphor::logging::log<phosphor::logging::level::ERR>(
1111 "Invalid data address and size");
1112 return ipmi::responseParmOutOfRange();
1113 }
1114
1115 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
1116 std::string service = ipmi::getService(*bus, mdrv2Interface, mdrv2Path);
1117
1118 if (mdrv2 == nullptr)
1119 {
1120 mdrv2 = std::make_unique<MDRV2>();
1121 }
1122
1123 int agentIndex = mdrv2->agentLookup(agentId);
1124 if (agentIndex == -1)
1125 {
1126 phosphor::logging::log<phosphor::logging::level::ERR>(
1127 "Unknown agent id", phosphor::logging::entry("ID=%x", agentId));
1128 return ipmi::responseParmOutOfRange();
1129 }
1130
1131 int idIndex = mdrv2->findDataId(dataInfo.data(), dataInfo.size(), service);
1132
1133 if ((idIndex < 0) || (idIndex >= maxDirEntries))
1134 {
1135 phosphor::logging::log<phosphor::logging::level::ERR>(
1136 "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex));
1137 return ipmi::responseParmOutOfRange();
1138 }
1139
1140 if (mdrv2->smbiosTryLock(1, idIndex, &session, timeout))
1141 {
1142 try
1143 {
1144 mdrv2->area =
1145 std::make_unique<SharedMemoryArea>(xferAddress, xferLength);
1146 }
1147 catch (const std::system_error& e)
1148 {
1149 mdrv2->smbiosUnlock(idIndex);
1150 phosphor::logging::log<phosphor::logging::level::ERR>(
1151 "Unable to access share memory",
1152 phosphor::logging::entry("ERROR=%s", e.what()));
1153 return ipmi::responseUnspecifiedError();
1154 }
1155 mdrv2->smbiosDir.dir[idIndex].common.size = dataLength;
1156 mdrv2->smbiosDir.dir[idIndex].lockHandle = session;
1157 if (-1 ==
1158 mdrv2->syncDirCommonData(
1159 idIndex, mdrv2->smbiosDir.dir[idIndex].common.size, service))
1160 {
1161 phosphor::logging::log<phosphor::logging::level::ERR>(
1162 "Unable to sync data to service");
1163 return ipmi::responseResponseError();
1164 }
1165 }
1166 else
1167 {
1168 phosphor::logging::log<phosphor::logging::level::ERR>(
1169 "Canot lock smbios");
1170 return ipmi::responseUnspecifiedError();
1171 }
1172
1173 static constexpr uint8_t xferStartAck = 1;
1174
1175 return ipmi::responseSuccess(xferStartAck, session);
1176 }
1177
1178 /**
1179 @brief This command is executed to close the session.
1180
1181 @param - agentId, lockHandle.
1182
1183 @return completion code on success.
1184 **/
cmd_mdr2_data_done(uint16_t agentId,uint16_t lockHandle)1185 ipmi::RspType<> cmd_mdr2_data_done(uint16_t agentId, uint16_t lockHandle)
1186 {
1187 if (mdrv2 == nullptr)
1188 {
1189 mdrv2 = std::make_unique<MDRV2>();
1190 }
1191
1192 int agentIndex = mdrv2->agentLookup(agentId);
1193 if (agentIndex == -1)
1194 {
1195 phosphor::logging::log<phosphor::logging::level::ERR>(
1196 "Unknown agent id", phosphor::logging::entry("ID=%x", agentId));
1197 return ipmi::responseParmOutOfRange();
1198 }
1199
1200 int idIndex = mdrv2->findLockHandle(lockHandle);
1201
1202 if ((idIndex < 0) || (idIndex >= maxDirEntries))
1203 {
1204 phosphor::logging::log<phosphor::logging::level::ERR>(
1205 "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex));
1206 return ipmi::responseParmOutOfRange();
1207 }
1208
1209 if (!mdrv2->smbiosUnlock(idIndex))
1210 {
1211 phosphor::logging::log<phosphor::logging::level::ERR>(
1212 "Send data done failed - cannot unlock idIndex");
1213 return ipmi::responseDestinationUnavailable();
1214 }
1215
1216 mdrv2->area.reset(nullptr);
1217 MDRSMBIOSHeader mdr2Smbios;
1218 mdr2Smbios.mdrType = mdrTypeII;
1219 mdr2Smbios.dirVer = mdrv2->smbiosDir.dir[0].common.dataVersion;
1220 mdr2Smbios.timestamp = mdrv2->smbiosDir.dir[0].common.timestamp;
1221 mdr2Smbios.dataSize = mdrv2->smbiosDir.dir[0].common.size;
1222
1223 if (access(smbiosPath, 0) == -1)
1224 {
1225 int flag = mkdir(smbiosPath, S_IRWXU);
1226 if (flag != 0)
1227 {
1228 phosphor::logging::log<phosphor::logging::level::ERR>(
1229 "create folder failed for writting smbios file");
1230 }
1231 }
1232 if (!mdrv2->storeDatatoFlash(
1233 &mdr2Smbios, mdrv2->smbiosDir.dir[smbiosDirIndex].dataStorage))
1234 {
1235 phosphor::logging::log<phosphor::logging::level::ERR>(
1236 "MDR2 Store data to flash failed");
1237 return ipmi::responseDestinationUnavailable();
1238 }
1239 bool status = false;
1240 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
1241 std::string service = ipmi::getService(*bus, mdrv2Interface, mdrv2Path);
1242 sdbusplus::message_t method = bus->new_method_call(
1243 service.c_str(), mdrv2Path, mdrv2Interface, "AgentSynchronizeData");
1244
1245 try
1246 {
1247 sdbusplus::message_t reply = bus->call(method);
1248 reply.read(status);
1249 }
1250 catch (const sdbusplus::exception_t& e)
1251 {
1252 phosphor::logging::log<phosphor::logging::level::ERR>(
1253 "Error Sync data with service",
1254 phosphor::logging::entry("ERROR=%s", e.what()),
1255 phosphor::logging::entry("SERVICE=%s", service.c_str()),
1256 phosphor::logging::entry("PATH=%s", mdrv2Path));
1257 return ipmi::responseResponseError();
1258 }
1259
1260 if (!status)
1261 {
1262 phosphor::logging::log<phosphor::logging::level::ERR>(
1263 "Sync data with service failure");
1264 return ipmi::responseUnspecifiedError();
1265 }
1266
1267 return ipmi::responseSuccess();
1268 }
1269
register_netfn_smbiosmdrv2_functions(void)1270 static void register_netfn_smbiosmdrv2_functions(void)
1271 {
1272 // MDR V2 Command
1273 // <Get MDRII Status Command>
1274 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp,
1275 ipmi::intel::app::cmdMdrIIAgentStatus,
1276 ipmi::Privilege::Operator, mdr2AgentStatus);
1277
1278 // <Get MDRII Directory Command>
1279 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp,
1280 ipmi::intel::app::cmdMdrIIGetDir,
1281 ipmi::Privilege::Operator, mdr2GetDir);
1282
1283 // <Send MDRII Directory Command>
1284 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp,
1285 ipmi::intel::app::cmdMdrIISendDir,
1286 ipmi::Privilege::Operator, mdr2SendDir);
1287
1288 // <Get MDRII Data Info Command>
1289 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp,
1290 ipmi::intel::app::cmdMdrIIGetDataInfo,
1291 ipmi::Privilege::Operator, mdr2GetDataInfo);
1292
1293 // <Send MDRII Info Offer>
1294 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp,
1295 ipmi::intel::app::cmdMdrIISendDataInfoOffer,
1296 ipmi::Privilege::Operator, mdr2DataInfoOffer);
1297
1298 // <Send MDRII Data Info>
1299 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp,
1300 ipmi::intel::app::cmdMdrIISendDataInfo,
1301 ipmi::Privilege::Operator, mdr2SendDataInfo);
1302
1303 // <Get MDRII Data Block Command>
1304 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp,
1305 ipmi::intel::app::cmdMdrIIGetDataBlock,
1306 ipmi::Privilege::Operator, mdr2GetDataBlock);
1307
1308 // <Send MDRII Data Block>
1309 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp,
1310 ipmi::intel::app::cmdMdrIISendDataBlock,
1311 ipmi::Privilege::Operator, mdr2SendDataBlock);
1312
1313 // <Lock MDRII Data Command>
1314 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp,
1315 ipmi::intel::app::cmdMdrIILockData,
1316 ipmi::Privilege::Operator, mdr2LockData);
1317
1318 // <Unlock MDRII Data Command>
1319 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp,
1320 ipmi::intel::app::cmdMdrIIUnlockData,
1321 ipmi::Privilege::Operator, mdr2UnlockData);
1322
1323 // <Send MDRII Data Start>
1324 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp,
1325 ipmi::intel::app::cmdMdrIIDataStart,
1326 ipmi::Privilege::Operator, cmd_mdr2_data_start);
1327
1328 // <Send MDRII Data Done>
1329 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp,
1330 ipmi::intel::app::cmdMdrIIDataDone,
1331 ipmi::Privilege::Operator, cmd_mdr2_data_done);
1332 }
1333