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(), dataInfo.size(), 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     if (mdrv2 == nullptr)
625     {
626         mdrv2 = std::make_unique<MDRV2>();
627     }
628 
629     int agentIndex = mdrv2->agentLookup(agentId);
630     if (agentIndex == -1)
631     {
632         phosphor::logging::log<phosphor::logging::level::ERR>(
633             "Unknown agent id", phosphor::logging::entry("ID=%x", agentId));
634         return ipmi::responseParmOutOfRange();
635     }
636 
637     int idIndex = mdrv2->findLockHandle(lockHandle);
638 
639     if ((idIndex < 0) || (idIndex >= maxDirEntries))
640     {
641         phosphor::logging::log<phosphor::logging::level::ERR>(
642             "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex));
643         return ipmi::responseParmOutOfRange();
644     }
645 
646     if (xferOffset >= mdrv2->smbiosDir.dir[idIndex].common.size)
647     {
648         phosphor::logging::log<phosphor::logging::level::ERR>(
649             "Offset is outside of range.");
650         return ipmi::responseParmOutOfRange();
651     }
652 
653     size_t outSize = (xferLength > mdrv2->smbiosDir.dir[idIndex].xferSize)
654                          ? mdrv2->smbiosDir.dir[idIndex].xferSize
655                          : xferLength;
656     if (outSize > UINT_MAX - xferOffset)
657     {
658         phosphor::logging::log<phosphor::logging::level::ERR>(
659             "Out size and offset are out of range");
660         return ipmi::responseParmOutOfRange();
661     }
662     if ((xferOffset + outSize) > mdrv2->smbiosDir.dir[idIndex].common.size)
663     {
664         outSize = mdrv2->smbiosDir.dir[idIndex].common.size - xferOffset;
665     }
666 
667     uint32_t respXferLength = outSize;
668 
669     if (respXferLength > xferLength)
670     {
671         phosphor::logging::log<phosphor::logging::level::ERR>(
672             "Get data block unexpected error.");
673         return ipmi::responseUnspecifiedError();
674     }
675 
676     if ((xferOffset + outSize) >
677         UINT_MAX -
678             reinterpret_cast<size_t>(mdrv2->smbiosDir.dir[idIndex].dataStorage))
679     {
680         phosphor::logging::log<phosphor::logging::level::ERR>(
681             "Input data to calculate checksum is out of range");
682         return ipmi::responseParmOutOfRange();
683     }
684 
685     uint32_t u32Checksum = mdrv2->calcChecksum32(
686         mdrv2->smbiosDir.dir[idIndex].dataStorage + xferOffset, outSize);
687     if (u32Checksum == invalidChecksum)
688     {
689         phosphor::logging::log<phosphor::logging::level::ERR>(
690             "Get data block failed - invalid checksum");
691         return ipmi::response(ccOemInvalidChecksum);
692     }
693     std::vector<uint8_t> data(outSize);
694 
695     std::copy(&mdrv2->smbiosDir.dir[idIndex].dataStorage[xferOffset],
696               &mdrv2->smbiosDir.dir[idIndex].dataStorage[xferOffset + outSize],
697               data.begin());
698 
699     return ipmi::responseSuccess(respXferLength, u32Checksum, data);
700 }
701 
702 /** @brief implements mdr2 send data block command
703  *  @param agentId
704  *  @param lockHandle
705  *  @param xferOffset
706  *  @param xferLength
707  *  @param checksum
708  *
709  *  @returns IPMI completion code
710  */
711 ipmi::RspType<> mdr2SendDataBlock(uint16_t agentId, uint16_t lockHandle,
712                                   uint32_t xferOffset, uint32_t xferLength,
713                                   uint32_t checksum)
714 {
715 
716     if (mdrv2 == nullptr)
717     {
718         mdrv2 = std::make_unique<MDRV2>();
719     }
720 
721     int agentIndex = mdrv2->agentLookup(agentId);
722     if (agentIndex == -1)
723     {
724         phosphor::logging::log<phosphor::logging::level::ERR>(
725             "Unknown agent id", phosphor::logging::entry("ID=%x", agentId));
726         return ipmi::responseParmOutOfRange();
727     }
728 
729     int idIndex = mdrv2->findLockHandle(lockHandle);
730 
731     if ((idIndex < 0) || (idIndex >= maxDirEntries))
732     {
733         phosphor::logging::log<phosphor::logging::level::ERR>(
734             "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex));
735         return ipmi::responseParmOutOfRange();
736     }
737 
738     if (mdrv2->smbiosIsUpdating(idIndex))
739     {
740         if (xferOffset > UINT_MAX - xferLength)
741         {
742             phosphor::logging::log<phosphor::logging::level::ERR>(
743                 "Offset and length are out of range");
744             return ipmi::responseParmOutOfRange();
745         }
746         if (((xferOffset + xferLength) >
747              mdrv2->smbiosDir.dir[idIndex].maxDataSize) ||
748             ((xferOffset + xferLength) >
749              mdrv2->smbiosDir.dir[idIndex].common.dataSetSize))
750         {
751             phosphor::logging::log<phosphor::logging::level::ERR>(
752                 "Send data block Invalid offset/length");
753             return ipmi::responseReqDataLenExceeded();
754         }
755         if (reinterpret_cast<size_t>(
756                 mdrv2->smbiosDir.dir[idIndex].dataStorage) >
757             UINT_MAX - xferOffset)
758         {
759             phosphor::logging::log<phosphor::logging::level::ERR>(
760                 "Offset is out of range");
761             return ipmi::responseParmOutOfRange();
762         }
763         uint8_t *destAddr =
764             mdrv2->smbiosDir.dir[idIndex].dataStorage + xferOffset;
765         uint8_t *sourceAddr = reinterpret_cast<uint8_t *>(mdrv2->area->vPtr);
766         uint32_t calcChecksum = mdrv2->calcChecksum32(sourceAddr, xferLength);
767         if (calcChecksum != checksum)
768         {
769             phosphor::logging::log<phosphor::logging::level::ERR>(
770                 "Send data block Invalid checksum");
771             return ipmi::response(ccOemInvalidChecksum);
772         }
773         else
774         {
775             if (reinterpret_cast<size_t>(sourceAddr) > UINT_MAX - xferLength)
776             {
777                 phosphor::logging::log<phosphor::logging::level::ERR>(
778                     "Length is out of range");
779                 return ipmi::responseParmOutOfRange();
780             }
781             std::copy(sourceAddr, sourceAddr + xferLength, destAddr);
782         }
783     }
784     else
785     {
786         phosphor::logging::log<phosphor::logging::level::ERR>(
787             "Send data block failed, other data is updating");
788         return ipmi::responseDestinationUnavailable();
789     }
790 
791     return ipmi::responseSuccess();
792 }
793 
794 bool MDRV2::storeDatatoFlash(MDRSMBIOSHeader *mdrHdr, uint8_t *data)
795 {
796     std::ofstream smbiosFile(mdrType2File,
797                              std::ios_base::binary | std::ios_base::trunc);
798     if (!smbiosFile.good())
799     {
800         phosphor::logging::log<phosphor::logging::level::ERR>(
801             "Write data from flash error - Open MDRV2 table file failure");
802         return false;
803     }
804 
805     try
806     {
807         smbiosFile.write(reinterpret_cast<char *>(mdrHdr),
808                          sizeof(MDRSMBIOSHeader));
809         smbiosFile.write(reinterpret_cast<char *>(data), mdrHdr->dataSize);
810     }
811     catch (std::ofstream::failure &e)
812     {
813         phosphor::logging::log<phosphor::logging::level::ERR>(
814             "Write data from flash error - write data error",
815             phosphor::logging::entry("ERROR=%s", e.what()));
816         return false;
817     }
818 
819     return true;
820 }
821 
822 void SharedMemoryArea::Initialize(uint32_t addr, uint32_t areaSize)
823 {
824     int memDriver = 0;
825 
826     // open mem driver for the system memory access
827     memDriver = open("/dev/vgasharedmem", O_RDONLY);
828     if (memDriver < 0)
829     {
830         phosphor::logging::log<phosphor::logging::level::ERR>(
831             "Cannot access mem driver");
832         throw std::system_error(EIO, std::generic_category());
833     }
834 
835     // map the system memory
836     vPtr = mmap(NULL,                       // where to map to: don't mind
837                 areaSize,                   // how many bytes ?
838                 PROT_READ,                  // want to read and write
839                 MAP_SHARED,                 // no copy on write
840                 memDriver,                  // handle to /dev/mem
841                 (physicalAddr & pageMask)); // hopefully the Text-buffer :-)
842 
843     close(memDriver);
844     if (vPtr == MAP_FAILED)
845     {
846         phosphor::logging::log<phosphor::logging::level::ERR>(
847             "Failed to map share memory");
848         throw std::system_error(EIO, std::generic_category());
849     }
850     size = areaSize;
851     physicalAddr = addr;
852 }
853 
854 bool MDRV2::smbiosUnlock(uint8_t index)
855 {
856     bool ret;
857     switch (smbiosDir.dir[index].stage)
858     {
859         case MDR2SMBIOSStatusEnum::mdr2Updating:
860             smbiosDir.dir[index].stage = MDR2SMBIOSStatusEnum::mdr2Updated;
861             smbiosDir.dir[index].lock = MDR2DirLockEnum::mdr2DirUnlock;
862 
863             timer->stop();
864             smbiosDir.dir[index].lockHandle = 0;
865             ret = true;
866             break;
867 
868         case MDR2SMBIOSStatusEnum::mdr2Updated:
869         case MDR2SMBIOSStatusEnum::mdr2Loaded:
870             smbiosDir.dir[index].lock = MDR2DirLockEnum::mdr2DirUnlock;
871 
872             timer->stop();
873 
874             smbiosDir.dir[index].lockHandle = 0;
875             ret = true;
876             break;
877 
878         default:
879             break;
880     }
881 
882     return ret;
883 }
884 
885 bool MDRV2::smbiosTryLock(uint8_t flag, uint8_t index, uint16_t *session,
886                           uint16_t timeout)
887 {
888     bool ret = false;
889     uint32_t u32Status = 0;
890 
891     if (timeout == 0)
892     {
893         timeout = defaultTimeout;
894     }
895     std::chrono::microseconds usec(timeout * sysClock);
896 
897     switch (smbiosDir.dir[index].stage)
898     {
899         case MDR2SMBIOSStatusEnum::mdr2Updating:
900             if (smbiosDir.dir[index].lock != MDR2DirLockEnum::mdr2DirLock)
901             {
902                 smbiosDir.dir[index].lock = MDR2DirLockEnum::mdr2DirLock;
903                 timer->start(usec);
904                 lockIndex = index;
905 
906                 *session = getSessionHandle(&smbiosDir);
907                 smbiosDir.dir[index].lockHandle = *session;
908                 ret = true;
909             }
910             break;
911         case MDR2SMBIOSStatusEnum::mdr2Init:
912             if (flag)
913             {
914                 smbiosDir.dir[index].stage = MDR2SMBIOSStatusEnum::mdr2Updating;
915                 smbiosDir.dir[index].lock = MDR2DirLockEnum::mdr2DirUnlock;
916                 timer->start(usec);
917                 lockIndex = index;
918 
919                 *session = getSessionHandle(&smbiosDir);
920                 smbiosDir.dir[index].lockHandle = *session;
921                 ret = true;
922             }
923             break;
924 
925         case MDR2SMBIOSStatusEnum::mdr2Updated:
926         case MDR2SMBIOSStatusEnum::mdr2Loaded:
927             if (smbiosDir.dir[index].lock != MDR2DirLockEnum::mdr2DirLock)
928             {
929                 if (flag)
930                 {
931                     smbiosDir.dir[index].stage =
932                         MDR2SMBIOSStatusEnum::mdr2Updating;
933                     smbiosDir.dir[index].lock = MDR2DirLockEnum::mdr2DirUnlock;
934                 }
935                 else
936                 {
937                     smbiosDir.dir[index].lock = MDR2DirLockEnum::mdr2DirLock;
938                 }
939 
940                 timer->start(usec);
941                 lockIndex = index;
942 
943                 *session = getSessionHandle(&smbiosDir);
944                 smbiosDir.dir[index].lockHandle = *session;
945                 ret = true;
946             }
947             break;
948 
949         default:
950             break;
951     }
952     return ret;
953 }
954 
955 void MDRV2::timeoutHandler()
956 {
957     smbiosUnlock(lockIndex);
958     mdrv2->area.reset(nullptr);
959 }
960 
961 /** @brief implements mdr2 lock data command
962  *  @param agentId
963  *  @param dataInfo
964  *  @param timeout
965  *
966  *  @returns IPMI completion code plus response data
967  *  - mdr2Version
968  *  - session
969  *  - dataLength
970  *  - xferAddress
971  *  - xferLength
972  */
973 ipmi::RspType<uint8_t,  // mdr2Version
974               uint16_t, // session
975               uint32_t, // dataLength
976               uint32_t, // xferAddress
977               uint32_t  // xferLength
978               >
979     mdr2LockData(uint16_t agentId, std::array<uint8_t, dataInfoSize> dataInfo,
980                  uint16_t timeout)
981 {
982     if (mdrv2 == nullptr)
983     {
984         mdrv2 = std::make_unique<MDRV2>();
985     }
986 
987     int agentIndex = mdrv2->agentLookup(agentId);
988     if (agentIndex == -1)
989     {
990         phosphor::logging::log<phosphor::logging::level::ERR>(
991             "Unknown agent id", phosphor::logging::entry("ID=%x", agentId));
992         return ipmi::responseParmOutOfRange();
993     }
994 
995     std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
996     std::string service = ipmi::getService(*bus, mdrv2Interface, mdrv2Path);
997 
998     int idIndex = mdrv2->findDataId(dataInfo.data(), dataInfo.size(), service);
999 
1000     if ((idIndex < 0) || (idIndex >= maxDirEntries))
1001     {
1002         phosphor::logging::log<phosphor::logging::level::ERR>(
1003             "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex));
1004         return ipmi::responseParmOutOfRange();
1005     }
1006 
1007     uint16_t session = 0;
1008     if (!mdrv2->smbiosTryLock(0, idIndex, &session, timeout))
1009     {
1010         phosphor::logging::log<phosphor::logging::level::ERR>(
1011             "Lock Data failed - cannot lock idIndex");
1012         return ipmi::responseCommandNotAvailable();
1013     }
1014 
1015     uint32_t dataLength = mdrv2->smbiosDir.dir[idIndex].common.size;
1016     uint32_t xferAddress = mdrv2->smbiosDir.dir[idIndex].xferBuff;
1017     uint32_t xferLength = mdrv2->smbiosDir.dir[idIndex].xferSize;
1018 
1019     return ipmi::responseSuccess(mdr2Version, session, dataLength, xferAddress,
1020                                  xferLength);
1021 }
1022 
1023 /** @brief implements mdr2 unlock data command
1024  *  @param agentId
1025  *  @param lockHandle
1026  *
1027  *  @returns IPMI completion code
1028  */
1029 ipmi::RspType<> mdr2UnlockData(uint16_t agentId, uint16_t lockHandle)
1030 {
1031     phosphor::logging::log<phosphor::logging::level::ERR>("unlock data");
1032 
1033     if (mdrv2 == nullptr)
1034     {
1035         mdrv2 = std::make_unique<MDRV2>();
1036     }
1037 
1038     int agentIndex = mdrv2->agentLookup(agentId);
1039     if (agentIndex == -1)
1040     {
1041         phosphor::logging::log<phosphor::logging::level::ERR>(
1042             "Unknown agent id", phosphor::logging::entry("ID=%x", agentId));
1043         return ipmi::responseParmOutOfRange();
1044     }
1045 
1046     int idIndex = mdrv2->findLockHandle(lockHandle);
1047 
1048     if ((idIndex < 0) || (idIndex >= maxDirEntries))
1049     {
1050         phosphor::logging::log<phosphor::logging::level::ERR>(
1051             "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex));
1052         return ipmi::responseParmOutOfRange();
1053     }
1054 
1055     if (!mdrv2->smbiosUnlock(idIndex))
1056     {
1057         phosphor::logging::log<phosphor::logging::level::ERR>(
1058             "Unlock Data failed - cannot unlock idIndex");
1059         return ipmi::responseCommandNotAvailable();
1060     }
1061 
1062     return ipmi::responseSuccess();
1063 }
1064 
1065 /**
1066 @brief This command is executed after POST BIOS to get the session info.
1067 
1068 @param - agentId, dataInfo, dataLength, xferAddress, xferLength, timeout.
1069 
1070 @return xferStartAck and session on success.
1071 **/
1072 ipmi::RspType<uint8_t, uint16_t>
1073     cmd_mdr2_data_start(uint16_t agentId, std::array<uint8_t, 16> dataInfo,
1074                         uint32_t dataLength, uint32_t xferAddress,
1075                         uint32_t xferLength, uint16_t timeout)
1076 {
1077     uint16_t session = 0;
1078 
1079     if (dataLength > smbiosTableStorageSize)
1080     {
1081         phosphor::logging::log<phosphor::logging::level::ERR>(
1082             "Requested data length is out of SMBIOS Table storage size.");
1083         return ipmi::responseParmOutOfRange();
1084     }
1085     if ((xferLength + xferAddress) > mdriiSMSize)
1086     {
1087         phosphor::logging::log<phosphor::logging::level::ERR>(
1088             "Invalid data address and size");
1089         return ipmi::responseParmOutOfRange();
1090     }
1091 
1092     std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
1093     std::string service = ipmi::getService(*bus, mdrv2Interface, mdrv2Path);
1094 
1095     if (mdrv2 == nullptr)
1096     {
1097         mdrv2 = std::make_unique<MDRV2>();
1098     }
1099 
1100     int agentIndex = mdrv2->agentLookup(agentId);
1101     if (agentIndex == -1)
1102     {
1103         phosphor::logging::log<phosphor::logging::level::ERR>(
1104             "Unknown agent id", phosphor::logging::entry("ID=%x", agentId));
1105         return ipmi::responseParmOutOfRange();
1106     }
1107 
1108     int idIndex = mdrv2->findDataId(dataInfo.data(), dataInfo.size(), service);
1109 
1110     if ((idIndex < 0) || (idIndex >= maxDirEntries))
1111     {
1112         phosphor::logging::log<phosphor::logging::level::ERR>(
1113             "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex));
1114         return ipmi::responseParmOutOfRange();
1115     }
1116 
1117     if (mdrv2->smbiosTryLock(1, idIndex, &session, timeout))
1118     {
1119         try
1120         {
1121             mdrv2->area =
1122                 std::make_unique<SharedMemoryArea>(xferAddress, xferLength);
1123         }
1124         catch (const std::system_error &e)
1125         {
1126             mdrv2->smbiosUnlock(idIndex);
1127             phosphor::logging::log<phosphor::logging::level::ERR>(
1128                 "Unable to access share memory",
1129                 phosphor::logging::entry("ERROR=%s", e.what()));
1130             return ipmi::responseUnspecifiedError();
1131         }
1132         mdrv2->smbiosDir.dir[idIndex].common.size = dataLength;
1133         mdrv2->smbiosDir.dir[idIndex].lockHandle = session;
1134         if (-1 ==
1135             mdrv2->syncDirCommonData(
1136                 idIndex, mdrv2->smbiosDir.dir[idIndex].common.size, service))
1137         {
1138             phosphor::logging::log<phosphor::logging::level::ERR>(
1139                 "Unable to sync data to service");
1140             return ipmi::responseResponseError();
1141         }
1142     }
1143     else
1144     {
1145         phosphor::logging::log<phosphor::logging::level::ERR>(
1146             "Canot lock smbios");
1147         return ipmi::responseUnspecifiedError();
1148     }
1149 
1150     static constexpr uint8_t xferStartAck = 1;
1151 
1152     return ipmi::responseSuccess(xferStartAck, session);
1153 }
1154 
1155 /**
1156 @brief This command is executed to close the session.
1157 
1158 @param - agentId, lockHandle.
1159 
1160 @return completion code on success.
1161 **/
1162 ipmi::RspType<> cmd_mdr2_data_done(uint16_t agentId, uint16_t lockHandle)
1163 {
1164 
1165     if (mdrv2 == nullptr)
1166     {
1167         mdrv2 = std::make_unique<MDRV2>();
1168     }
1169 
1170     int agentIndex = mdrv2->agentLookup(agentId);
1171     if (agentIndex == -1)
1172     {
1173         phosphor::logging::log<phosphor::logging::level::ERR>(
1174             "Unknown agent id", phosphor::logging::entry("ID=%x", agentId));
1175         return ipmi::responseParmOutOfRange();
1176     }
1177 
1178     int idIndex = mdrv2->findLockHandle(lockHandle);
1179 
1180     if ((idIndex < 0) || (idIndex >= maxDirEntries))
1181     {
1182         phosphor::logging::log<phosphor::logging::level::ERR>(
1183             "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex));
1184         return ipmi::responseParmOutOfRange();
1185     }
1186 
1187     if (!mdrv2->smbiosUnlock(idIndex))
1188     {
1189         phosphor::logging::log<phosphor::logging::level::ERR>(
1190             "Send data done failed - cannot unlock idIndex");
1191         return ipmi::responseDestinationUnavailable();
1192     }
1193 
1194     mdrv2->area.reset(nullptr);
1195     MDRSMBIOSHeader mdr2Smbios;
1196     mdr2Smbios.mdrType = mdrTypeII;
1197     mdr2Smbios.dirVer = mdrv2->smbiosDir.dir[0].common.dataVersion;
1198     mdr2Smbios.timestamp = mdrv2->smbiosDir.dir[0].common.timestamp;
1199     mdr2Smbios.dataSize = mdrv2->smbiosDir.dir[0].common.size;
1200 
1201     if (access(smbiosPath, 0) == -1)
1202     {
1203         int flag = mkdir(smbiosPath, S_IRWXU);
1204         if (flag != 0)
1205         {
1206             phosphor::logging::log<phosphor::logging::level::ERR>(
1207                 "create folder failed for writting smbios file");
1208         }
1209     }
1210     if (!mdrv2->storeDatatoFlash(
1211             &mdr2Smbios, mdrv2->smbiosDir.dir[smbiosDirIndex].dataStorage))
1212     {
1213         phosphor::logging::log<phosphor::logging::level::ERR>(
1214             "MDR2 Store data to flash failed");
1215         return ipmi::responseDestinationUnavailable();
1216     }
1217     bool status = false;
1218     std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
1219     std::string service = ipmi::getService(*bus, mdrv2Interface, mdrv2Path);
1220     sdbusplus::message::message method = bus->new_method_call(
1221         service.c_str(), mdrv2Path, mdrv2Interface, "AgentSynchronizeData");
1222 
1223     try
1224     {
1225         sdbusplus::message::message reply = bus->call(method);
1226         reply.read(status);
1227     }
1228     catch (sdbusplus::exception_t &e)
1229     {
1230         phosphor::logging::log<phosphor::logging::level::ERR>(
1231             "Error Sync data with service",
1232             phosphor::logging::entry("ERROR=%s", e.what()),
1233             phosphor::logging::entry("SERVICE=%s", service.c_str()),
1234             phosphor::logging::entry("PATH=%s", mdrv2Path));
1235         return ipmi::responseResponseError();
1236     }
1237 
1238     if (!status)
1239     {
1240         phosphor::logging::log<phosphor::logging::level::ERR>(
1241             "Sync data with service failure");
1242         return ipmi::responseUnspecifiedError();
1243     }
1244 
1245     return ipmi::responseSuccess();
1246 }
1247 
1248 static void register_netfn_smbiosmdrv2_functions(void)
1249 {
1250     // MDR V2 Command
1251     // <Get MDRII Status Command>
1252     ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp,
1253                           ipmi::intel::app::cmdMdrIIAgentStatus,
1254                           ipmi::Privilege::Operator, mdr2AgentStatus);
1255 
1256     // <Get MDRII Directory Command>
1257     ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp,
1258                           ipmi::intel::app::cmdMdrIIGetDir,
1259                           ipmi::Privilege::Operator, mdr2GetDir);
1260 
1261     // <Send MDRII Directory Command>
1262     ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp,
1263                           ipmi::intel::app::cmdMdrIISendDir,
1264                           ipmi::Privilege::Operator, mdr2SendDir);
1265 
1266     // <Get MDRII Data Info Command>
1267     ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp,
1268                           ipmi::intel::app::cmdMdrIIGetDataInfo,
1269                           ipmi::Privilege::Operator, mdr2GetDataInfo);
1270 
1271     // <Send MDRII Info Offer>
1272     ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp,
1273                           ipmi::intel::app::cmdMdrIISendDataInfoOffer,
1274                           ipmi::Privilege::Operator, mdr2DataInfoOffer);
1275 
1276     // <Send MDRII Data Info>
1277     ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp,
1278                           ipmi::intel::app::cmdMdrIISendDataInfo,
1279                           ipmi::Privilege::Operator, mdr2SendDataInfo);
1280 
1281     // <Get MDRII Data Block Command>
1282     ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp,
1283                           ipmi::intel::app::cmdMdrIIGetDataBlock,
1284                           ipmi::Privilege::Operator, mdr2GetDataBlock);
1285 
1286     // <Send MDRII Data Block>
1287     ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp,
1288                           ipmi::intel::app::cmdMdrIISendDataBlock,
1289                           ipmi::Privilege::Operator, mdr2SendDataBlock);
1290 
1291     // <Lock MDRII Data Command>
1292     ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp,
1293                           ipmi::intel::app::cmdMdrIILockData,
1294                           ipmi::Privilege::Operator, mdr2LockData);
1295 
1296     // <Unlock MDRII Data Command>
1297     ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp,
1298                           ipmi::intel::app::cmdMdrIIUnlockData,
1299                           ipmi::Privilege::Operator, mdr2UnlockData);
1300 
1301     // <Send MDRII Data Start>
1302     ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp,
1303                           ipmi::intel::app::cmdMdrIIDataStart,
1304                           ipmi::Privilege::Operator, cmd_mdr2_data_start);
1305 
1306     // <Send MDRII Data Done>
1307     ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp,
1308                           ipmi::intel::app::cmdMdrIIDataDone,
1309                           ipmi::Privilege::Operator, cmd_mdr2_data_done);
1310 }
1311