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