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 ipmi_ret_t cmd_mdr2_get_data_info(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
403                                   ipmi_request_t request,
404                                   ipmi_response_t response,
405                                   ipmi_data_len_t data_len,
406                                   ipmi_context_t context)
407 {
408     auto requestData =
409         reinterpret_cast<const MDRiiGetDataInfoRequest *>(request);
410     auto dataOut = reinterpret_cast<uint8_t *>(response);
411     std::vector<uint8_t> res;
412 
413     if (*data_len < sizeof(MDRiiGetDataInfoRequest))
414     {
415         *data_len = 0;
416         return IPMI_CC_REQ_DATA_LEN_INVALID;
417     }
418 
419     *data_len = 0;
420 
421     std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
422     std::string service = ipmi::getService(*bus, mdrv2Interface, mdrv2Path);
423 
424     if (mdrv2 == nullptr)
425     {
426         mdrv2 = std::make_unique<MDRV2>();
427     }
428 
429     int agentIndex = mdrv2->agentLookup(requestData->agentId);
430     if (agentIndex == -1)
431     {
432         phosphor::logging::log<phosphor::logging::level::ERR>(
433             "Unknown agent id",
434             phosphor::logging::entry("ID=%x", requestData->agentId));
435         return IPMI_CC_PARM_OUT_OF_RANGE;
436     }
437 
438     int idIndex =
439         mdrv2->findDataId(requestData->dataSetInfo.dataInfo,
440                           sizeof(requestData->dataSetInfo.dataInfo), service);
441 
442     if ((idIndex < 0) || (idIndex >= maxDirEntries))
443     {
444         phosphor::logging::log<phosphor::logging::level::ERR>(
445             "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex));
446         return IPMI_CC_PARM_OUT_OF_RANGE;
447     }
448 
449     sdbusplus::message::message method = bus->new_method_call(
450         service.c_str(), mdrv2Path, mdrv2Interface, "GetDataInformation");
451 
452     method.append(idIndex);
453 
454     try
455     {
456         sdbusplus::message::message reply = bus->call(method);
457         reply.read(res);
458     }
459     catch (sdbusplus::exception_t &e)
460     {
461         phosphor::logging::log<phosphor::logging::level::ERR>(
462             "Error get data info",
463             phosphor::logging::entry("ERROR=%s", e.what()),
464             phosphor::logging::entry("SERVICE=%s", service.c_str()),
465             phosphor::logging::entry("PATH=%s", mdrv2Path));
466         return IPMI_CC_RESPONSE_ERROR;
467     }
468 
469     if (res.size() != sizeof(MDRiiGetDataInfoResponse))
470     {
471         phosphor::logging::log<phosphor::logging::level::ERR>(
472             "Get data info response length not invalid");
473         return IPMI_CC_UNSPECIFIED_ERROR;
474     }
475     *data_len = static_cast<size_t>(res.size());
476     std::copy(&res[0], &res[*data_len], dataOut);
477 
478     return IPMI_CC_OK;
479 }
480 
481 /** @brief implements mdr2 data info offer command
482  *  @param agentId - Offer a agent ID to get the "Data Set ID"
483  *
484  *  @returns IPMI completion code plus response data
485  *  - dataOut - data Set Id
486  */
487 ipmi::RspType<std::vector<uint8_t>> mdr2DataInfoOffer(uint16_t agentId)
488 {
489     std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
490     std::string service = ipmi::getService(*bus, mdrv2Interface, mdrv2Path);
491 
492     if (mdrv2 == nullptr)
493     {
494         mdrv2 = std::make_unique<MDRV2>();
495     }
496 
497     int agentIndex = mdrv2->agentLookup(agentId);
498     if (agentIndex == -1)
499     {
500         phosphor::logging::log<phosphor::logging::level::ERR>(
501             "Unknown agent id", phosphor::logging::entry("ID=%x", agentId));
502         return ipmi::responseParmOutOfRange();
503     }
504 
505     sdbusplus::message::message method = bus->new_method_call(
506         service.c_str(), mdrv2Path, mdrv2Interface, "GetDataOffer");
507 
508     std::vector<uint8_t> dataOut;
509     try
510     {
511         sdbusplus::message::message reply = bus->call(method);
512         reply.read(dataOut);
513     }
514     catch (sdbusplus::exception_t &e)
515     {
516         phosphor::logging::log<phosphor::logging::level::ERR>(
517             "Error send data info offer",
518             phosphor::logging::entry("ERROR=%s", e.what()),
519             phosphor::logging::entry("SERVICE=%s", service.c_str()),
520             phosphor::logging::entry("PATH=%s", mdrv2Path));
521         return ipmi::responseResponseError();
522     }
523 
524     constexpr size_t respInfoSize = 16;
525     if (dataOut.size() != respInfoSize)
526     {
527         phosphor::logging::log<phosphor::logging::level::ERR>(
528             "Error send data info offer, return length invalid");
529         return ipmi::responseUnspecifiedError();
530     }
531 
532     return ipmi::responseSuccess(dataOut);
533 }
534 
535 ipmi_ret_t cmd_mdr2_send_data_info(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
536                                    ipmi_request_t request,
537                                    ipmi_response_t response,
538                                    ipmi_data_len_t data_len,
539                                    ipmi_context_t context)
540 {
541     auto requestData =
542         reinterpret_cast<const MDRiiSendDataInfoRequest *>(request);
543     bool entryChanged = true;
544 
545     if (*data_len != sizeof(MDRiiSendDataInfoRequest))
546     {
547         *data_len = 0;
548         return IPMI_CC_REQ_DATA_LEN_INVALID;
549     }
550 
551     *data_len = 0;
552 
553     if (requestData->dataLength > smbiosTableStorageSize)
554     {
555         phosphor::logging::log<phosphor::logging::level::ERR>(
556             "Requested data length is out of SMBIOS Table storage size.");
557         return IPMI_CC_PARM_OUT_OF_RANGE;
558     }
559 
560     std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
561     std::string service = ipmi::getService(*bus, mdrv2Interface, mdrv2Path);
562 
563     if (mdrv2 == nullptr)
564     {
565         mdrv2 = std::make_unique<MDRV2>();
566     }
567 
568     int agentIndex = mdrv2->agentLookup(requestData->agentId);
569     if (agentIndex == -1)
570     {
571         phosphor::logging::log<phosphor::logging::level::ERR>(
572             "Unknown agent id",
573             phosphor::logging::entry("ID=%x", requestData->agentId));
574         return IPMI_CC_PARM_OUT_OF_RANGE;
575     }
576 
577     int idIndex =
578         mdrv2->findDataId(requestData->dataSetInfo.dataInfo,
579                           sizeof(requestData->dataSetInfo.dataInfo), service);
580 
581     if ((idIndex < 0) || (idIndex >= maxDirEntries))
582     {
583         phosphor::logging::log<phosphor::logging::level::ERR>(
584             "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex));
585         return IPMI_CC_PARM_OUT_OF_RANGE;
586     }
587 
588     sdbusplus::message::message method = bus->new_method_call(
589         service.c_str(), mdrv2Path, mdrv2Interface, "SendDataInformation");
590 
591     method.append((uint8_t)idIndex, requestData->validFlag,
592                   requestData->dataLength, requestData->dataVersion,
593                   requestData->timeStamp);
594 
595     try
596     {
597         sdbusplus::message::message reply = bus->call(method);
598         reply.read(entryChanged);
599     }
600     catch (sdbusplus::exception_t &e)
601     {
602         phosphor::logging::log<phosphor::logging::level::ERR>(
603             "Error send data info",
604             phosphor::logging::entry("ERROR=%s", e.what()),
605             phosphor::logging::entry("SERVICE=%s", service.c_str()),
606             phosphor::logging::entry("PATH=%s", mdrv2Path));
607         return IPMI_CC_RESPONSE_ERROR;
608     }
609 
610     *data_len = 1;
611 
612     if (entryChanged)
613     {
614         *(static_cast<uint8_t *>(response)) = 1;
615     }
616     else
617     {
618         *(static_cast<uint8_t *>(response)) = 0;
619     }
620 
621     return IPMI_CC_OK;
622 }
623 
624 ipmi_ret_t cmd_mdr2_get_data_block(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
625                                    ipmi_request_t request,
626                                    ipmi_response_t response,
627                                    ipmi_data_len_t data_len,
628                                    ipmi_context_t context)
629 {
630     auto requestData =
631         reinterpret_cast<const MDRiiGetDataBlockRequest *>(request);
632     auto responseData = reinterpret_cast<MDRiiGetDataBlockResponse *>(response);
633     std::tuple<uint8_t, uint32_t, uint32_t, std::vector<uint8_t>> res;
634     std::vector<uint8_t> resData;
635     uint8_t status = 1;
636 
637     if (*data_len != sizeof(MDRiiGetDataBlockRequest))
638     {
639         *data_len = 0;
640         return IPMI_CC_REQ_DATA_LEN_INVALID;
641     }
642 
643     *data_len = 0;
644 
645     if (mdrv2 == nullptr)
646     {
647         mdrv2 = std::make_unique<MDRV2>();
648     }
649 
650     int agentIndex = mdrv2->agentLookup(requestData->agentId);
651     if (agentIndex == -1)
652     {
653         phosphor::logging::log<phosphor::logging::level::ERR>(
654             "Unknown agent id",
655             phosphor::logging::entry("ID=%x", requestData->agentId));
656         return IPMI_CC_PARM_OUT_OF_RANGE;
657     }
658 
659     int idIndex = mdrv2->findLockHandle(requestData->lockHandle);
660 
661     if ((idIndex < 0) || (idIndex >= maxDirEntries))
662     {
663         phosphor::logging::log<phosphor::logging::level::ERR>(
664             "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex));
665         return IPMI_CC_PARM_OUT_OF_RANGE;
666     }
667 
668     if (requestData->xferOffset >= mdrv2->smbiosDir.dir[idIndex].common.size)
669     {
670         phosphor::logging::log<phosphor::logging::level::ERR>(
671             "Offset is outside of range.");
672         return IPMI_CC_PARM_OUT_OF_RANGE;
673     }
674 
675     size_t outSize =
676         (requestData->xferLength > mdrv2->smbiosDir.dir[idIndex].xferSize)
677             ? mdrv2->smbiosDir.dir[idIndex].xferSize
678             : requestData->xferLength;
679     if (outSize > UINT_MAX - requestData->xferOffset)
680     {
681         phosphor::logging::log<phosphor::logging::level::ERR>(
682             "Out size and offset are out of range");
683         return IPMI_CC_PARM_OUT_OF_RANGE;
684     }
685     if ((requestData->xferOffset + outSize) >
686         mdrv2->smbiosDir.dir[idIndex].common.size)
687     {
688         outSize =
689             mdrv2->smbiosDir.dir[idIndex].common.size - requestData->xferOffset;
690     }
691 
692     responseData->xferLength = outSize;
693     if (responseData->xferLength > requestData->xferLength)
694     {
695         phosphor::logging::log<phosphor::logging::level::ERR>(
696             "Get data block unexpected error.");
697         return IPMI_CC_UNSPECIFIED_ERROR;
698     }
699 
700     if ((requestData->xferOffset + outSize) >
701         UINT_MAX -
702             reinterpret_cast<size_t>(mdrv2->smbiosDir.dir[idIndex].dataStorage))
703     {
704         phosphor::logging::log<phosphor::logging::level::ERR>(
705             "Input data to calculate checksum is out of range");
706         return IPMI_CC_PARM_OUT_OF_RANGE;
707     }
708 
709     uint32_t u32Checksum = mdrv2->calcChecksum32(
710         mdrv2->smbiosDir.dir[idIndex].dataStorage + requestData->xferOffset,
711         outSize);
712     if (u32Checksum == invalidChecksum)
713     {
714         phosphor::logging::log<phosphor::logging::level::ERR>(
715             "Get data block failed - invalid checksum");
716         return IPMI_CC_OEM_INVALID_CHECKSUM;
717     }
718     responseData->checksum = u32Checksum;
719 
720     *data_len = sizeof(responseData->xferLength) +
721                 sizeof(responseData->checksum) + outSize;
722 
723     if (*data_len > MAX_IPMI_BUFFER) // length + completion code should no more
724                                      // than MAX_IPMI_BUFFER
725     {
726         phosphor::logging::log<phosphor::logging::level::ERR>(
727             "Data length send from service is invalid");
728         *data_len = 0;
729         return IPMI_CC_RESPONSE_ERROR;
730     }
731 
732     std::copy(
733         &mdrv2->smbiosDir.dir[idIndex].dataStorage[requestData->xferOffset],
734         &mdrv2->smbiosDir.dir[idIndex]
735              .dataStorage[requestData->xferOffset + outSize],
736         responseData->data);
737 
738     return IPMI_CC_OK;
739 }
740 
741 /** @brief implements mdr2 send data block command
742  *  @param agentId
743  *  @param lockHandle
744  *  @param xferOffset
745  *  @param xferLength
746  *  @param checksum
747  *
748  *  @returns IPMI completion code
749  */
750 ipmi::RspType<> mdr2SendDataBlock(uint16_t agentId, uint16_t lockHandle,
751                                   uint32_t xferOffset, uint32_t xferLength,
752                                   uint32_t checksum)
753 {
754     if (mdrv2 == nullptr)
755     {
756         mdrv2 = std::make_unique<MDRV2>();
757     }
758 
759     int agentIndex = mdrv2->agentLookup(agentId);
760     if (agentIndex == -1)
761     {
762         phosphor::logging::log<phosphor::logging::level::ERR>(
763             "Unknown agent id", phosphor::logging::entry("ID=%x", agentId));
764         return ipmi::responseParmOutOfRange();
765     }
766 
767     int idIndex = mdrv2->findLockHandle(lockHandle);
768 
769     if ((idIndex < 0) || (idIndex >= maxDirEntries))
770     {
771         phosphor::logging::log<phosphor::logging::level::ERR>(
772             "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex));
773         return ipmi::responseParmOutOfRange();
774     }
775 
776     if (mdrv2->smbiosIsUpdating(idIndex))
777     {
778         if (xferOffset > UINT_MAX - xferLength)
779         {
780             phosphor::logging::log<phosphor::logging::level::ERR>(
781                 "Offset and length are out of range");
782             return ipmi::responseParmOutOfRange();
783         }
784         if (((xferOffset + xferLength) >
785              mdrv2->smbiosDir.dir[idIndex].maxDataSize) ||
786             ((xferOffset + xferLength) >
787              mdrv2->smbiosDir.dir[idIndex].common.dataSetSize))
788         {
789             phosphor::logging::log<phosphor::logging::level::ERR>(
790                 "Send data block Invalid offset/length");
791             return ipmi::responseReqDataLenExceeded();
792         }
793         if (reinterpret_cast<size_t>(
794                 mdrv2->smbiosDir.dir[idIndex].dataStorage) >
795             UINT_MAX - xferOffset)
796         {
797             phosphor::logging::log<phosphor::logging::level::ERR>(
798                 "Offset is out of range");
799             return ipmi::responseParmOutOfRange();
800         }
801         uint8_t *destAddr =
802             mdrv2->smbiosDir.dir[idIndex].dataStorage + xferOffset;
803         uint8_t *sourceAddr = reinterpret_cast<uint8_t *>(mdrv2->area->vPtr);
804         uint32_t calcChecksum = mdrv2->calcChecksum32(sourceAddr, xferLength);
805         if (calcChecksum != checksum)
806         {
807             phosphor::logging::log<phosphor::logging::level::ERR>(
808                 "Send data block Invalid checksum");
809             return ipmi::response(ccOemInvalidChecksum);
810         }
811         else
812         {
813             if (reinterpret_cast<size_t>(sourceAddr) > UINT_MAX - xferLength)
814             {
815                 phosphor::logging::log<phosphor::logging::level::ERR>(
816                     "Length is out of range");
817                 return ipmi::responseParmOutOfRange();
818             }
819             std::copy(sourceAddr, sourceAddr + xferLength, destAddr);
820         }
821     }
822     else
823     {
824         phosphor::logging::log<phosphor::logging::level::ERR>(
825             "Send data block failed, other data is updating");
826         return ipmi::responseDestinationUnavailable();
827     }
828 
829     return ipmi::responseSuccess();
830 }
831 
832 bool MDRV2::storeDatatoFlash(MDRSMBIOSHeader *mdrHdr, uint8_t *data)
833 {
834     std::ofstream smbiosFile(mdrType2File,
835                              std::ios_base::binary | std::ios_base::trunc);
836     if (!smbiosFile.good())
837     {
838         phosphor::logging::log<phosphor::logging::level::ERR>(
839             "Write data from flash error - Open MDRV2 table file failure");
840         return false;
841     }
842 
843     try
844     {
845         smbiosFile.write(reinterpret_cast<char *>(mdrHdr),
846                          sizeof(MDRSMBIOSHeader));
847         smbiosFile.write(reinterpret_cast<char *>(data), mdrHdr->dataSize);
848     }
849     catch (std::ofstream::failure &e)
850     {
851         phosphor::logging::log<phosphor::logging::level::ERR>(
852             "Write data from flash error - write data error",
853             phosphor::logging::entry("ERROR=%s", e.what()));
854         return false;
855     }
856 
857     return true;
858 }
859 
860 void SharedMemoryArea::Initialize(uint32_t addr, uint32_t areaSize)
861 {
862     int memDriver = 0;
863 
864     // open mem driver for the system memory access
865     memDriver = open("/dev/vgasharedmem", O_RDONLY);
866     if (memDriver < 0)
867     {
868         phosphor::logging::log<phosphor::logging::level::ERR>(
869             "Cannot access mem driver");
870         throw std::system_error(EIO, std::generic_category());
871     }
872 
873     // map the system memory
874     vPtr = mmap(NULL,                       // where to map to: don't mind
875                 areaSize,                   // how many bytes ?
876                 PROT_READ,                  // want to read and write
877                 MAP_SHARED,                 // no copy on write
878                 memDriver,                  // handle to /dev/mem
879                 (physicalAddr & pageMask)); // hopefully the Text-buffer :-)
880 
881     close(memDriver);
882     if (vPtr == MAP_FAILED)
883     {
884         phosphor::logging::log<phosphor::logging::level::ERR>(
885             "Failed to map share memory");
886         throw std::system_error(EIO, std::generic_category());
887     }
888     size = areaSize;
889     physicalAddr = addr;
890 }
891 
892 bool MDRV2::smbiosUnlock(uint8_t index)
893 {
894     bool ret;
895     switch (smbiosDir.dir[index].stage)
896     {
897         case MDR2SMBIOSStatusEnum::mdr2Updating:
898             smbiosDir.dir[index].stage = MDR2SMBIOSStatusEnum::mdr2Updated;
899             smbiosDir.dir[index].lock = MDR2DirLockEnum::mdr2DirUnlock;
900 
901             timer->stop();
902             smbiosDir.dir[index].lockHandle = 0;
903             ret = true;
904             break;
905 
906         case MDR2SMBIOSStatusEnum::mdr2Updated:
907         case MDR2SMBIOSStatusEnum::mdr2Loaded:
908             smbiosDir.dir[index].lock = MDR2DirLockEnum::mdr2DirUnlock;
909 
910             timer->stop();
911 
912             smbiosDir.dir[index].lockHandle = 0;
913             ret = true;
914             break;
915 
916         default:
917             break;
918     }
919 
920     return ret;
921 }
922 
923 bool MDRV2::smbiosTryLock(uint8_t flag, uint8_t index, uint16_t *session,
924                           uint16_t timeout)
925 {
926     bool ret = false;
927     uint32_t u32Status = 0;
928 
929     if (timeout == 0)
930     {
931         timeout = defaultTimeout;
932     }
933     std::chrono::microseconds usec(timeout * sysClock);
934 
935     switch (smbiosDir.dir[index].stage)
936     {
937         case MDR2SMBIOSStatusEnum::mdr2Updating:
938             if (smbiosDir.dir[index].lock != MDR2DirLockEnum::mdr2DirLock)
939             {
940                 smbiosDir.dir[index].lock = MDR2DirLockEnum::mdr2DirLock;
941                 timer->start(usec);
942                 lockIndex = index;
943 
944                 *session = getSessionHandle(&smbiosDir);
945                 smbiosDir.dir[index].lockHandle = *session;
946                 ret = true;
947             }
948             break;
949         case MDR2SMBIOSStatusEnum::mdr2Init:
950             if (flag)
951             {
952                 smbiosDir.dir[index].stage = MDR2SMBIOSStatusEnum::mdr2Updating;
953                 smbiosDir.dir[index].lock = MDR2DirLockEnum::mdr2DirUnlock;
954                 timer->start(usec);
955                 lockIndex = index;
956 
957                 *session = getSessionHandle(&smbiosDir);
958                 smbiosDir.dir[index].lockHandle = *session;
959                 ret = true;
960             }
961             break;
962 
963         case MDR2SMBIOSStatusEnum::mdr2Updated:
964         case MDR2SMBIOSStatusEnum::mdr2Loaded:
965             if (smbiosDir.dir[index].lock != MDR2DirLockEnum::mdr2DirLock)
966             {
967                 if (flag)
968                 {
969                     smbiosDir.dir[index].stage =
970                         MDR2SMBIOSStatusEnum::mdr2Updating;
971                     smbiosDir.dir[index].lock = MDR2DirLockEnum::mdr2DirUnlock;
972                 }
973                 else
974                 {
975                     smbiosDir.dir[index].lock = MDR2DirLockEnum::mdr2DirLock;
976                 }
977 
978                 timer->start(usec);
979                 lockIndex = index;
980 
981                 *session = getSessionHandle(&smbiosDir);
982                 smbiosDir.dir[index].lockHandle = *session;
983                 ret = true;
984             }
985             break;
986 
987         default:
988             break;
989     }
990     return ret;
991 }
992 
993 void MDRV2::timeoutHandler()
994 {
995     smbiosUnlock(lockIndex);
996     mdrv2->area.reset(nullptr);
997 }
998 
999 /** @brief implements mdr2 lock data command
1000  *  @param agentId
1001  *  @param dataInfo
1002  *  @param timeout
1003  *
1004  *  @returns IPMI completion code plus response data
1005  *  - mdr2Version
1006  *  - session
1007  *  - dataLength
1008  *  - xferAddress
1009  *  - xferLength
1010  */
1011 ipmi::RspType<uint8_t,  // mdr2Version
1012               uint16_t, // session
1013               uint32_t, // dataLength
1014               uint32_t, // xferAddress
1015               uint32_t  // xferLength
1016               >
1017     mdr2LockData(uint16_t agentId, std::array<uint8_t, dataInfoSize> dataInfo,
1018                  uint16_t timeout)
1019 {
1020     if (mdrv2 == nullptr)
1021     {
1022         mdrv2 = std::make_unique<MDRV2>();
1023     }
1024 
1025     int agentIndex = mdrv2->agentLookup(agentId);
1026     if (agentIndex == -1)
1027     {
1028         phosphor::logging::log<phosphor::logging::level::ERR>(
1029             "Unknown agent id", phosphor::logging::entry("ID=%x", agentId));
1030         return ipmi::responseParmOutOfRange();
1031     }
1032 
1033     std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
1034     std::string service = ipmi::getService(*bus, mdrv2Interface, mdrv2Path);
1035 
1036     int idIndex = mdrv2->findDataId(dataInfo.data(), sizeof(dataInfo), service);
1037 
1038     if ((idIndex < 0) || (idIndex >= maxDirEntries))
1039     {
1040         phosphor::logging::log<phosphor::logging::level::ERR>(
1041             "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex));
1042         return ipmi::responseParmOutOfRange();
1043     }
1044 
1045     uint16_t session = 0;
1046     if (!mdrv2->smbiosTryLock(0, idIndex, &session, timeout))
1047     {
1048         phosphor::logging::log<phosphor::logging::level::ERR>(
1049             "Lock Data failed - cannot lock idIndex");
1050         return ipmi::responseCommandNotAvailable();
1051     }
1052 
1053     uint32_t dataLength = mdrv2->smbiosDir.dir[idIndex].common.size;
1054     uint32_t xferAddress = mdrv2->smbiosDir.dir[idIndex].xferBuff;
1055     uint32_t xferLength = mdrv2->smbiosDir.dir[idIndex].xferSize;
1056 
1057     return ipmi::responseSuccess(mdr2Version, session, dataLength, xferAddress,
1058                                  xferLength);
1059 }
1060 
1061 /** @brief implements mdr2 unlock data command
1062  *  @param agentId
1063  *  @param lockHandle
1064  *
1065  *  @returns IPMI completion code
1066  */
1067 ipmi::RspType<> mdr2UnlockData(uint16_t agentId, uint16_t lockHandle)
1068 {
1069     phosphor::logging::log<phosphor::logging::level::ERR>("unlock data");
1070 
1071     if (mdrv2 == nullptr)
1072     {
1073         mdrv2 = std::make_unique<MDRV2>();
1074     }
1075 
1076     int agentIndex = mdrv2->agentLookup(agentId);
1077     if (agentIndex == -1)
1078     {
1079         phosphor::logging::log<phosphor::logging::level::ERR>(
1080             "Unknown agent id", phosphor::logging::entry("ID=%x", agentId));
1081         return ipmi::responseParmOutOfRange();
1082     }
1083 
1084     int idIndex = mdrv2->findLockHandle(lockHandle);
1085 
1086     if ((idIndex < 0) || (idIndex >= maxDirEntries))
1087     {
1088         phosphor::logging::log<phosphor::logging::level::ERR>(
1089             "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex));
1090         return ipmi::responseParmOutOfRange();
1091     }
1092 
1093     if (!mdrv2->smbiosUnlock(idIndex))
1094     {
1095         phosphor::logging::log<phosphor::logging::level::ERR>(
1096             "Unlock Data failed - cannot unlock idIndex");
1097         return ipmi::responseCommandNotAvailable();
1098     }
1099 
1100     return ipmi::responseSuccess();
1101 }
1102 
1103 /**
1104 @brief This command is executed after POST BIOS to get the session info.
1105 
1106 @param - agentId, dataInfo, dataLength, xferAddress, xferLength, timeout.
1107 
1108 @return xferStartAck and session on success.
1109 **/
1110 ipmi::RspType<uint8_t, uint16_t>
1111     cmd_mdr2_data_start(uint16_t agentId, std::array<uint8_t, 16> dataInfo,
1112                         uint32_t dataLength, uint32_t xferAddress,
1113                         uint32_t xferLength, uint16_t timeout)
1114 {
1115     uint16_t session = 0;
1116 
1117     if (dataLength > smbiosTableStorageSize)
1118     {
1119         phosphor::logging::log<phosphor::logging::level::ERR>(
1120             "Requested data length is out of SMBIOS Table storage size.");
1121         return ipmi::responseParmOutOfRange();
1122     }
1123     if ((xferLength + xferAddress) > mdriiSMSize)
1124     {
1125         phosphor::logging::log<phosphor::logging::level::ERR>(
1126             "Invalid data address and size");
1127         return ipmi::responseParmOutOfRange();
1128     }
1129 
1130     std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
1131     std::string service = ipmi::getService(*bus, mdrv2Interface, mdrv2Path);
1132 
1133     if (mdrv2 == nullptr)
1134     {
1135         mdrv2 = std::make_unique<MDRV2>();
1136     }
1137 
1138     int agentIndex = mdrv2->agentLookup(agentId);
1139     if (agentIndex == -1)
1140     {
1141         phosphor::logging::log<phosphor::logging::level::ERR>(
1142             "Unknown agent id", phosphor::logging::entry("ID=%x", agentId));
1143         return ipmi::responseParmOutOfRange();
1144     }
1145 
1146     int idIndex = mdrv2->findDataId(dataInfo.data(), sizeof(dataInfo), service);
1147 
1148     if ((idIndex < 0) || (idIndex >= maxDirEntries))
1149     {
1150         phosphor::logging::log<phosphor::logging::level::ERR>(
1151             "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex));
1152         return ipmi::responseParmOutOfRange();
1153     }
1154 
1155     if (mdrv2->smbiosTryLock(1, idIndex, &session, timeout))
1156     {
1157         try
1158         {
1159             mdrv2->area =
1160                 std::make_unique<SharedMemoryArea>(xferAddress, xferLength);
1161         }
1162         catch (const std::system_error &e)
1163         {
1164             mdrv2->smbiosUnlock(idIndex);
1165             phosphor::logging::log<phosphor::logging::level::ERR>(
1166                 "Unable to access share memory",
1167                 phosphor::logging::entry("ERROR=%s", e.what()));
1168             return ipmi::responseUnspecifiedError();
1169         }
1170         mdrv2->smbiosDir.dir[idIndex].common.size = dataLength;
1171         mdrv2->smbiosDir.dir[idIndex].lockHandle = session;
1172         if (-1 ==
1173             mdrv2->syncDirCommonData(
1174                 idIndex, mdrv2->smbiosDir.dir[idIndex].common.size, service))
1175         {
1176             phosphor::logging::log<phosphor::logging::level::ERR>(
1177                 "Unable to sync data to service");
1178             return ipmi::responseResponseError();
1179         }
1180     }
1181     else
1182     {
1183         phosphor::logging::log<phosphor::logging::level::ERR>(
1184             "Canot lock smbios");
1185         return ipmi::responseUnspecifiedError();
1186     }
1187 
1188     static constexpr uint8_t xferStartAck = 1;
1189 
1190     return ipmi::responseSuccess(xferStartAck, session);
1191 }
1192 
1193 /**
1194 @brief This command is executed to close the session.
1195 
1196 @param - agentId, lockHandle.
1197 
1198 @return completion code on success.
1199 **/
1200 ipmi::RspType<> cmd_mdr2_data_done(uint16_t agentId, uint16_t lockHandle)
1201 {
1202 
1203     if (mdrv2 == nullptr)
1204     {
1205         mdrv2 = std::make_unique<MDRV2>();
1206     }
1207 
1208     int agentIndex = mdrv2->agentLookup(agentId);
1209     if (agentIndex == -1)
1210     {
1211         phosphor::logging::log<phosphor::logging::level::ERR>(
1212             "Unknown agent id", phosphor::logging::entry("ID=%x", agentId));
1213         return ipmi::responseParmOutOfRange();
1214     }
1215 
1216     int idIndex = mdrv2->findLockHandle(lockHandle);
1217 
1218     if ((idIndex < 0) || (idIndex >= maxDirEntries))
1219     {
1220         phosphor::logging::log<phosphor::logging::level::ERR>(
1221             "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex));
1222         return ipmi::responseParmOutOfRange();
1223     }
1224 
1225     if (!mdrv2->smbiosUnlock(idIndex))
1226     {
1227         phosphor::logging::log<phosphor::logging::level::ERR>(
1228             "Send data done failed - cannot unlock idIndex");
1229         return ipmi::responseDestinationUnavailable();
1230     }
1231 
1232     mdrv2->area.reset(nullptr);
1233     MDRSMBIOSHeader mdr2Smbios;
1234     mdr2Smbios.mdrType = mdrTypeII;
1235     mdr2Smbios.dirVer = mdrv2->smbiosDir.dir[0].common.dataVersion;
1236     mdr2Smbios.timestamp = mdrv2->smbiosDir.dir[0].common.timestamp;
1237     mdr2Smbios.dataSize = mdrv2->smbiosDir.dir[0].common.size;
1238 
1239     if (access(smbiosPath, 0) == -1)
1240     {
1241         int flag = mkdir(smbiosPath, S_IRWXU);
1242         if (flag != 0)
1243         {
1244             phosphor::logging::log<phosphor::logging::level::ERR>(
1245                 "create folder failed for writting smbios file");
1246         }
1247     }
1248     if (!mdrv2->storeDatatoFlash(
1249             &mdr2Smbios, mdrv2->smbiosDir.dir[smbiosDirIndex].dataStorage))
1250     {
1251         phosphor::logging::log<phosphor::logging::level::ERR>(
1252             "MDR2 Store data to flash failed");
1253         return ipmi::responseDestinationUnavailable();
1254     }
1255     bool status = false;
1256     std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
1257     std::string service = ipmi::getService(*bus, mdrv2Interface, mdrv2Path);
1258     sdbusplus::message::message method = bus->new_method_call(
1259         service.c_str(), mdrv2Path, mdrv2Interface, "AgentSynchronizeData");
1260 
1261     try
1262     {
1263         sdbusplus::message::message reply = bus->call(method);
1264         reply.read(status);
1265     }
1266     catch (sdbusplus::exception_t &e)
1267     {
1268         phosphor::logging::log<phosphor::logging::level::ERR>(
1269             "Error Sync data with service",
1270             phosphor::logging::entry("ERROR=%s", e.what()),
1271             phosphor::logging::entry("SERVICE=%s", service.c_str()),
1272             phosphor::logging::entry("PATH=%s", mdrv2Path));
1273         return ipmi::responseResponseError();
1274     }
1275 
1276     if (!status)
1277     {
1278         phosphor::logging::log<phosphor::logging::level::ERR>(
1279             "Sync data with service failure");
1280         return ipmi::responseUnspecifiedError();
1281     }
1282 
1283     return ipmi::responseSuccess();
1284 }
1285 
1286 static void register_netfn_smbiosmdrv2_functions(void)
1287 {
1288     // MDR V2 Command
1289     // <Get MDRII Status Command>
1290     ipmi::registerHandler(ipmi::prioOemBase, NETFUN_INTEL_APP_OEM,
1291                           IPMI_NETFN_INTEL_OEM_APP_CMD::MDRII_AGENT_STATUS,
1292                           ipmi::Privilege::Operator, mdr2AgentStatus);
1293 
1294     // <Get MDRII Directory Command>
1295     ipmi::registerHandler(ipmi::prioOemBase, NETFUN_INTEL_APP_OEM,
1296                           IPMI_NETFN_INTEL_OEM_APP_CMD::MDRII_GET_DIR,
1297                           ipmi::Privilege::Operator, mdr2GetDir);
1298 
1299     // <Send MDRII Directory Command>
1300     ipmi::registerHandler(ipmi::prioOemBase, NETFUN_INTEL_APP_OEM,
1301                           IPMI_NETFN_INTEL_OEM_APP_CMD::MDRII_SEND_DIR,
1302                           ipmi::Privilege::Operator, mdr2SendDir);
1303 
1304     // <Get MDRII Data Info Command>
1305     ipmi_register_callback(NETFUN_INTEL_APP_OEM,
1306                            IPMI_NETFN_INTEL_OEM_APP_CMD::MDRII_GET_DATA_INFO,
1307                            NULL, cmd_mdr2_get_data_info, PRIVILEGE_OPERATOR);
1308 
1309     // <Send MDRII Info Offer>
1310     ipmi::registerHandler(
1311         ipmi::prioOemBase, NETFUN_INTEL_APP_OEM,
1312         IPMI_NETFN_INTEL_OEM_APP_CMD::MDRII_SEND_DATA_INFO_OFFER,
1313         ipmi::Privilege::Operator, mdr2DataInfoOffer);
1314 
1315     // <Send MDRII Data Info>
1316     ipmi_register_callback(NETFUN_INTEL_APP_OEM,
1317                            IPMI_NETFN_INTEL_OEM_APP_CMD::MDRII_SEND_DATA_INFO,
1318                            NULL, cmd_mdr2_send_data_info, PRIVILEGE_OPERATOR);
1319 
1320     // <Get MDRII Data Block Command>
1321     ipmi_register_callback(NETFUN_INTEL_APP_OEM,
1322                            IPMI_NETFN_INTEL_OEM_APP_CMD::MDRII_GET_DATA_BLOCK,
1323                            NULL, cmd_mdr2_get_data_block, PRIVILEGE_OPERATOR);
1324 
1325     // <Send MDRII Data Block>
1326     ipmi::registerHandler(ipmi::prioOemBase, NETFUN_INTEL_APP_OEM,
1327                           IPMI_NETFN_INTEL_OEM_APP_CMD::MDRII_SEND_DATA_BLOCK,
1328                           ipmi::Privilege::Operator, mdr2SendDataBlock);
1329 
1330     // <Lock MDRII Data Command>
1331     ipmi::registerHandler(ipmi::prioOemBase, NETFUN_INTEL_APP_OEM,
1332                           IPMI_NETFN_INTEL_OEM_APP_CMD::MDRII_LOCK_DATA,
1333                           ipmi::Privilege::Operator, mdr2LockData);
1334 
1335     // <Unlock MDRII Data Command>
1336     ipmi::registerHandler(ipmi::prioOemBase, NETFUN_INTEL_APP_OEM,
1337                           IPMI_NETFN_INTEL_OEM_APP_CMD::MDRII_UNLOCK_DATA,
1338                           ipmi::Privilege::Operator, mdr2UnlockData);
1339 
1340     // <Send MDRII Data Start>
1341     ipmi::registerHandler(ipmi::prioOemBase, NETFUN_INTEL_APP_OEM,
1342                           IPMI_NETFN_INTEL_OEM_APP_CMD::MDRII_DATA_START,
1343                           ipmi::Privilege::Operator, cmd_mdr2_data_start);
1344 
1345     // <Send MDRII Data Done>
1346     ipmi::registerHandler(ipmi::prioOemBase, NETFUN_INTEL_APP_OEM,
1347                           IPMI_NETFN_INTEL_OEM_APP_CMD::MDRII_DATA_DONE,
1348                           ipmi::Privilege::Operator, cmd_mdr2_data_done);
1349 }
1350