blob: 8f3baa2d7ff5123e966c7a04f30a28b5fafd8e9a [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
187bool getPendingList(ipmi::Context::ptr ctx, std::string& payloadData)
188{
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
361bool update(ipmi::Context::ptr ctx)
362{
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{
633 FILE* fptr;
634 uint16_t size;
635
636 if (!(std::filesystem::exists(biosConfigFolder)))
637 {
638 std::filesystem::create_directory(biosConfigFolder);
639 }
640
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000641 std::ifstream ifs(biosConfigNVPath, std::ios::in | std::ios::binary);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800642
643 if (ifs.good())
644 {
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000645 ifs.seekg(std::ios_base::beg);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800646 ifs.read(reinterpret_cast<char*>(&gNVOOBdata),
647 sizeof(struct NVOOBdata));
648 ifs.close();
649 return ipmi::ccSuccess;
650 }
651 return ipmi::ccResponseError;
652}
653
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800654ipmi::RspType<> ipmiOEMSetBIOSCap(ipmi::Context::ptr ctx,
655 uint8_t BIOSCapabilties, uint8_t reserved1,
656 uint8_t reserved2, uint8_t reserved3)
657{
Arun Lal K M3a1be322022-02-08 21:37:30 +0000658 if (getPostCompleted())
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800659 {
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800660 return ipmi::response(ipmiCCNotSupportedInCurrentState);
661 }
Arun Lal K M3a1be322022-02-08 21:37:30 +0000662
663 if (reserved1 != 0 || reserved2 != 0 || reserved3 != 0)
664 {
665 return ipmi::responseInvalidFieldRequest();
666 }
667
668 gNVOOBdata.mBIOSCapabilities.OOBCapability = BIOSCapabilties;
669 gNVOOBdata.mIsBIOSCapInitDone = true;
670
671 flushNVOOBdata();
672 return ipmi::responseSuccess();
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800673}
674
675ipmi::RspType<uint8_t, uint8_t, uint8_t, uint8_t>
676 ipmiOEMGetBIOSCap(ipmi::Context::ptr ctx)
677{
678 if (gNVOOBdata.mIsBIOSCapInitDone)
679 {
680 return ipmi::responseSuccess(gNVOOBdata.mBIOSCapabilities.OOBCapability,
681 0, 0, 0);
682 }
683 else
684 {
685 return ipmi::response(ipmiCCBIOSCapabilityInitNotDone);
686 }
687}
688
689ipmi::RspType<uint32_t> ipmiOEMSetPayload(ipmi::Context::ptr ctx,
690 uint8_t paramSel, uint8_t payloadType,
691 std::vector<uint8_t> payload)
692{
693 uint8_t biosCapOffsetBit = 2; // BIT:1 0-OOB BIOS config not supported
694 // 1-OOB BIOS config is supported
695
696 if (!(gNVOOBdata.mBIOSCapabilities.OOBCapability & (biosCapOffsetBit)))
697 {
698 return ipmi::response(ipmiCCBIOSCapabilityInitNotDone);
699 }
Arun Lal K M382dc972022-01-20 22:18:23 +0000700
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800701 // Validate the Payload Type
702 if (payloadType > maxPayloadSupported)
703 {
704 return ipmi::responseInvalidFieldRequest();
705 }
706
707 // We should support this Payload type 0 command only in KCS Interface
708 if (payloadType == static_cast<uint8_t>(ipmi::PType::IntelXMLType0))
709 {
Arun Lal K M3a1be322022-02-08 21:37:30 +0000710 if (getPostCompleted())
711 {
712 return ipmi::response(ipmiCCNotSupportedInCurrentState);
713 }
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800714 }
715
716 switch (static_cast<PTState>(paramSel))
717 {
718 case ipmi::PTState::StartTransfer:
719 {
720 PayloadStartTransfer* pPayloadStartTransfer =
721 reinterpret_cast<PayloadStartTransfer*>(payload.data());
722 if (payload.size() < sizeof(PayloadStartTransfer))
723 {
724 phosphor::logging::log<phosphor::logging::level::ERR>(
725 "ipmiOEMSetPayload: BIOS Config Payload size is not "
726 "correct");
727 return ipmi::responseReqDataLenInvalid();
728 }
729 cleanUpPayloadFile(payloadType);
730
731 gNVOOBdata.payloadInfo[payloadType].payloadReservationID = rand();
732 gNVOOBdata.payloadInfo[payloadType].payloadTotalChecksum =
733 pPayloadStartTransfer->payloadTotalChecksum;
734 gNVOOBdata.payloadInfo[payloadType].payloadTotalSize =
735 pPayloadStartTransfer->payloadTotalSize;
736 gNVOOBdata.payloadInfo[payloadType].payloadVersion =
737 pPayloadStartTransfer->payloadVersion;
738 gNVOOBdata.payloadInfo[payloadType].actualTotalPayloadWritten = 0;
739 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
740 static_cast<uint8_t>(ipmi::PStatus::Unknown);
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000741 gNVOOBdata.payloadInfo[payloadType].payloadType = payloadType;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800742
743 return ipmi::responseSuccess(
744 gNVOOBdata.payloadInfo[payloadType].payloadReservationID);
745 }
746 break;
747
748 case ipmi::PTState::InProgress:
749 {
750 PayloadInProgress* pPayloadInProgress =
751 reinterpret_cast<PayloadInProgress*>(payload.data());
752 PayloadInfo payloadInfo = gNVOOBdata.payloadInfo[payloadType];
753
754 if (payload.size() < sizeof(PayloadInProgress))
755 {
756 phosphor::logging::log<phosphor::logging::level::ERR>(
757 "BIOS Config Payload size is not correct");
758 return ipmi::responseReqDataLenInvalid();
759 }
760
761 if (pPayloadInProgress->payloadReservationID !=
762 payloadInfo.payloadReservationID)
763 {
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000764 phosphor::logging::log<phosphor::logging::level::ERR>(
765 "BIOS Config Payload reservation ID is not correct");
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800766 return ipmi::responseInvalidReservationId();
767 }
768 payloadInfo.payloadCurrentSize =
769 pPayloadInProgress->payloadCurrentSize;
770 // Need to verify the current Payload Checksum
771 const uint8_t* data =
772 reinterpret_cast<const uint8_t*>(payload.data());
773 // we have to remove the current size, current offset, current
774 // length,checksum bytes , reservation bytes
775 boost::crc_32_type calcChecksum;
776 calcChecksum.process_bytes(data + 16, payload.size() - 16);
777 if (calcChecksum.checksum() !=
778 pPayloadInProgress->payloadCurrentChecksum)
779 {
780 phosphor::logging::log<phosphor::logging::level::ERR>(
781 "ipmiOEMSetPayload: Payload Checksum Failed");
782 return ipmi::response(ipmiCCPayloadChecksumFailed);
783 }
784 // store the data in temp file
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500785 std::string FilePath = "/var/oob/temp" +
786 std::to_string(payloadType);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800787
788 std::ofstream outFile(FilePath, std::ios::binary | std::ios::app);
789 outFile.seekp(pPayloadInProgress->payloadOffset);
790 // we have to remove the current size, current offset, current
791 // length,checksum bytes , reservation bytes
792
793 const char* writedata =
794 reinterpret_cast<const char*>(payload.data());
795 outFile.write(writedata + 16, payload.size() - 16);
796 outFile.close();
797
798 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
799 static_cast<uint8_t>(ipmi::PStatus::Unknown);
800 gNVOOBdata.payloadInfo[payloadType].actualTotalPayloadWritten +=
801 payloadInfo.payloadCurrentSize;
802 return ipmi::responseSuccess(payloadInfo.payloadCurrentSize);
803 }
804 break;
805 case ipmi::PTState::EndTransfer:
806 {
807 PayloadEndTransfer* pPayloadEndTransfer =
808 reinterpret_cast<PayloadEndTransfer*>(payload.data());
809 PayloadInfo payloadInfo = gNVOOBdata.payloadInfo[payloadType];
810 if (pPayloadEndTransfer->payloadReservationID !=
811 payloadInfo.payloadReservationID)
812 {
813 return ipmi::responseInvalidReservationId();
814 }
815 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
816 static_cast<uint8_t>(ipmi::PStatus::Unknown);
817
818 if (gNVOOBdata.payloadInfo[payloadType].actualTotalPayloadWritten !=
819 gNVOOBdata.payloadInfo[payloadType].payloadTotalSize)
820 {
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800821 return ipmi::response(ipmiCCPayloadPayloadInComplete);
822 }
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500823 std::string tempFilePath = "/var/oob/temp" +
824 std::to_string(payloadType);
825 std::string payloadFilePath = "/var/oob/Payload" +
826 std::to_string(payloadType);
827 auto renamestatus = std::rename(tempFilePath.c_str(),
828 payloadFilePath.c_str());
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800829 if (renamestatus)
830 {
831 phosphor::logging::log<phosphor::logging::level::ERR>(
832 "ipmiOEMSetPayload: Renaming Payload file - failed");
833 }
834
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800835 if (payloadType == static_cast<uint8_t>(ipmi::PType::IntelXMLType0))
836 {
837 // Unzip the Intel format XML file type 0
838 auto response = generateBIOSXMLFile("/usr/bin/lzcat", "-d",
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000839 payloadFilePath.c_str());
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800840 if (response)
841 {
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800842 phosphor::logging::log<phosphor::logging::level::ERR>(
843 "ipmiOEMSetPayload: generateBIOSXMLFile - failed");
844 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
845 static_cast<uint8_t>(ipmi::PStatus::Corrupted);
846 return ipmi::response(ipmiCCPayloadPayloadPacketMissed);
847 }
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000848 phosphor::logging::log<phosphor::logging::level::INFO>(
849 " ipmiOEMSetPayload : Convert XML into native-dbus DONE");
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000850
Arun Lal K Me7725612021-07-15 18:20:58 +0000851 /* So that we don't block the call */
852 auto io = getIoContext();
853 auto dbus = getSdBus();
854 if (io && dbus)
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000855 {
Arun Lal K Me7725612021-07-15 18:20:58 +0000856 std::string service = getService(*dbus, biosConfigIntf,
857 biosConfigBaseMgrPath);
858
859 boost::asio::post(*io, [service, payloadType] {
860 generateAndSendAttributesData(service, payloadType);
861 });
862 }
863 else
864 {
865 phosphor::logging::log<phosphor::logging::level::INFO>(
866 "ipmiOEMSetPayload: Unable to get io context or sdbus");
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000867 return ipmi::responseResponseError();
868 }
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800869 }
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800870
871 struct stat filestat;
872
873 /* Get entry's information. */
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000874 if (!stat(payloadFilePath.c_str(), &filestat))
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800875 {
876 gNVOOBdata.payloadInfo[payloadType].payloadTimeStamp =
877 filestat.st_mtime;
878 gNVOOBdata.payloadInfo[payloadType].payloadTotalSize =
879 filestat.st_size;
Snehalatha Venkatesh0d0dc342022-01-20 11:36:56 +0000880 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
881 static_cast<uint8_t>(ipmi::PStatus::Valid);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800882 }
883 else
884 {
885 return ipmi::responseResponseError();
886 }
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800887 flushNVOOBdata();
888 return ipmi::responseSuccess(
889 gNVOOBdata.payloadInfo[payloadType].actualTotalPayloadWritten);
890 }
891 break;
892 case ipmi::PTState::UserAbort:
893 {
894 PayloadEndTransfer* pPayloadEndTransfer =
895 reinterpret_cast<PayloadEndTransfer*>(payload.data());
896 PayloadInfo payloadInfo = gNVOOBdata.payloadInfo[payloadType];
897 if (pPayloadEndTransfer->payloadReservationID !=
898 payloadInfo.payloadReservationID)
899 {
900 return ipmi::responseInvalidReservationId();
901 }
902 gNVOOBdata.payloadInfo[payloadType].payloadReservationID = 0;
903 gNVOOBdata.payloadInfo[payloadType].payloadType = 0;
904 gNVOOBdata.payloadInfo[payloadType].payloadTotalSize = 0;
905 // Delete the temp file
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500906 std::string tempFilePath = "/var/oob/temp" +
907 std::to_string(payloadType);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800908 unlink(tempFilePath.c_str());
909 flushNVOOBdata();
910 return ipmi::responseSuccess();
911 }
912 break;
913 default:
914 return ipmi::responseInvalidFieldRequest();
915 }
916 return ipmi::responseResponseError();
917}
918
919ipmi::RspType<message::Payload>
920 ipmiOEMGetPayload(ipmi::Context::ptr ctx, uint8_t paramSel,
921 uint8_t payloadType, ipmi::message::Payload& payload)
922{
923 // 1-OOB BIOS config is supported
924 message::Payload retValue;
925
Matt Simmering2daecd62022-05-19 12:50:53 -0700926 if (static_cast<GetPayloadParameter>(paramSel) >=
927 ipmi::GetPayloadParameter::MaxPayloadParameters)
928 {
929 return ipmi::responseInvalidFieldRequest();
930 }
931
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800932 if (!(gNVOOBdata.mBIOSCapabilities.OOBCapability & (biosCapOffsetBit)))
933 {
934 return ipmi::response(ipmiCCBIOSCapabilityInitNotDone);
935 }
936 // Validate the Payload Type
937 if (payloadType > maxPayloadSupported)
938 {
939 return ipmi::responseInvalidFieldRequest();
940 }
941
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000942 if (payloadType == static_cast<uint8_t>(ipmi::PType::IntelXMLType1))
943 {
944 if (!payload1::update(ctx))
945 {
946 phosphor::logging::log<phosphor::logging::level::ERR>(
947 "ipmiOEMGetPayload: unable to update NVOOBdata for payloadType "
948 "= IntelXMLType1");
949 return ipmi::response(ipmi::ccUnspecifiedError);
950 }
951 }
952
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800953 struct PayloadInfo res = gNVOOBdata.payloadInfo[payloadType];
954
955 switch (static_cast<GetPayloadParameter>(paramSel))
956 {
957 case ipmi::GetPayloadParameter::GetPayloadInfo:
958 {
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500959 std::string payloadFilePath = "/var/oob/Payload" +
960 std::to_string(payloadType);
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000961
962 std::ifstream ifs(payloadFilePath,
963 std::ios::in | std::ios::binary | std::ios::ate);
964
965 if (!ifs.good())
966 {
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000967 phosphor::logging::log<phosphor::logging::level::ERR>(
968 "ipmiOEMGetPayload: Payload File Error");
969 // File does not exist code here
970 return ipmi::response(ipmi::ccUnspecifiedError);
971 }
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000972
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000973 ifs.close();
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800974 retValue.pack(res.payloadVersion);
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000975 retValue.pack(payloadType);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800976 retValue.pack(res.payloadTotalSize);
977 retValue.pack(res.payloadTotalChecksum);
978 retValue.pack(res.payloadflag);
979 retValue.pack(res.payloadStatus);
980 retValue.pack(res.payloadTimeStamp);
981
982 return ipmi::responseSuccess(std::move(retValue));
983 }
984
985 break;
986 case ipmi::GetPayloadParameter::GetPayloadData:
987 {
988 if (res.payloadStatus ==
989 (static_cast<uint8_t>(ipmi::PStatus::Valid)))
990 {
991 std::vector<uint32_t> reqData;
992 if (payload.unpack(reqData) || !payload.fullyUnpacked())
993 {
994 return ipmi::responseReqDataLenInvalid();
995 }
996 uint32_t offset = reqData.at(0);
997 uint32_t length = reqData.at(1);
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500998 std::string payloadFilePath = "/var/oob/Payload" +
999 std::to_string(payloadType);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001000
Snehalatha Venkatesh0d0dc342022-01-20 11:36:56 +00001001 if (length > static_cast<uint32_t>(maxGetPayloadDataSize))
Snehalatha Venkatesh2ff15bf2021-12-30 11:51:14 +00001002 {
1003 phosphor::logging::log<phosphor::logging::level::ERR>(
1004 "ipmiOEMGetPayload: length > maxGetPayloadDataSize",
1005 phosphor::logging::entry("LENGTH=%d", length),
1006 phosphor::logging::entry("maxGetPayloadDataSize=%d",
1007 maxGetPayloadDataSize));
1008 return ipmi::responseInvalidFieldRequest();
1009 }
1010
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +00001011 std::ifstream ifs(payloadFilePath, std::ios::in |
1012 std::ios::binary |
1013 std::ios::ate);
1014
1015 if (!ifs.good())
1016 {
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +00001017 phosphor::logging::log<phosphor::logging::level::ERR>(
1018 "ipmiOEMGetPayload: Payload File Error");
1019 // File does not exist code here
1020 return ipmi::response(ipmi::ccUnspecifiedError);
1021 }
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001022 std::ifstream::pos_type fileSize = ifs.tellg();
1023 // Total file data within given offset
1024 if (fileSize < static_cast<uint64_t>(offset))
1025 {
Snehalatha Venkatesh2ff15bf2021-12-30 11:51:14 +00001026 phosphor::logging::log<phosphor::logging::level::ERR>(
1027 "ipmiOEMGetPayload: filesize < offset");
1028 return ipmi::responseInvalidFieldRequest();
1029 }
1030
1031 if ((static_cast<uint64_t>(fileSize) - offset) < length)
1032 {
1033 phosphor::logging::log<phosphor::logging::level::ERR>(
1034 "ipmiOEMGetPayload: (filesize - offset) < length ");
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001035 return ipmi::responseInvalidFieldRequest();
1036 }
1037
1038 ifs.seekg(offset, std::ios::beg);
1039 std::array<uint8_t, maxGetPayloadDataSize> Buffer;
1040 ifs.read(reinterpret_cast<char*>(Buffer.data()), length);
1041 uint32_t readCount = ifs.gcount();
1042 ifs.close();
1043
1044 boost::crc_32_type calcChecksum;
1045 calcChecksum.process_bytes(
1046 reinterpret_cast<char*>(Buffer.data()), readCount);
1047 uint32_t chkSum = calcChecksum.checksum();
1048 retValue.pack(payloadType);
1049 retValue.pack(readCount);
1050 retValue.pack(chkSum);
1051
1052 for (int i = 0; i < readCount; i++)
1053 {
1054 retValue.pack(Buffer.at(i));
1055 }
Arun Lal K Mb0caca02021-09-05 22:09:33 +00001056
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001057 return ipmi::responseSuccess(std::move(retValue));
1058 }
1059 else
1060 {
1061 return ipmi::responseResponseError();
1062 }
1063 }
1064 break;
1065 case ipmi::GetPayloadParameter::GetPayloadStatus:
1066 {
1067 retValue.pack(gNVOOBdata.payloadInfo[payloadType].payloadStatus);
1068 return ipmi::responseSuccess(std::move(retValue));
1069 }
1070 break;
1071 default:
1072 return ipmi::responseInvalidFieldRequest();
1073 }
1074 return ipmi::responseInvalidFieldRequest();
1075}
1076
1077ipmi::RspType<> ipmiOEMSetBIOSHashInfo(
1078 ipmi::Context::ptr ctx, std::array<uint8_t, maxSeedSize>& pwdSeed,
Ayushi Smriti32381872021-06-23 11:05:48 +05301079 uint8_t algoInfo, std::array<uint8_t, maxHashSize>& adminPwdHash)
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001080{
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001081 // We should not support this command after System Booted - After Exit Boot
1082 // service called
Arun Lal K M382dc972022-01-20 22:18:23 +00001083 if (getPostCompleted())
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001084 {
Ayushi Smriti32381872021-06-23 11:05:48 +05301085 return ipmi::response(ipmiCCNotSupportedInCurrentState);
1086 }
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001087
Ayushi Smriti32381872021-06-23 11:05:48 +05301088 nlohmann::json json;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001089
Ayushi Smriti32381872021-06-23 11:05:48 +05301090 if ((algoInfo & 0xF) == algoSHA384)
1091 {
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001092 json["HashAlgo"] = "SHA384";
Ayushi Smriti32381872021-06-23 11:05:48 +05301093 }
1094 else if ((algoInfo & 0xF) == algoSHA256)
1095 {
1096 json["HashAlgo"] = "SHA256";
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001097 }
1098 else
1099 {
Ayushi Smriti32381872021-06-23 11:05:48 +05301100 return ipmi::responseInvalidFieldRequest();
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001101 }
Ayushi Smriti32381872021-06-23 11:05:48 +05301102
1103 json["Seed"] = pwdSeed;
1104 json["IsAdminPwdChanged"] = false;
1105 json["AdminPwdHash"] = adminPwdHash;
1106 json["IsUserPwdChanged"] = false;
1107
1108 std::array<uint8_t, maxHashSize> userPwdHash;
1109 userPwdHash.fill({}); // initializing with 0 as user password hash field
1110 // is not used presently
1111 json["UserPwdHash"] = userPwdHash;
1112 json["StatusFlag"] = algoInfo;
1113
1114 std::string hashFilePath = "/var/lib/bios-settings-manager/seedData";
1115 std::ofstream ofs(hashFilePath, std::ios::out);
1116 const auto& writeData = json.dump();
1117 ofs << writeData;
1118 ofs.close();
1119 return ipmi::responseSuccess();
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001120}
1121
Ayushi Smriti32381872021-06-23 11:05:48 +05301122ipmi::RspType<std::array<uint8_t, maxSeedSize>, uint8_t,
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001123 std::array<uint8_t, maxHashSize>>
1124 ipmiOEMGetBIOSHash(ipmi::Context::ptr ctx)
1125{
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001126 nlohmann::json data = nullptr;
1127
Arun Lal K M1d0bac92022-02-11 00:23:13 +00001128 // We should not support this command after System Booted - After Exit Boot
1129 // service called
Arun Lal K M3a1be322022-02-08 21:37:30 +00001130 if (getPostCompleted())
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001131 {
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001132 return ipmi::response(ipmiCCNotSupportedInCurrentState);
1133 }
Arun Lal K M3a1be322022-02-08 21:37:30 +00001134
1135 std::string HashFilePath = "/var/lib/bios-settings-manager/seedData";
1136
1137 std::ifstream devIdFile(HashFilePath);
1138 if (!devIdFile.is_open())
1139 {
1140 return ipmi::responseResponseError();
1141 }
1142
1143 try
1144 {
1145 data = nlohmann::json::parse(devIdFile, nullptr, false);
1146 }
1147 catch (const nlohmann::json::parse_error& e)
1148 {
1149 return ipmi::responseResponseError();
1150 }
1151
1152 if (data.is_discarded())
1153 {
1154 return ipmi::responseResponseError();
1155 }
1156
1157 std::array<uint8_t, maxHashSize> newAdminHash;
1158 std::array<uint8_t, maxSeedSize> seed;
1159
1160 uint8_t flag = 0;
1161 uint8_t adminPwdChangedFlag = 0;
1162 if (!data.is_discarded())
1163 {
Arun Lal K M3a1be322022-02-08 21:37:30 +00001164 adminPwdChangedFlag = data["IsAdminPwdChanged"];
1165 newAdminHash = data["AdminPwdHash"];
1166 seed = data["Seed"];
1167 }
1168
1169 auto status = getResetBIOSSettings(flag);
1170 if (status)
1171 {
1172 return ipmi::responseResponseError();
1173 }
Snehalatha Venkatesh6346e982022-03-09 06:49:18 +00001174 if (flag)
1175 {
1176 flag |= restoreDefaultValues;
1177 }
Arun Lal K M3a1be322022-02-08 21:37:30 +00001178 if (adminPwdChangedFlag)
1179 {
1180 flag |= adminPasswordChanged;
1181 }
1182
1183 std::copy(std::begin(newAdminHash), std::end(newAdminHash),
1184 std::begin(newAdminHash));
1185
1186 return ipmi::responseSuccess(seed, flag, newAdminHash);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001187}
1188
1189static void registerBIOSConfigFunctions(void)
1190{
1191 phosphor::logging::log<phosphor::logging::level::INFO>(
1192 "BIOSConfig module initialization");
1193 InitNVOOBdata();
1194
1195 registerHandler(prioOemBase, intel::netFnGeneral,
1196 intel::general::cmdSetBIOSCap, Privilege::Admin,
1197 ipmiOEMSetBIOSCap);
1198
1199 registerHandler(prioOemBase, intel::netFnGeneral,
1200 intel::general::cmdGetBIOSCap, Privilege::User,
1201 ipmiOEMGetBIOSCap);
1202 registerHandler(prioOemBase, intel::netFnGeneral,
1203 intel::general::cmdSetBIOSPwdHashInfo, Privilege::Admin,
1204 ipmiOEMSetBIOSHashInfo);
1205
1206 registerHandler(prioOemBase, intel::netFnGeneral,
1207 intel::general::cmdGetBIOSPwdHash, Privilege::User,
1208 ipmiOEMGetBIOSHash);
1209
1210 registerHandler(prioOemBase, intel::netFnGeneral,
1211 intel::general::cmdGetPayload, Privilege::User,
1212 ipmiOEMGetPayload);
1213 registerHandler(prioOemBase, intel::netFnGeneral,
1214 intel::general::cmdSetPayload, Privilege::Admin,
1215 ipmiOEMSetPayload);
1216
1217 return;
1218}
1219
1220} // namespace ipmi