blob: 92b1f41ffb294558a33153a416bb820198e85a8a [file] [log] [blame]
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001/*
2// Copyright (c) 2020 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
Arun Lal K Me7725612021-07-15 18:20:58 +000017#include "biosxml.hpp"
18
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +080019#include <openssl/sha.h>
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +080020
21#include <biosconfigcommands.hpp>
22#include <boost/crc.hpp>
23#include <boost/process/child.hpp>
24#include <boost/process/io.hpp>
25#include <ipmid/api.hpp>
26#include <ipmid/message.hpp>
27#include <ipmid/message/types.hpp>
28#include <ipmid/types.hpp>
29#include <ipmid/utils.hpp>
30#include <nlohmann/json.hpp>
31#include <oemcommands.hpp>
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +080032#include <sdbusplus/bus.hpp>
33#include <sdbusplus/message/types.hpp>
34
35#include <filesystem>
Suryakanth Sekarcc402592021-04-01 15:02:10 +053036#include <string_view>
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +080037
38namespace ipmi
39{
Arun Lal K Mb0caca02021-09-05 22:09:33 +000040static bool flushNVOOBdata();
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +080041static void registerBIOSConfigFunctions() __attribute__((constructor));
42
43// Define BIOS config related Completion Code
44using Cc = uint8_t;
45static constexpr Cc ipmiCCPayloadPayloadPacketMissed = 0x80;
46static constexpr Cc ipmiCCBIOSPasswordInitNotDone = 0x80;
47static constexpr Cc ipmiCCPayloadChecksumFailed = 0x81;
48static constexpr Cc ipmiCCNotSupportedInCurrentState = 0x82;
49static constexpr Cc ipmiCCPayloadPayloadInComplete = 0x83;
50static constexpr Cc ipmiCCBIOSCapabilityInitNotDone = 0x85;
51static constexpr Cc ipmiCCPayloadLengthIllegal = 0x85;
52
53static constexpr uint8_t userPasswordChanged = (1 << 5);
54static constexpr uint8_t adminPasswordChanged = (1 << 4);
Snehalatha Venkatesh6346e982022-03-09 06:49:18 +000055static constexpr uint8_t restoreDefaultValues = (1 << 7);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +080056
57static constexpr const char* biosConfigFolder = "/var/oob";
58static constexpr const char* biosConfigNVPath = "/var/oob/nvoobdata.dat";
59static constexpr const uint8_t algoSHA384 = 2;
Ayushi Smriti32381872021-06-23 11:05:48 +053060static constexpr const uint8_t algoSHA256 = 1;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +080061static constexpr const uint8_t biosCapOffsetBit = 0x3;
62static constexpr uint16_t maxGetPayloadDataSize = 4096;
63static constexpr const char* biosXMLFilePath = "/var/oob/bios.xml";
64static constexpr const char* biosXMLFilePath1 = "/var/oob/tempbios.xml";
65
66static constexpr const char* biosConfigBaseMgrPath =
67 "/xyz/openbmc_project/bios_config/manager";
68static constexpr const char* biosConfigIntf =
69 "xyz.openbmc_project.BIOSConfig.Manager";
70static constexpr const char* resetBIOSSettingsProp = "ResetBIOSSettings";
71/*baseBIOSTable
72map{attributeName,struct{attributeType,readonlyStatus,displayname,
73 description,menuPath,current,default,
74 array{struct{optionstring,optionvalue}}}}
75*/
Arun Lal K Me7725612021-07-15 18:20:58 +000076
77bios::BiosBaseTableType attributesData;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +080078
79NVOOBdata gNVOOBdata;
80
81enum class PTState : uint8_t
82{
83 StartTransfer = 0,
84 InProgress = 1,
85 EndTransfer = 2,
86 UserAbort = 3
87};
88enum class PStatus : uint8_t
89{
90 Unknown = 0,
91 Valid = 1,
92 Corrupted = 2
93};
94enum class PType : uint8_t
95{
96 IntelXMLType0 = 0,
97 IntelXMLType1 = 1,
98 OTAPayload = 5,
99};
100
101//
102// GetPayload Payload status enumeration
103//
104enum class GetPayloadParameter : uint8_t
105{
106 GetPayloadInfo = 0, // 0
107 GetPayloadData = 1, // 1
Matt Simmering2daecd62022-05-19 12:50:53 -0700108 GetPayloadStatus = 2,
109 MaxPayloadParameters
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800110};
111
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000112namespace payload1
113{
114
115enum class AttributesType : uint8_t
116{
117 unknown = 0,
118 string,
Arun Lal K Md2d60ab2021-12-29 19:42:03 +0000119 integer,
120 enumeration
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000121};
122
123using PendingAttributesType =
Jason M. Bills0748c692022-09-08 15:34:08 -0700124 std::map<std::string, std::tuple<std::string, ipmi::DbusVariant>>;
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000125
126AttributesType getAttrType(const std::string_view typeDbus)
127{
128 if (typeDbus == "xyz.openbmc_project.BIOSConfig.Manager."
129 "AttributeType.String")
130 {
131 return AttributesType::string;
132 }
133 else if (typeDbus == "xyz.openbmc_project.BIOSConfig."
134 "Manager.AttributeType.Integer")
135 {
136 return AttributesType::integer;
137 }
Arun Lal K Md2d60ab2021-12-29 19:42:03 +0000138 else if (typeDbus == "xyz.openbmc_project.BIOSConfig."
139 "Manager.AttributeType.Enumeration")
140 {
141 return AttributesType::enumeration;
142 }
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000143
144 return AttributesType::unknown;
145}
146
147bool fillPayloadData(std::string& payloadData,
Jason M. Bills0748c692022-09-08 15:34:08 -0700148 const ipmi::DbusVariant& attributes,
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000149 const std::string_view key, AttributesType& attrType)
150{
151 payloadData += key;
152 payloadData += '=';
153
Arun Lal K Md2d60ab2021-12-29 19:42:03 +0000154 if (attrType == AttributesType::string ||
155 attrType == AttributesType::enumeration)
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000156 {
157 if (!std::holds_alternative<std::string>(attributes))
158 {
159 phosphor::logging::log<phosphor::logging::level::ERR>(
160 "fillPayloadData: No string data in attributes");
161 return false;
162 }
163 payloadData += std::get<std::string>(attributes);
164 }
165 else if (attrType == AttributesType::integer)
166 {
167 if (!std::holds_alternative<int64_t>(attributes))
168 {
169 phosphor::logging::log<phosphor::logging::level::ERR>(
170 "fillPayloadData: No int64_t data in attributes");
171 return false;
172 }
173 payloadData += std::to_string(std::get<int64_t>(attributes));
174 }
175 else
176 {
177 phosphor::logging::log<phosphor::logging::level::ERR>(
178 "fillPayloadData: Unsupported attribute type");
179 return false;
180 }
181
182 payloadData += '\n';
183
184 return true;
185}
186
Vernon Mauerydcff1502022-09-28 11:12:46 -0700187bool getPendingList(ipmi::Context::ptr& ctx, std::string& payloadData)
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000188{
189 std::variant<PendingAttributesType> pendingAttributesData;
190 boost::system::error_code ec;
191
192 payloadData.clear();
193
194 auto dbus = getSdBus();
195 if (!dbus)
196 {
197 phosphor::logging::log<phosphor::logging::level::ERR>(
198 "getPendingList: getSdBus() failed");
199 return false;
200 }
201
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500202 std::string service = getService(*dbus, biosConfigIntf,
203 biosConfigBaseMgrPath);
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000204
205 try
206 {
207 pendingAttributesData =
208 dbus->yield_method_call<std::variant<PendingAttributesType>>(
209 ctx->yield, ec, service,
210 "/xyz/openbmc_project/bios_config/manager",
211 "org.freedesktop.DBus.Properties", "Get",
212 "xyz.openbmc_project.BIOSConfig.Manager", "PendingAttributes");
213 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500214 catch (const std::exception& ex)
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000215 {
216 phosphor::logging::log<phosphor::logging::level::ERR>(ex.what());
217 return false;
218 }
219
220 if (ec)
221 {
222 std::string err = "getPendingList: error while trying to get "
223 "PendingAttributes, error = ";
224 err += ec.message();
225
226 phosphor::logging::log<phosphor::logging::level::ERR>(err.c_str());
227
228 return false;
229 }
230
231 const PendingAttributesType* pendingAttributes =
232 std::get_if<PendingAttributesType>(&pendingAttributesData);
233 if (!pendingAttributes)
234 {
235 phosphor::logging::log<phosphor::logging::level::ERR>(
236 "getPendingList: pendingAttributes is null");
237 return false;
238 }
239
240 for (const auto& [key, attributes] : *pendingAttributes)
241 {
242 const std::string& itemType = std::get<0>(attributes);
243 AttributesType attrType = getAttrType(itemType);
244
245 if (!fillPayloadData(payloadData, std::get<1>(attributes), key,
246 attrType))
247 {
248 return false;
249 }
250 }
251
252 if (payloadData.empty())
253 {
254 phosphor::logging::log<phosphor::logging::level::ERR>(
255 "getPendingList: payloadData is empty");
256 return false;
257 }
258
259 return true;
260}
261bool updatePayloadFile(std::string& payloadFilePath, std::string payloadData)
262{
263 std::ofstream payloadFile(payloadFilePath,
264 std::ios::out | std::ios::binary);
265
266 payloadFile << payloadData;
267
268 if (!payloadFile.good())
269 {
270 return false;
271 }
272
273 return true;
274}
275
276bool computeCheckSum(std::string& payloadFilePath,
277 boost::crc_32_type& calcChecksum)
278{
279 std::ifstream payloadFile(payloadFilePath.c_str(),
280 std::ios::in | std::ios::binary | std::ios::ate);
281
282 if (!payloadFile.good())
283 {
284 phosphor::logging::log<phosphor::logging::level::ERR>(
285 "computeCheckSum: Cannot open Payload1 file");
286 return false;
287 }
288
289 payloadFile.seekg(0, payloadFile.end);
290 int length = payloadFile.tellg();
291 payloadFile.seekg(0, payloadFile.beg);
292
293 if (maxGetPayloadDataSize < length)
294 {
295 phosphor::logging::log<phosphor::logging::level::ERR>(
296 "computeCheckSum: length > maxGetPayloadDataSize");
297 return false;
298 }
299
300 std::unique_ptr<char[]> payloadBuffer(new char[length]);
301
302 payloadFile.read(payloadBuffer.get(), length);
303 uint32_t readCount = payloadFile.gcount();
304
305 calcChecksum.process_bytes(payloadBuffer.get(), readCount);
306
307 return true;
308}
309
310bool updatePayloadInfo(std::string& payloadFilePath)
311{
312 boost::crc_32_type calcChecksum;
313
314 uint8_t payloadType = static_cast<uint8_t>(ipmi::PType::IntelXMLType1);
315 auto& payloadInfo = gNVOOBdata.payloadInfo[payloadType];
316
317 if (!computeCheckSum(payloadFilePath, calcChecksum))
318 {
319 phosphor::logging::log<phosphor::logging::level::ERR>(
320 "updatePayloadInfo: Cannot compute checksum for Payload1 file");
321 return false;
322 }
323
324 payloadInfo.payloadVersion = 0;
325 payloadInfo.payloadflag = 0;
326 payloadInfo.payloadReservationID = rand();
327
328 payloadInfo.payloadType = payloadType;
329
330 payloadInfo.payloadTotalChecksum = calcChecksum.checksum();
331 payloadInfo.payloadCurrentChecksum = payloadInfo.payloadTotalChecksum;
332
333 payloadInfo.payloadStatus = (static_cast<uint8_t>(ipmi::PStatus::Valid));
334
335 struct stat filestat;
336 /* Get entry's information. */
337 if (!stat(payloadFilePath.c_str(), &filestat))
338 {
339 payloadInfo.payloadTimeStamp = filestat.st_mtime;
340 payloadInfo.payloadTotalSize = filestat.st_size;
341 payloadInfo.payloadCurrentSize = filestat.st_size;
342 payloadInfo.actualTotalPayloadWritten = filestat.st_size;
343 }
344 else
345 {
346 phosphor::logging::log<phosphor::logging::level::ERR>(
347 "updatePayloadInfo: Cannot get file status for Payload1 file");
348 return false;
349 }
350
351 if (!flushNVOOBdata())
352 {
353 phosphor::logging::log<phosphor::logging::level::ERR>(
354 "updatePayloadInfo: flushNVOOBdata failed");
355 return false;
356 }
357
358 return true;
359}
360
Vernon Mauerydcff1502022-09-28 11:12:46 -0700361bool update(ipmi::Context::ptr& ctx)
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000362{
363 std::string payloadFilePath =
364 "/var/oob/Payload" +
365 std::to_string(static_cast<uint8_t>(ipmi::PType::IntelXMLType1));
366
367 std::string payloadData;
368
369 if (!getPendingList(ctx, payloadData))
370 {
371 phosphor::logging::log<phosphor::logging::level::ERR>(
372 "payload1::update : getPendingList() failed");
373 return false;
374 }
375
376 if (!updatePayloadFile(payloadFilePath, payloadData))
377 {
378 phosphor::logging::log<phosphor::logging::level::ERR>(
379 "payload1::update : updatePayloadFile() failed");
380 return false;
381 }
382
383 if (!updatePayloadInfo(payloadFilePath))
384 {
385 phosphor::logging::log<phosphor::logging::level::ERR>(
386 "payload1::update : updatePayloadInfo() failed");
387 return false;
388 }
389
390 return true;
391}
392} // namespace payload1
393
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800394/** @brief implement to set the BaseBIOSTable property
395 * @returns status
396 */
Arun Lal K Me7725612021-07-15 18:20:58 +0000397static bool sendAllAttributes(std::string service)
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800398{
Arun Lal K Me7725612021-07-15 18:20:58 +0000399 std::shared_ptr<sdbusplus::asio::connection> pSdBusPlus = getSdBus();
400
401 if (pSdBusPlus)
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800402 {
Arun Lal K Me7725612021-07-15 18:20:58 +0000403 try
404 {
405 pSdBusPlus->async_method_call(
406 [](const boost::system::error_code ec) {
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500407 /* No more need to keep attributes data in memory */
408 attributesData.clear();
Arun Lal K Me7725612021-07-15 18:20:58 +0000409
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500410 if (ec)
411 {
412 phosphor::logging::log<phosphor::logging::level::ERR>(
413 "sendAllAttributes error: send all attributes - "
414 "failed");
415 return;
416 }
Arun Lal K Me7725612021-07-15 18:20:58 +0000417
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500418 phosphor::logging::log<phosphor::logging::level::INFO>(
419 "sendAllAttributes: send all attributes - done");
Arun Lal K Me7725612021-07-15 18:20:58 +0000420 },
421 service, biosConfigBaseMgrPath,
422 "org.freedesktop.DBus.Properties", "Set", biosConfigIntf,
423 "BaseBIOSTable",
424 std::variant<bios::BiosBaseTableType>(attributesData));
425
426 return true;
427 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500428 catch (const std::exception& ex)
Arun Lal K Me7725612021-07-15 18:20:58 +0000429 {
430 phosphor::logging::log<phosphor::logging::level::ERR>(ex.what());
431 }
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800432 }
Arun Lal K Me7725612021-07-15 18:20:58 +0000433
434 return false;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800435}
436
437/** @brief implement to flush the updated data in nv space
438 * @returns status
439 */
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000440static bool flushNVOOBdata()
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800441{
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000442 std::ofstream outFile(biosConfigNVPath, std::ios::binary);
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000443
444 outFile.seekp(std::ios_base::beg);
445 const char* writedata = reinterpret_cast<const char*>(&gNVOOBdata);
446 outFile.write(writedata, sizeof(struct NVOOBdata));
447
448 if (!outFile.good())
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800449 {
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000450 return false;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800451 }
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000452
453 return true;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800454}
455
456/** @brief implement to get the System State
457 * @returns status
458 */
Arun Lal K M382dc972022-01-20 22:18:23 +0000459static bool getPostCompleted()
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800460{
Arun Lal K M382dc972022-01-20 22:18:23 +0000461 /*
462 * In case of failure we treat postCompleted as true.
463 * So that BIOS config commands is not accepted by BMC by mistake.
464 */
465 bool postCompleted = true;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800466
467 try
468 {
469 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
470 Value variant =
471 getDbusProperty(*dbus, "xyz.openbmc_project.State.OperatingSystem",
472 "/xyz/openbmc_project/state/os",
473 "xyz.openbmc_project.State.OperatingSystem.Status",
474 "OperatingSystemState");
Arun Lal K M382dc972022-01-20 22:18:23 +0000475 auto& value = std::get<std::string>(variant);
476
477 // The short strings "Standby" is deprecated in favor of the
478 // full enum strings. Support for the short strings will be
479 // removed in the future.
480 postCompleted = (value == "Standby") ||
481 (value == "xyz.openbmc_project.State.OperatingSystem."
482 "Status.OSStatus.Standby");
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800483 }
484 catch (const std::exception& e)
485 {
Arun Lal K M382dc972022-01-20 22:18:23 +0000486 phosphor::logging::log<phosphor::logging::level::ERR>(
487 "'getDbusProperty' failed to read "
488 "xyz.openbmc_project.State.OperatingSystem");
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800489 }
Arun Lal K M382dc972022-01-20 22:18:23 +0000490
491 return postCompleted;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800492}
493
494/** @brief implement to get the Rest BIOS property
495 * @returns status
496 */
497static int getResetBIOSSettings(uint8_t& ResetFlag)
498{
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800499 try
500 {
501 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500502 std::string service = getService(*dbus, biosConfigIntf,
503 biosConfigBaseMgrPath);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800504 Value variant = getDbusProperty(*dbus, service, biosConfigBaseMgrPath,
505 biosConfigIntf, resetBIOSSettingsProp);
Suryakanth Sekarcc402592021-04-01 15:02:10 +0530506
507 std::string_view ResetStr = std::get<std::string>(variant);
508 if (ResetStr ==
509 "xyz.openbmc_project.BIOSConfig.Manager.ResetFlag.NoAction")
510 {
511 ResetFlag = 0;
512 }
513 else if (ResetStr == "xyz.openbmc_project.BIOSConfig.Manager.ResetFlag."
514 "FactoryDefaults")
515 {
516 ResetFlag = 1;
517 }
518 else if (ResetStr == "xyz.openbmc_project.BIOSConfig.Manager.ResetFlag."
519 "FailSafeDefaults")
520 {
521 ResetFlag = 2;
522 }
523 else
524 {
525 return ipmi::ccUnspecifiedError;
526 }
527
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800528 return ipmi::ccSuccess;
529 }
530 catch (const std::exception& e)
531 {
532 return ipmi::ccUnspecifiedError;
533 }
534}
535
Arun Lal K Me7725612021-07-15 18:20:58 +0000536/** @brief Get attributes data (bios base table) from bios.xml
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800537 */
Arun Lal K Me7725612021-07-15 18:20:58 +0000538static bool generateAttributesData()
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800539{
Arun Lal K Me7725612021-07-15 18:20:58 +0000540 try
541 {
542 bios::Xml biosxml(biosXMLFilePath);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800543
Arun Lal K Me7725612021-07-15 18:20:58 +0000544 if (!biosxml.doDepexCompute())
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800545 {
Arun Lal K Me7725612021-07-15 18:20:58 +0000546 phosphor::logging::log<phosphor::logging::level::ERR>(
547 "'depex' compute failed");
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800548 }
Arun Lal K Me7725612021-07-15 18:20:58 +0000549
550 if (!biosxml.getBaseTable(attributesData))
551 {
552 phosphor::logging::log<phosphor::logging::level::ERR>(
553 "Failed to get bios base table");
554 }
555 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500556 catch (const std::exception& ex)
Arun Lal K Me7725612021-07-15 18:20:58 +0000557 {
558 phosphor::logging::log<phosphor::logging::level::ERR>(ex.what());
559 return false;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800560 }
561
Arun Lal K Me7725612021-07-15 18:20:58 +0000562 return true;
563}
564
565/** @brief Generate attributes data from bios.xml
566 * and send attributes data (bios base table) to dbus using set method.
567 */
568static void generateAndSendAttributesData(std::string service,
569 uint8_t payloadType)
570{
571 if (!generateAttributesData())
572 {
573 phosphor::logging::log<phosphor::logging::level::ERR>(
574 "generateAndSendAttributesData: generateAttributesData - failed");
575 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
576 static_cast<uint8_t>(ipmi::PStatus::Corrupted);
577 return;
578 }
579
580 phosphor::logging::log<phosphor::logging::level::INFO>(
581 "generateAndSendAttributesData : generateAttributesData is done");
582
583 if (!sendAllAttributes(service))
584 {
585 phosphor::logging::log<phosphor::logging::level::ERR>(
586 "generateAndSendAttributesData: sendAllAttributes - failed");
587 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
588 static_cast<uint8_t>(ipmi::PStatus::Corrupted);
589 return;
590 }
591
592 phosphor::logging::log<phosphor::logging::level::INFO>(
593 "generateAndSendAttributesData : sendAllAttributes is done");
594 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
595 static_cast<uint8_t>(ipmi::PStatus::Valid);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800596}
597
598/** @brief implement executing the linux command to uncompress and generate the
599 * xmlfile
600 * @param[in] linux command
601 * @returns status
602 */
603template <typename... ArgTypes>
604static int generateBIOSXMLFile(const char* path, ArgTypes&&... tArgs)
605{
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800606 boost::process::child execProg(path, const_cast<char*>(tArgs)...,
607 boost::process::std_out > biosXMLFilePath);
608 execProg.wait();
609 return execProg.exit_code();
610}
611
612/** @brief implements to clean up the temp/ existing payload file
613 **/
614static void cleanUpPayloadFile(uint8_t& payloadType)
615{
616 // Clear the payload Information
617 std::string FilePath = "/var/oob/temp" + std::to_string(payloadType);
618 unlink(FilePath.c_str());
619 FilePath = "/var/oob/Payload" + std::to_string(payloadType);
620 unlink(FilePath.c_str());
621 if (payloadType == static_cast<uint8_t>(ipmi::PType::IntelXMLType0))
622 {
623 unlink("/var/oob/Payload1");
624 gNVOOBdata.payloadInfo[static_cast<uint8_t>(ipmi::PType::IntelXMLType1)]
625 .payloadStatus = static_cast<uint8_t>(ipmi::PStatus::Unknown);
626 }
627}
628
629/** @brief implements to create the oob folders and nv space
630 **/
631static Cc InitNVOOBdata()
632{
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800633 if (!(std::filesystem::exists(biosConfigFolder)))
634 {
635 std::filesystem::create_directory(biosConfigFolder);
636 }
637
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000638 std::ifstream ifs(biosConfigNVPath, std::ios::in | std::ios::binary);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800639
640 if (ifs.good())
641 {
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000642 ifs.seekg(std::ios_base::beg);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800643 ifs.read(reinterpret_cast<char*>(&gNVOOBdata),
644 sizeof(struct NVOOBdata));
645 ifs.close();
646 return ipmi::ccSuccess;
647 }
648 return ipmi::ccResponseError;
649}
650
Vernon Mauerydcff1502022-09-28 11:12:46 -0700651ipmi::RspType<> ipmiOEMSetBIOSCap(ipmi::Context::ptr&, uint8_t BIOSCapabilties,
652 uint8_t reserved1, uint8_t reserved2,
653 uint8_t reserved3)
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800654{
Arun Lal K M3a1be322022-02-08 21:37:30 +0000655 if (getPostCompleted())
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800656 {
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800657 return ipmi::response(ipmiCCNotSupportedInCurrentState);
658 }
Arun Lal K M3a1be322022-02-08 21:37:30 +0000659
660 if (reserved1 != 0 || reserved2 != 0 || reserved3 != 0)
661 {
662 return ipmi::responseInvalidFieldRequest();
663 }
664
665 gNVOOBdata.mBIOSCapabilities.OOBCapability = BIOSCapabilties;
666 gNVOOBdata.mIsBIOSCapInitDone = true;
667
668 flushNVOOBdata();
669 return ipmi::responseSuccess();
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800670}
671
672ipmi::RspType<uint8_t, uint8_t, uint8_t, uint8_t>
Vernon Mauerydcff1502022-09-28 11:12:46 -0700673 ipmiOEMGetBIOSCap(ipmi::Context::ptr&)
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800674{
675 if (gNVOOBdata.mIsBIOSCapInitDone)
676 {
677 return ipmi::responseSuccess(gNVOOBdata.mBIOSCapabilities.OOBCapability,
678 0, 0, 0);
679 }
680 else
681 {
682 return ipmi::response(ipmiCCBIOSCapabilityInitNotDone);
683 }
684}
685
Vernon Mauerydcff1502022-09-28 11:12:46 -0700686ipmi::RspType<uint32_t> ipmiOEMSetPayload(ipmi::Context::ptr&, uint8_t paramSel,
687 uint8_t payloadType,
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800688 std::vector<uint8_t> payload)
689{
690 uint8_t biosCapOffsetBit = 2; // BIT:1 0-OOB BIOS config not supported
691 // 1-OOB BIOS config is supported
692
693 if (!(gNVOOBdata.mBIOSCapabilities.OOBCapability & (biosCapOffsetBit)))
694 {
695 return ipmi::response(ipmiCCBIOSCapabilityInitNotDone);
696 }
Arun Lal K M382dc972022-01-20 22:18:23 +0000697
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800698 // Validate the Payload Type
699 if (payloadType > maxPayloadSupported)
700 {
701 return ipmi::responseInvalidFieldRequest();
702 }
703
704 // We should support this Payload type 0 command only in KCS Interface
705 if (payloadType == static_cast<uint8_t>(ipmi::PType::IntelXMLType0))
706 {
Arun Lal K M3a1be322022-02-08 21:37:30 +0000707 if (getPostCompleted())
708 {
709 return ipmi::response(ipmiCCNotSupportedInCurrentState);
710 }
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800711 }
712
713 switch (static_cast<PTState>(paramSel))
714 {
715 case ipmi::PTState::StartTransfer:
716 {
717 PayloadStartTransfer* pPayloadStartTransfer =
718 reinterpret_cast<PayloadStartTransfer*>(payload.data());
719 if (payload.size() < sizeof(PayloadStartTransfer))
720 {
721 phosphor::logging::log<phosphor::logging::level::ERR>(
722 "ipmiOEMSetPayload: BIOS Config Payload size is not "
723 "correct");
724 return ipmi::responseReqDataLenInvalid();
725 }
726 cleanUpPayloadFile(payloadType);
727
728 gNVOOBdata.payloadInfo[payloadType].payloadReservationID = rand();
729 gNVOOBdata.payloadInfo[payloadType].payloadTotalChecksum =
730 pPayloadStartTransfer->payloadTotalChecksum;
731 gNVOOBdata.payloadInfo[payloadType].payloadTotalSize =
732 pPayloadStartTransfer->payloadTotalSize;
733 gNVOOBdata.payloadInfo[payloadType].payloadVersion =
734 pPayloadStartTransfer->payloadVersion;
735 gNVOOBdata.payloadInfo[payloadType].actualTotalPayloadWritten = 0;
736 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
737 static_cast<uint8_t>(ipmi::PStatus::Unknown);
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000738 gNVOOBdata.payloadInfo[payloadType].payloadType = payloadType;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800739
740 return ipmi::responseSuccess(
741 gNVOOBdata.payloadInfo[payloadType].payloadReservationID);
742 }
743 break;
744
745 case ipmi::PTState::InProgress:
746 {
747 PayloadInProgress* pPayloadInProgress =
748 reinterpret_cast<PayloadInProgress*>(payload.data());
749 PayloadInfo payloadInfo = gNVOOBdata.payloadInfo[payloadType];
750
751 if (payload.size() < sizeof(PayloadInProgress))
752 {
753 phosphor::logging::log<phosphor::logging::level::ERR>(
754 "BIOS Config Payload size is not correct");
755 return ipmi::responseReqDataLenInvalid();
756 }
757
758 if (pPayloadInProgress->payloadReservationID !=
759 payloadInfo.payloadReservationID)
760 {
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000761 phosphor::logging::log<phosphor::logging::level::ERR>(
762 "BIOS Config Payload reservation ID is not correct");
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800763 return ipmi::responseInvalidReservationId();
764 }
765 payloadInfo.payloadCurrentSize =
766 pPayloadInProgress->payloadCurrentSize;
767 // Need to verify the current Payload Checksum
768 const uint8_t* data =
769 reinterpret_cast<const uint8_t*>(payload.data());
770 // we have to remove the current size, current offset, current
771 // length,checksum bytes , reservation bytes
772 boost::crc_32_type calcChecksum;
773 calcChecksum.process_bytes(data + 16, payload.size() - 16);
774 if (calcChecksum.checksum() !=
775 pPayloadInProgress->payloadCurrentChecksum)
776 {
777 phosphor::logging::log<phosphor::logging::level::ERR>(
778 "ipmiOEMSetPayload: Payload Checksum Failed");
779 return ipmi::response(ipmiCCPayloadChecksumFailed);
780 }
781 // store the data in temp file
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500782 std::string FilePath = "/var/oob/temp" +
783 std::to_string(payloadType);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800784
785 std::ofstream outFile(FilePath, std::ios::binary | std::ios::app);
786 outFile.seekp(pPayloadInProgress->payloadOffset);
787 // we have to remove the current size, current offset, current
788 // length,checksum bytes , reservation bytes
789
790 const char* writedata =
791 reinterpret_cast<const char*>(payload.data());
792 outFile.write(writedata + 16, payload.size() - 16);
793 outFile.close();
794
795 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
796 static_cast<uint8_t>(ipmi::PStatus::Unknown);
797 gNVOOBdata.payloadInfo[payloadType].actualTotalPayloadWritten +=
798 payloadInfo.payloadCurrentSize;
799 return ipmi::responseSuccess(payloadInfo.payloadCurrentSize);
800 }
801 break;
802 case ipmi::PTState::EndTransfer:
803 {
804 PayloadEndTransfer* pPayloadEndTransfer =
805 reinterpret_cast<PayloadEndTransfer*>(payload.data());
806 PayloadInfo payloadInfo = gNVOOBdata.payloadInfo[payloadType];
807 if (pPayloadEndTransfer->payloadReservationID !=
808 payloadInfo.payloadReservationID)
809 {
810 return ipmi::responseInvalidReservationId();
811 }
812 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
813 static_cast<uint8_t>(ipmi::PStatus::Unknown);
814
815 if (gNVOOBdata.payloadInfo[payloadType].actualTotalPayloadWritten !=
816 gNVOOBdata.payloadInfo[payloadType].payloadTotalSize)
817 {
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800818 return ipmi::response(ipmiCCPayloadPayloadInComplete);
819 }
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500820 std::string tempFilePath = "/var/oob/temp" +
821 std::to_string(payloadType);
822 std::string payloadFilePath = "/var/oob/Payload" +
823 std::to_string(payloadType);
824 auto renamestatus = std::rename(tempFilePath.c_str(),
825 payloadFilePath.c_str());
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800826 if (renamestatus)
827 {
828 phosphor::logging::log<phosphor::logging::level::ERR>(
829 "ipmiOEMSetPayload: Renaming Payload file - failed");
830 }
831
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800832 if (payloadType == static_cast<uint8_t>(ipmi::PType::IntelXMLType0))
833 {
834 // Unzip the Intel format XML file type 0
835 auto response = generateBIOSXMLFile("/usr/bin/lzcat", "-d",
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000836 payloadFilePath.c_str());
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800837 if (response)
838 {
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800839 phosphor::logging::log<phosphor::logging::level::ERR>(
840 "ipmiOEMSetPayload: generateBIOSXMLFile - failed");
841 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
842 static_cast<uint8_t>(ipmi::PStatus::Corrupted);
843 return ipmi::response(ipmiCCPayloadPayloadPacketMissed);
844 }
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000845 phosphor::logging::log<phosphor::logging::level::INFO>(
846 " ipmiOEMSetPayload : Convert XML into native-dbus DONE");
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000847
Arun Lal K Me7725612021-07-15 18:20:58 +0000848 /* So that we don't block the call */
849 auto io = getIoContext();
850 auto dbus = getSdBus();
851 if (io && dbus)
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000852 {
Arun Lal K Me7725612021-07-15 18:20:58 +0000853 std::string service = getService(*dbus, biosConfigIntf,
854 biosConfigBaseMgrPath);
855
856 boost::asio::post(*io, [service, payloadType] {
857 generateAndSendAttributesData(service, payloadType);
858 });
859 }
860 else
861 {
862 phosphor::logging::log<phosphor::logging::level::INFO>(
863 "ipmiOEMSetPayload: Unable to get io context or sdbus");
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000864 return ipmi::responseResponseError();
865 }
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800866 }
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800867
868 struct stat filestat;
869
870 /* Get entry's information. */
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000871 if (!stat(payloadFilePath.c_str(), &filestat))
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800872 {
873 gNVOOBdata.payloadInfo[payloadType].payloadTimeStamp =
874 filestat.st_mtime;
875 gNVOOBdata.payloadInfo[payloadType].payloadTotalSize =
876 filestat.st_size;
Snehalatha Venkatesh0d0dc342022-01-20 11:36:56 +0000877 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
878 static_cast<uint8_t>(ipmi::PStatus::Valid);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800879 }
880 else
881 {
882 return ipmi::responseResponseError();
883 }
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800884 flushNVOOBdata();
885 return ipmi::responseSuccess(
886 gNVOOBdata.payloadInfo[payloadType].actualTotalPayloadWritten);
887 }
888 break;
889 case ipmi::PTState::UserAbort:
890 {
891 PayloadEndTransfer* pPayloadEndTransfer =
892 reinterpret_cast<PayloadEndTransfer*>(payload.data());
893 PayloadInfo payloadInfo = gNVOOBdata.payloadInfo[payloadType];
894 if (pPayloadEndTransfer->payloadReservationID !=
895 payloadInfo.payloadReservationID)
896 {
897 return ipmi::responseInvalidReservationId();
898 }
899 gNVOOBdata.payloadInfo[payloadType].payloadReservationID = 0;
900 gNVOOBdata.payloadInfo[payloadType].payloadType = 0;
901 gNVOOBdata.payloadInfo[payloadType].payloadTotalSize = 0;
902 // Delete the temp file
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500903 std::string tempFilePath = "/var/oob/temp" +
904 std::to_string(payloadType);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800905 unlink(tempFilePath.c_str());
906 flushNVOOBdata();
907 return ipmi::responseSuccess();
908 }
909 break;
910 default:
911 return ipmi::responseInvalidFieldRequest();
912 }
913 return ipmi::responseResponseError();
914}
915
916ipmi::RspType<message::Payload>
Vernon Mauerydcff1502022-09-28 11:12:46 -0700917 ipmiOEMGetPayload(ipmi::Context::ptr& ctx, uint8_t paramSel,
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800918 uint8_t payloadType, ipmi::message::Payload& payload)
919{
920 // 1-OOB BIOS config is supported
921 message::Payload retValue;
922
Matt Simmering2daecd62022-05-19 12:50:53 -0700923 if (static_cast<GetPayloadParameter>(paramSel) >=
924 ipmi::GetPayloadParameter::MaxPayloadParameters)
925 {
926 return ipmi::responseInvalidFieldRequest();
927 }
928
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800929 if (!(gNVOOBdata.mBIOSCapabilities.OOBCapability & (biosCapOffsetBit)))
930 {
931 return ipmi::response(ipmiCCBIOSCapabilityInitNotDone);
932 }
933 // Validate the Payload Type
934 if (payloadType > maxPayloadSupported)
935 {
936 return ipmi::responseInvalidFieldRequest();
937 }
938
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000939 if (payloadType == static_cast<uint8_t>(ipmi::PType::IntelXMLType1))
940 {
941 if (!payload1::update(ctx))
942 {
943 phosphor::logging::log<phosphor::logging::level::ERR>(
944 "ipmiOEMGetPayload: unable to update NVOOBdata for payloadType "
945 "= IntelXMLType1");
946 return ipmi::response(ipmi::ccUnspecifiedError);
947 }
948 }
949
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800950 struct PayloadInfo res = gNVOOBdata.payloadInfo[payloadType];
951
952 switch (static_cast<GetPayloadParameter>(paramSel))
953 {
954 case ipmi::GetPayloadParameter::GetPayloadInfo:
955 {
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500956 std::string payloadFilePath = "/var/oob/Payload" +
957 std::to_string(payloadType);
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000958
959 std::ifstream ifs(payloadFilePath,
960 std::ios::in | std::ios::binary | std::ios::ate);
961
962 if (!ifs.good())
963 {
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000964 phosphor::logging::log<phosphor::logging::level::ERR>(
965 "ipmiOEMGetPayload: Payload File Error");
966 // File does not exist code here
967 return ipmi::response(ipmi::ccUnspecifiedError);
968 }
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000969
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000970 ifs.close();
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800971 retValue.pack(res.payloadVersion);
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000972 retValue.pack(payloadType);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800973 retValue.pack(res.payloadTotalSize);
974 retValue.pack(res.payloadTotalChecksum);
975 retValue.pack(res.payloadflag);
976 retValue.pack(res.payloadStatus);
977 retValue.pack(res.payloadTimeStamp);
978
979 return ipmi::responseSuccess(std::move(retValue));
980 }
981
982 break;
983 case ipmi::GetPayloadParameter::GetPayloadData:
984 {
985 if (res.payloadStatus ==
986 (static_cast<uint8_t>(ipmi::PStatus::Valid)))
987 {
988 std::vector<uint32_t> reqData;
989 if (payload.unpack(reqData) || !payload.fullyUnpacked())
990 {
991 return ipmi::responseReqDataLenInvalid();
992 }
993 uint32_t offset = reqData.at(0);
994 uint32_t length = reqData.at(1);
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500995 std::string payloadFilePath = "/var/oob/Payload" +
996 std::to_string(payloadType);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800997
Snehalatha Venkatesh0d0dc342022-01-20 11:36:56 +0000998 if (length > static_cast<uint32_t>(maxGetPayloadDataSize))
Snehalatha Venkatesh2ff15bf2021-12-30 11:51:14 +0000999 {
1000 phosphor::logging::log<phosphor::logging::level::ERR>(
1001 "ipmiOEMGetPayload: length > maxGetPayloadDataSize",
1002 phosphor::logging::entry("LENGTH=%d", length),
1003 phosphor::logging::entry("maxGetPayloadDataSize=%d",
1004 maxGetPayloadDataSize));
1005 return ipmi::responseInvalidFieldRequest();
1006 }
1007
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +00001008 std::ifstream ifs(payloadFilePath, std::ios::in |
1009 std::ios::binary |
1010 std::ios::ate);
1011
1012 if (!ifs.good())
1013 {
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +00001014 phosphor::logging::log<phosphor::logging::level::ERR>(
1015 "ipmiOEMGetPayload: Payload File Error");
1016 // File does not exist code here
1017 return ipmi::response(ipmi::ccUnspecifiedError);
1018 }
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001019 std::ifstream::pos_type fileSize = ifs.tellg();
1020 // Total file data within given offset
Vernon Mauerydcff1502022-09-28 11:12:46 -07001021 if (fileSize < static_cast<int64_t>(offset))
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001022 {
Snehalatha Venkatesh2ff15bf2021-12-30 11:51:14 +00001023 phosphor::logging::log<phosphor::logging::level::ERR>(
1024 "ipmiOEMGetPayload: filesize < offset");
1025 return ipmi::responseInvalidFieldRequest();
1026 }
1027
1028 if ((static_cast<uint64_t>(fileSize) - offset) < length)
1029 {
1030 phosphor::logging::log<phosphor::logging::level::ERR>(
1031 "ipmiOEMGetPayload: (filesize - offset) < length ");
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001032 return ipmi::responseInvalidFieldRequest();
1033 }
1034
1035 ifs.seekg(offset, std::ios::beg);
1036 std::array<uint8_t, maxGetPayloadDataSize> Buffer;
1037 ifs.read(reinterpret_cast<char*>(Buffer.data()), length);
1038 uint32_t readCount = ifs.gcount();
1039 ifs.close();
1040
1041 boost::crc_32_type calcChecksum;
1042 calcChecksum.process_bytes(
1043 reinterpret_cast<char*>(Buffer.data()), readCount);
1044 uint32_t chkSum = calcChecksum.checksum();
1045 retValue.pack(payloadType);
1046 retValue.pack(readCount);
1047 retValue.pack(chkSum);
1048
Vernon Mauerydcff1502022-09-28 11:12:46 -07001049 for (uint32_t i = 0; i < readCount; i++)
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001050 {
1051 retValue.pack(Buffer.at(i));
1052 }
Arun Lal K Mb0caca02021-09-05 22:09:33 +00001053
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001054 return ipmi::responseSuccess(std::move(retValue));
1055 }
1056 else
1057 {
1058 return ipmi::responseResponseError();
1059 }
1060 }
1061 break;
1062 case ipmi::GetPayloadParameter::GetPayloadStatus:
1063 {
1064 retValue.pack(gNVOOBdata.payloadInfo[payloadType].payloadStatus);
1065 return ipmi::responseSuccess(std::move(retValue));
1066 }
1067 break;
1068 default:
1069 return ipmi::responseInvalidFieldRequest();
1070 }
1071 return ipmi::responseInvalidFieldRequest();
1072}
1073
1074ipmi::RspType<> ipmiOEMSetBIOSHashInfo(
Vernon Mauerydcff1502022-09-28 11:12:46 -07001075 ipmi::Context::ptr&, std::array<uint8_t, maxSeedSize>& pwdSeed,
Ayushi Smriti32381872021-06-23 11:05:48 +05301076 uint8_t algoInfo, std::array<uint8_t, maxHashSize>& adminPwdHash)
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001077{
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001078 // We should not support this command after System Booted - After Exit Boot
1079 // service called
Arun Lal K M382dc972022-01-20 22:18:23 +00001080 if (getPostCompleted())
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001081 {
Ayushi Smriti32381872021-06-23 11:05:48 +05301082 return ipmi::response(ipmiCCNotSupportedInCurrentState);
1083 }
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001084
Ayushi Smriti32381872021-06-23 11:05:48 +05301085 nlohmann::json json;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001086
Ayushi Smriti32381872021-06-23 11:05:48 +05301087 if ((algoInfo & 0xF) == algoSHA384)
1088 {
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001089 json["HashAlgo"] = "SHA384";
Ayushi Smriti32381872021-06-23 11:05:48 +05301090 }
1091 else if ((algoInfo & 0xF) == algoSHA256)
1092 {
1093 json["HashAlgo"] = "SHA256";
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001094 }
1095 else
1096 {
Ayushi Smriti32381872021-06-23 11:05:48 +05301097 return ipmi::responseInvalidFieldRequest();
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001098 }
Ayushi Smriti32381872021-06-23 11:05:48 +05301099
1100 json["Seed"] = pwdSeed;
1101 json["IsAdminPwdChanged"] = false;
1102 json["AdminPwdHash"] = adminPwdHash;
1103 json["IsUserPwdChanged"] = false;
1104
1105 std::array<uint8_t, maxHashSize> userPwdHash;
1106 userPwdHash.fill({}); // initializing with 0 as user password hash field
1107 // is not used presently
1108 json["UserPwdHash"] = userPwdHash;
1109 json["StatusFlag"] = algoInfo;
1110
1111 std::string hashFilePath = "/var/lib/bios-settings-manager/seedData";
1112 std::ofstream ofs(hashFilePath, std::ios::out);
1113 const auto& writeData = json.dump();
1114 ofs << writeData;
1115 ofs.close();
1116 return ipmi::responseSuccess();
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001117}
1118
Ayushi Smriti32381872021-06-23 11:05:48 +05301119ipmi::RspType<std::array<uint8_t, maxSeedSize>, uint8_t,
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001120 std::array<uint8_t, maxHashSize>>
Vernon Mauerydcff1502022-09-28 11:12:46 -07001121 ipmiOEMGetBIOSHash(ipmi::Context::ptr&)
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001122{
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001123 nlohmann::json data = nullptr;
1124
Arun Lal K M1d0bac92022-02-11 00:23:13 +00001125 // We should not support this command after System Booted - After Exit Boot
1126 // service called
Arun Lal K M3a1be322022-02-08 21:37:30 +00001127 if (getPostCompleted())
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001128 {
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001129 return ipmi::response(ipmiCCNotSupportedInCurrentState);
1130 }
Arun Lal K M3a1be322022-02-08 21:37:30 +00001131
1132 std::string HashFilePath = "/var/lib/bios-settings-manager/seedData";
1133
1134 std::ifstream devIdFile(HashFilePath);
1135 if (!devIdFile.is_open())
1136 {
1137 return ipmi::responseResponseError();
1138 }
1139
1140 try
1141 {
1142 data = nlohmann::json::parse(devIdFile, nullptr, false);
1143 }
1144 catch (const nlohmann::json::parse_error& e)
1145 {
1146 return ipmi::responseResponseError();
1147 }
1148
1149 if (data.is_discarded())
1150 {
1151 return ipmi::responseResponseError();
1152 }
1153
1154 std::array<uint8_t, maxHashSize> newAdminHash;
1155 std::array<uint8_t, maxSeedSize> seed;
1156
1157 uint8_t flag = 0;
1158 uint8_t adminPwdChangedFlag = 0;
1159 if (!data.is_discarded())
1160 {
Arun Lal K M3a1be322022-02-08 21:37:30 +00001161 adminPwdChangedFlag = data["IsAdminPwdChanged"];
1162 newAdminHash = data["AdminPwdHash"];
1163 seed = data["Seed"];
1164 }
1165
1166 auto status = getResetBIOSSettings(flag);
1167 if (status)
1168 {
1169 return ipmi::responseResponseError();
1170 }
Snehalatha Venkatesh6346e982022-03-09 06:49:18 +00001171 if (flag)
1172 {
1173 flag |= restoreDefaultValues;
1174 }
Arun Lal K M3a1be322022-02-08 21:37:30 +00001175 if (adminPwdChangedFlag)
1176 {
1177 flag |= adminPasswordChanged;
1178 }
1179
1180 std::copy(std::begin(newAdminHash), std::end(newAdminHash),
1181 std::begin(newAdminHash));
1182
1183 return ipmi::responseSuccess(seed, flag, newAdminHash);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001184}
1185
1186static void registerBIOSConfigFunctions(void)
1187{
1188 phosphor::logging::log<phosphor::logging::level::INFO>(
1189 "BIOSConfig module initialization");
1190 InitNVOOBdata();
1191
1192 registerHandler(prioOemBase, intel::netFnGeneral,
1193 intel::general::cmdSetBIOSCap, Privilege::Admin,
1194 ipmiOEMSetBIOSCap);
1195
1196 registerHandler(prioOemBase, intel::netFnGeneral,
1197 intel::general::cmdGetBIOSCap, Privilege::User,
1198 ipmiOEMGetBIOSCap);
1199 registerHandler(prioOemBase, intel::netFnGeneral,
1200 intel::general::cmdSetBIOSPwdHashInfo, Privilege::Admin,
1201 ipmiOEMSetBIOSHashInfo);
1202
1203 registerHandler(prioOemBase, intel::netFnGeneral,
1204 intel::general::cmdGetBIOSPwdHash, Privilege::User,
1205 ipmiOEMGetBIOSHash);
1206
1207 registerHandler(prioOemBase, intel::netFnGeneral,
1208 intel::general::cmdGetPayload, Privilege::User,
1209 ipmiOEMGetPayload);
1210 registerHandler(prioOemBase, intel::netFnGeneral,
1211 intel::general::cmdSetPayload, Privilege::Admin,
1212 ipmiOEMSetPayload);
1213
1214 return;
1215}
1216
1217} // namespace ipmi