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