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