xref: /openbmc/intel-ipmi-oem/src/smbiosmdrv2handler.cpp (revision 1bcced0820999e7e050257b9f78cf36b23eb762b)
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