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