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