blob: 8792e9bf736cfff5678fbeceea7eb4c48692e441 [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);
55
56static constexpr const char* biosConfigFolder = "/var/oob";
57static constexpr const char* biosConfigNVPath = "/var/oob/nvoobdata.dat";
58static constexpr const uint8_t algoSHA384 = 2;
Ayushi Smriti32381872021-06-23 11:05:48 +053059static constexpr const uint8_t algoSHA256 = 1;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +080060static constexpr const uint8_t biosCapOffsetBit = 0x3;
61static constexpr uint16_t maxGetPayloadDataSize = 4096;
62static constexpr const char* biosXMLFilePath = "/var/oob/bios.xml";
63static constexpr const char* biosXMLFilePath1 = "/var/oob/tempbios.xml";
64
65static constexpr const char* biosConfigBaseMgrPath =
66 "/xyz/openbmc_project/bios_config/manager";
67static constexpr const char* biosConfigIntf =
68 "xyz.openbmc_project.BIOSConfig.Manager";
69static constexpr const char* resetBIOSSettingsProp = "ResetBIOSSettings";
70/*baseBIOSTable
71map{attributeName,struct{attributeType,readonlyStatus,displayname,
72 description,menuPath,current,default,
73 array{struct{optionstring,optionvalue}}}}
74*/
Arun Lal K Me7725612021-07-15 18:20:58 +000075
76bios::BiosBaseTableType attributesData;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +080077
78NVOOBdata gNVOOBdata;
79
80enum class PTState : uint8_t
81{
82 StartTransfer = 0,
83 InProgress = 1,
84 EndTransfer = 2,
85 UserAbort = 3
86};
87enum class PStatus : uint8_t
88{
89 Unknown = 0,
90 Valid = 1,
91 Corrupted = 2
92};
93enum class PType : uint8_t
94{
95 IntelXMLType0 = 0,
96 IntelXMLType1 = 1,
97 OTAPayload = 5,
98};
99
100//
101// GetPayload Payload status enumeration
102//
103enum class GetPayloadParameter : uint8_t
104{
105 GetPayloadInfo = 0, // 0
106 GetPayloadData = 1, // 1
107 GetPayloadStatus = 2
108};
109
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000110namespace payload1
111{
112
113enum class AttributesType : uint8_t
114{
115 unknown = 0,
116 string,
Arun Lal K Md2d60ab2021-12-29 19:42:03 +0000117 integer,
118 enumeration
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000119};
120
121using PendingAttributesType =
122 std::map<std::string,
123 std::tuple<std::string, std::variant<int64_t, std::string>>>;
124
125AttributesType getAttrType(const std::string_view typeDbus)
126{
127 if (typeDbus == "xyz.openbmc_project.BIOSConfig.Manager."
128 "AttributeType.String")
129 {
130 return AttributesType::string;
131 }
132 else if (typeDbus == "xyz.openbmc_project.BIOSConfig."
133 "Manager.AttributeType.Integer")
134 {
135 return AttributesType::integer;
136 }
Arun Lal K Md2d60ab2021-12-29 19:42:03 +0000137 else if (typeDbus == "xyz.openbmc_project.BIOSConfig."
138 "Manager.AttributeType.Enumeration")
139 {
140 return AttributesType::enumeration;
141 }
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000142
143 return AttributesType::unknown;
144}
145
146bool fillPayloadData(std::string& payloadData,
147 const std::variant<int64_t, std::string>& attributes,
148 const std::string_view key, AttributesType& attrType)
149{
150 payloadData += key;
151 payloadData += '=';
152
Arun Lal K Md2d60ab2021-12-29 19:42:03 +0000153 if (attrType == AttributesType::string ||
154 attrType == AttributesType::enumeration)
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000155 {
156 if (!std::holds_alternative<std::string>(attributes))
157 {
158 phosphor::logging::log<phosphor::logging::level::ERR>(
159 "fillPayloadData: No string data in attributes");
160 return false;
161 }
162 payloadData += std::get<std::string>(attributes);
163 }
164 else if (attrType == AttributesType::integer)
165 {
166 if (!std::holds_alternative<int64_t>(attributes))
167 {
168 phosphor::logging::log<phosphor::logging::level::ERR>(
169 "fillPayloadData: No int64_t data in attributes");
170 return false;
171 }
172 payloadData += std::to_string(std::get<int64_t>(attributes));
173 }
174 else
175 {
176 phosphor::logging::log<phosphor::logging::level::ERR>(
177 "fillPayloadData: Unsupported attribute type");
178 return false;
179 }
180
181 payloadData += '\n';
182
183 return true;
184}
185
186bool getPendingList(ipmi::Context::ptr ctx, std::string& payloadData)
187{
188 std::variant<PendingAttributesType> pendingAttributesData;
189 boost::system::error_code ec;
190
191 payloadData.clear();
192
193 auto dbus = getSdBus();
194 if (!dbus)
195 {
196 phosphor::logging::log<phosphor::logging::level::ERR>(
197 "getPendingList: getSdBus() failed");
198 return false;
199 }
200
201 std::string service =
202 getService(*dbus, biosConfigIntf, biosConfigBaseMgrPath);
203
204 try
205 {
206 pendingAttributesData =
207 dbus->yield_method_call<std::variant<PendingAttributesType>>(
208 ctx->yield, ec, service,
209 "/xyz/openbmc_project/bios_config/manager",
210 "org.freedesktop.DBus.Properties", "Get",
211 "xyz.openbmc_project.BIOSConfig.Manager", "PendingAttributes");
212 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500213 catch (const std::exception& ex)
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000214 {
215 phosphor::logging::log<phosphor::logging::level::ERR>(ex.what());
216 return false;
217 }
218
219 if (ec)
220 {
221 std::string err = "getPendingList: error while trying to get "
222 "PendingAttributes, error = ";
223 err += ec.message();
224
225 phosphor::logging::log<phosphor::logging::level::ERR>(err.c_str());
226
227 return false;
228 }
229
230 const PendingAttributesType* pendingAttributes =
231 std::get_if<PendingAttributesType>(&pendingAttributesData);
232 if (!pendingAttributes)
233 {
234 phosphor::logging::log<phosphor::logging::level::ERR>(
235 "getPendingList: pendingAttributes is null");
236 return false;
237 }
238
239 for (const auto& [key, attributes] : *pendingAttributes)
240 {
241 const std::string& itemType = std::get<0>(attributes);
242 AttributesType attrType = getAttrType(itemType);
243
244 if (!fillPayloadData(payloadData, std::get<1>(attributes), key,
245 attrType))
246 {
247 return false;
248 }
249 }
250
251 if (payloadData.empty())
252 {
253 phosphor::logging::log<phosphor::logging::level::ERR>(
254 "getPendingList: payloadData is empty");
255 return false;
256 }
257
258 return true;
259}
260bool updatePayloadFile(std::string& payloadFilePath, std::string payloadData)
261{
262 std::ofstream payloadFile(payloadFilePath,
263 std::ios::out | std::ios::binary);
264
265 payloadFile << payloadData;
266
267 if (!payloadFile.good())
268 {
269 return false;
270 }
271
272 return true;
273}
274
275bool computeCheckSum(std::string& payloadFilePath,
276 boost::crc_32_type& calcChecksum)
277{
278 std::ifstream payloadFile(payloadFilePath.c_str(),
279 std::ios::in | std::ios::binary | std::ios::ate);
280
281 if (!payloadFile.good())
282 {
283 phosphor::logging::log<phosphor::logging::level::ERR>(
284 "computeCheckSum: Cannot open Payload1 file");
285 return false;
286 }
287
288 payloadFile.seekg(0, payloadFile.end);
289 int length = payloadFile.tellg();
290 payloadFile.seekg(0, payloadFile.beg);
291
292 if (maxGetPayloadDataSize < length)
293 {
294 phosphor::logging::log<phosphor::logging::level::ERR>(
295 "computeCheckSum: length > maxGetPayloadDataSize");
296 return false;
297 }
298
299 std::unique_ptr<char[]> payloadBuffer(new char[length]);
300
301 payloadFile.read(payloadBuffer.get(), length);
302 uint32_t readCount = payloadFile.gcount();
303
304 calcChecksum.process_bytes(payloadBuffer.get(), readCount);
305
306 return true;
307}
308
309bool updatePayloadInfo(std::string& payloadFilePath)
310{
311 boost::crc_32_type calcChecksum;
312
313 uint8_t payloadType = static_cast<uint8_t>(ipmi::PType::IntelXMLType1);
314 auto& payloadInfo = gNVOOBdata.payloadInfo[payloadType];
315
316 if (!computeCheckSum(payloadFilePath, calcChecksum))
317 {
318 phosphor::logging::log<phosphor::logging::level::ERR>(
319 "updatePayloadInfo: Cannot compute checksum for Payload1 file");
320 return false;
321 }
322
323 payloadInfo.payloadVersion = 0;
324 payloadInfo.payloadflag = 0;
325 payloadInfo.payloadReservationID = rand();
326
327 payloadInfo.payloadType = payloadType;
328
329 payloadInfo.payloadTotalChecksum = calcChecksum.checksum();
330 payloadInfo.payloadCurrentChecksum = payloadInfo.payloadTotalChecksum;
331
332 payloadInfo.payloadStatus = (static_cast<uint8_t>(ipmi::PStatus::Valid));
333
334 struct stat filestat;
335 /* Get entry's information. */
336 if (!stat(payloadFilePath.c_str(), &filestat))
337 {
338 payloadInfo.payloadTimeStamp = filestat.st_mtime;
339 payloadInfo.payloadTotalSize = filestat.st_size;
340 payloadInfo.payloadCurrentSize = filestat.st_size;
341 payloadInfo.actualTotalPayloadWritten = filestat.st_size;
342 }
343 else
344 {
345 phosphor::logging::log<phosphor::logging::level::ERR>(
346 "updatePayloadInfo: Cannot get file status for Payload1 file");
347 return false;
348 }
349
350 if (!flushNVOOBdata())
351 {
352 phosphor::logging::log<phosphor::logging::level::ERR>(
353 "updatePayloadInfo: flushNVOOBdata failed");
354 return false;
355 }
356
357 return true;
358}
359
360bool update(ipmi::Context::ptr ctx)
361{
362 std::string payloadFilePath =
363 "/var/oob/Payload" +
364 std::to_string(static_cast<uint8_t>(ipmi::PType::IntelXMLType1));
365
366 std::string payloadData;
367
368 if (!getPendingList(ctx, payloadData))
369 {
370 phosphor::logging::log<phosphor::logging::level::ERR>(
371 "payload1::update : getPendingList() failed");
372 return false;
373 }
374
375 if (!updatePayloadFile(payloadFilePath, payloadData))
376 {
377 phosphor::logging::log<phosphor::logging::level::ERR>(
378 "payload1::update : updatePayloadFile() failed");
379 return false;
380 }
381
382 if (!updatePayloadInfo(payloadFilePath))
383 {
384 phosphor::logging::log<phosphor::logging::level::ERR>(
385 "payload1::update : updatePayloadInfo() failed");
386 return false;
387 }
388
389 return true;
390}
391} // namespace payload1
392
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800393/** @brief implement to set the BaseBIOSTable property
394 * @returns status
395 */
Arun Lal K Me7725612021-07-15 18:20:58 +0000396static bool sendAllAttributes(std::string service)
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800397{
Arun Lal K Me7725612021-07-15 18:20:58 +0000398 std::shared_ptr<sdbusplus::asio::connection> pSdBusPlus = getSdBus();
399
400 if (pSdBusPlus)
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800401 {
Arun Lal K Me7725612021-07-15 18:20:58 +0000402 try
403 {
404 pSdBusPlus->async_method_call(
405 [](const boost::system::error_code ec) {
406 /* No more need to keep attributes data in memory */
407 attributesData.clear();
408
409 if (ec)
410 {
411 phosphor::logging::log<phosphor::logging::level::ERR>(
412 "sendAllAttributes error: send all attributes - "
413 "failed");
414 return;
415 }
416
417 phosphor::logging::log<phosphor::logging::level::INFO>(
418 "sendAllAttributes: send all attributes - done");
419 },
420 service, biosConfigBaseMgrPath,
421 "org.freedesktop.DBus.Properties", "Set", biosConfigIntf,
422 "BaseBIOSTable",
423 std::variant<bios::BiosBaseTableType>(attributesData));
424
425 return true;
426 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500427 catch (const std::exception& ex)
Arun Lal K Me7725612021-07-15 18:20:58 +0000428 {
429 phosphor::logging::log<phosphor::logging::level::ERR>(ex.what());
430 }
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800431 }
Arun Lal K Me7725612021-07-15 18:20:58 +0000432
433 return false;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800434}
435
436/** @brief implement to flush the updated data in nv space
437 * @returns status
438 */
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000439static bool flushNVOOBdata()
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800440{
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000441 std::ofstream outFile(biosConfigNVPath, std::ios::binary);
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000442
443 outFile.seekp(std::ios_base::beg);
444 const char* writedata = reinterpret_cast<const char*>(&gNVOOBdata);
445 outFile.write(writedata, sizeof(struct NVOOBdata));
446
447 if (!outFile.good())
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800448 {
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000449 return false;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800450 }
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000451
452 return true;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800453}
454
455/** @brief implement to get the System State
456 * @returns status
457 */
Arun Lal K M382dc972022-01-20 22:18:23 +0000458static bool getPostCompleted()
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800459{
Arun Lal K M382dc972022-01-20 22:18:23 +0000460 /*
461 * In case of failure we treat postCompleted as true.
462 * So that BIOS config commands is not accepted by BMC by mistake.
463 */
464 bool postCompleted = true;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800465
466 try
467 {
468 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
469 Value variant =
470 getDbusProperty(*dbus, "xyz.openbmc_project.State.OperatingSystem",
471 "/xyz/openbmc_project/state/os",
472 "xyz.openbmc_project.State.OperatingSystem.Status",
473 "OperatingSystemState");
Arun Lal K M382dc972022-01-20 22:18:23 +0000474 auto& value = std::get<std::string>(variant);
475
476 // The short strings "Standby" is deprecated in favor of the
477 // full enum strings. Support for the short strings will be
478 // removed in the future.
479 postCompleted = (value == "Standby") ||
480 (value == "xyz.openbmc_project.State.OperatingSystem."
481 "Status.OSStatus.Standby");
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800482 }
483 catch (const std::exception& e)
484 {
Arun Lal K M382dc972022-01-20 22:18:23 +0000485 phosphor::logging::log<phosphor::logging::level::ERR>(
486 "'getDbusProperty' failed to read "
487 "xyz.openbmc_project.State.OperatingSystem");
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800488 }
Arun Lal K M382dc972022-01-20 22:18:23 +0000489
490 return postCompleted;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800491}
492
493/** @brief implement to get the Rest BIOS property
494 * @returns status
495 */
496static int getResetBIOSSettings(uint8_t& ResetFlag)
497{
498
499 try
500 {
501 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
502 std::string service =
503 getService(*dbus, biosConfigIntf, biosConfigBaseMgrPath);
504 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{
606
607 boost::process::child execProg(path, const_cast<char*>(tArgs)...,
608 boost::process::std_out > biosXMLFilePath);
609 execProg.wait();
610 return execProg.exit_code();
611}
612
613/** @brief implements to clean up the temp/ existing payload file
614 **/
615static void cleanUpPayloadFile(uint8_t& payloadType)
616{
617 // Clear the payload Information
618 std::string FilePath = "/var/oob/temp" + std::to_string(payloadType);
619 unlink(FilePath.c_str());
620 FilePath = "/var/oob/Payload" + std::to_string(payloadType);
621 unlink(FilePath.c_str());
622 if (payloadType == static_cast<uint8_t>(ipmi::PType::IntelXMLType0))
623 {
624 unlink("/var/oob/Payload1");
625 gNVOOBdata.payloadInfo[static_cast<uint8_t>(ipmi::PType::IntelXMLType1)]
626 .payloadStatus = static_cast<uint8_t>(ipmi::PStatus::Unknown);
627 }
628}
629
630/** @brief implements to create the oob folders and nv space
631 **/
632static Cc InitNVOOBdata()
633{
634 FILE* fptr;
635 uint16_t size;
636
637 if (!(std::filesystem::exists(biosConfigFolder)))
638 {
639 std::filesystem::create_directory(biosConfigFolder);
640 }
641
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000642 std::ifstream ifs(biosConfigNVPath, std::ios::in | std::ios::binary);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800643
644 if (ifs.good())
645 {
646
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000647 ifs.seekg(std::ios_base::beg);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800648 ifs.read(reinterpret_cast<char*>(&gNVOOBdata),
649 sizeof(struct NVOOBdata));
650 ifs.close();
651 return ipmi::ccSuccess;
652 }
653 return ipmi::ccResponseError;
654}
655
656/** @brief implements check the command interface is
657 ** system interface or not
658 ** true mean System interface and false mean LAN or IPMB
659 **/
660static bool IsSystemInterface(ipmi::Context::ptr ctx)
661{
662 ChannelInfo chInfo;
663 Cc status = false;
664
665 try
666 {
667 getChannelInfo(ctx->channel, chInfo);
668 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500669 catch (const sdbusplus::exception_t& e)
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800670 {
671 return false;
672 }
673 if (chInfo.mediumType !=
674 static_cast<uint8_t>(EChannelMediumType::systemInterface))
675 {
676 return false;
677 }
678 return true;
679}
680
681ipmi::RspType<> ipmiOEMSetBIOSCap(ipmi::Context::ptr ctx,
682 uint8_t BIOSCapabilties, uint8_t reserved1,
683 uint8_t reserved2, uint8_t reserved3)
684{
Arun Lal K M382dc972022-01-20 22:18:23 +0000685 if (!getPostCompleted() && IsSystemInterface(ctx))
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800686 {
687 if (reserved1 != 0 || reserved2 != 0 || reserved3 != 0)
688 {
689 return ipmi::responseInvalidFieldRequest();
690 }
691
692 gNVOOBdata.mBIOSCapabilities.OOBCapability = BIOSCapabilties;
693 gNVOOBdata.mIsBIOSCapInitDone = true;
694
695 flushNVOOBdata();
696 return ipmi::responseSuccess();
697 }
698 else
699 {
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800700 return ipmi::response(ipmiCCNotSupportedInCurrentState);
701 }
702}
703
704ipmi::RspType<uint8_t, uint8_t, uint8_t, uint8_t>
705 ipmiOEMGetBIOSCap(ipmi::Context::ptr ctx)
706{
707 if (gNVOOBdata.mIsBIOSCapInitDone)
708 {
709 return ipmi::responseSuccess(gNVOOBdata.mBIOSCapabilities.OOBCapability,
710 0, 0, 0);
711 }
712 else
713 {
714 return ipmi::response(ipmiCCBIOSCapabilityInitNotDone);
715 }
716}
717
718ipmi::RspType<uint32_t> ipmiOEMSetPayload(ipmi::Context::ptr ctx,
719 uint8_t paramSel, uint8_t payloadType,
720 std::vector<uint8_t> payload)
721{
722 uint8_t biosCapOffsetBit = 2; // BIT:1 0-OOB BIOS config not supported
723 // 1-OOB BIOS config is supported
724
725 if (!(gNVOOBdata.mBIOSCapabilities.OOBCapability & (biosCapOffsetBit)))
726 {
727 return ipmi::response(ipmiCCBIOSCapabilityInitNotDone);
728 }
Arun Lal K M382dc972022-01-20 22:18:23 +0000729
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800730 // Validate the Payload Type
731 if (payloadType > maxPayloadSupported)
732 {
733 return ipmi::responseInvalidFieldRequest();
734 }
735
736 // We should support this Payload type 0 command only in KCS Interface
737 if (payloadType == static_cast<uint8_t>(ipmi::PType::IntelXMLType0))
738 {
Arun Lal K M382dc972022-01-20 22:18:23 +0000739 if (!IsSystemInterface(ctx) || getPostCompleted())
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800740 {
741 return ipmi::responseCommandNotAvailable();
742 }
743 }
744
745 switch (static_cast<PTState>(paramSel))
746 {
747 case ipmi::PTState::StartTransfer:
748 {
749 PayloadStartTransfer* pPayloadStartTransfer =
750 reinterpret_cast<PayloadStartTransfer*>(payload.data());
751 if (payload.size() < sizeof(PayloadStartTransfer))
752 {
753 phosphor::logging::log<phosphor::logging::level::ERR>(
754 "ipmiOEMSetPayload: BIOS Config Payload size is not "
755 "correct");
756 return ipmi::responseReqDataLenInvalid();
757 }
758 cleanUpPayloadFile(payloadType);
759
760 gNVOOBdata.payloadInfo[payloadType].payloadReservationID = rand();
761 gNVOOBdata.payloadInfo[payloadType].payloadTotalChecksum =
762 pPayloadStartTransfer->payloadTotalChecksum;
763 gNVOOBdata.payloadInfo[payloadType].payloadTotalSize =
764 pPayloadStartTransfer->payloadTotalSize;
765 gNVOOBdata.payloadInfo[payloadType].payloadVersion =
766 pPayloadStartTransfer->payloadVersion;
767 gNVOOBdata.payloadInfo[payloadType].actualTotalPayloadWritten = 0;
768 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
769 static_cast<uint8_t>(ipmi::PStatus::Unknown);
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000770 gNVOOBdata.payloadInfo[payloadType].payloadType = payloadType;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800771
772 return ipmi::responseSuccess(
773 gNVOOBdata.payloadInfo[payloadType].payloadReservationID);
774 }
775 break;
776
777 case ipmi::PTState::InProgress:
778 {
779 PayloadInProgress* pPayloadInProgress =
780 reinterpret_cast<PayloadInProgress*>(payload.data());
781 PayloadInfo payloadInfo = gNVOOBdata.payloadInfo[payloadType];
782
783 if (payload.size() < sizeof(PayloadInProgress))
784 {
785 phosphor::logging::log<phosphor::logging::level::ERR>(
786 "BIOS Config Payload size is not correct");
787 return ipmi::responseReqDataLenInvalid();
788 }
789
790 if (pPayloadInProgress->payloadReservationID !=
791 payloadInfo.payloadReservationID)
792 {
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000793 phosphor::logging::log<phosphor::logging::level::ERR>(
794 "BIOS Config Payload reservation ID is not correct");
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800795 return ipmi::responseInvalidReservationId();
796 }
797 payloadInfo.payloadCurrentSize =
798 pPayloadInProgress->payloadCurrentSize;
799 // Need to verify the current Payload Checksum
800 const uint8_t* data =
801 reinterpret_cast<const uint8_t*>(payload.data());
802 // we have to remove the current size, current offset, current
803 // length,checksum bytes , reservation bytes
804 boost::crc_32_type calcChecksum;
805 calcChecksum.process_bytes(data + 16, payload.size() - 16);
806 if (calcChecksum.checksum() !=
807 pPayloadInProgress->payloadCurrentChecksum)
808 {
809 phosphor::logging::log<phosphor::logging::level::ERR>(
810 "ipmiOEMSetPayload: Payload Checksum Failed");
811 return ipmi::response(ipmiCCPayloadChecksumFailed);
812 }
813 // store the data in temp file
814 std::string FilePath =
815 "/var/oob/temp" + std::to_string(payloadType);
816
817 std::ofstream outFile(FilePath, std::ios::binary | std::ios::app);
818 outFile.seekp(pPayloadInProgress->payloadOffset);
819 // we have to remove the current size, current offset, current
820 // length,checksum bytes , reservation bytes
821
822 const char* writedata =
823 reinterpret_cast<const char*>(payload.data());
824 outFile.write(writedata + 16, payload.size() - 16);
825 outFile.close();
826
827 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
828 static_cast<uint8_t>(ipmi::PStatus::Unknown);
829 gNVOOBdata.payloadInfo[payloadType].actualTotalPayloadWritten +=
830 payloadInfo.payloadCurrentSize;
831 return ipmi::responseSuccess(payloadInfo.payloadCurrentSize);
832 }
833 break;
834 case ipmi::PTState::EndTransfer:
835 {
836 PayloadEndTransfer* pPayloadEndTransfer =
837 reinterpret_cast<PayloadEndTransfer*>(payload.data());
838 PayloadInfo payloadInfo = gNVOOBdata.payloadInfo[payloadType];
839 if (pPayloadEndTransfer->payloadReservationID !=
840 payloadInfo.payloadReservationID)
841 {
842 return ipmi::responseInvalidReservationId();
843 }
844 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
845 static_cast<uint8_t>(ipmi::PStatus::Unknown);
846
847 if (gNVOOBdata.payloadInfo[payloadType].actualTotalPayloadWritten !=
848 gNVOOBdata.payloadInfo[payloadType].payloadTotalSize)
849 {
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800850 return ipmi::response(ipmiCCPayloadPayloadInComplete);
851 }
852 std::string tempFilePath =
853 "/var/oob/temp" + std::to_string(payloadType);
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000854 std::string payloadFilePath =
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800855 "/var/oob/Payload" + std::to_string(payloadType);
856 auto renamestatus =
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000857 std::rename(tempFilePath.c_str(), payloadFilePath.c_str());
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800858 if (renamestatus)
859 {
860 phosphor::logging::log<phosphor::logging::level::ERR>(
861 "ipmiOEMSetPayload: Renaming Payload file - failed");
862 }
863
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800864 if (payloadType == static_cast<uint8_t>(ipmi::PType::IntelXMLType0))
865 {
866 // Unzip the Intel format XML file type 0
867 auto response = generateBIOSXMLFile("/usr/bin/lzcat", "-d",
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000868 payloadFilePath.c_str());
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800869 if (response)
870 {
871
872 phosphor::logging::log<phosphor::logging::level::ERR>(
873 "ipmiOEMSetPayload: generateBIOSXMLFile - failed");
874 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
875 static_cast<uint8_t>(ipmi::PStatus::Corrupted);
876 return ipmi::response(ipmiCCPayloadPayloadPacketMissed);
877 }
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000878 phosphor::logging::log<phosphor::logging::level::INFO>(
879 " ipmiOEMSetPayload : Convert XML into native-dbus DONE");
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000880
Arun Lal K Me7725612021-07-15 18:20:58 +0000881 /* So that we don't block the call */
882 auto io = getIoContext();
883 auto dbus = getSdBus();
884 if (io && dbus)
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000885 {
Arun Lal K Me7725612021-07-15 18:20:58 +0000886 std::string service = getService(*dbus, biosConfigIntf,
887 biosConfigBaseMgrPath);
888
889 boost::asio::post(*io, [service, payloadType] {
890 generateAndSendAttributesData(service, payloadType);
891 });
892 }
893 else
894 {
895 phosphor::logging::log<phosphor::logging::level::INFO>(
896 "ipmiOEMSetPayload: Unable to get io context or sdbus");
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000897 return ipmi::responseResponseError();
898 }
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800899 }
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800900
901 struct stat filestat;
902
903 /* Get entry's information. */
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000904 if (!stat(payloadFilePath.c_str(), &filestat))
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800905 {
906 gNVOOBdata.payloadInfo[payloadType].payloadTimeStamp =
907 filestat.st_mtime;
908 gNVOOBdata.payloadInfo[payloadType].payloadTotalSize =
909 filestat.st_size;
Snehalatha Venkatesh0d0dc342022-01-20 11:36:56 +0000910 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
911 static_cast<uint8_t>(ipmi::PStatus::Valid);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800912 }
913 else
914 {
915 return ipmi::responseResponseError();
916 }
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800917 flushNVOOBdata();
918 return ipmi::responseSuccess(
919 gNVOOBdata.payloadInfo[payloadType].actualTotalPayloadWritten);
920 }
921 break;
922 case ipmi::PTState::UserAbort:
923 {
924 PayloadEndTransfer* pPayloadEndTransfer =
925 reinterpret_cast<PayloadEndTransfer*>(payload.data());
926 PayloadInfo payloadInfo = gNVOOBdata.payloadInfo[payloadType];
927 if (pPayloadEndTransfer->payloadReservationID !=
928 payloadInfo.payloadReservationID)
929 {
930 return ipmi::responseInvalidReservationId();
931 }
932 gNVOOBdata.payloadInfo[payloadType].payloadReservationID = 0;
933 gNVOOBdata.payloadInfo[payloadType].payloadType = 0;
934 gNVOOBdata.payloadInfo[payloadType].payloadTotalSize = 0;
935 // Delete the temp file
936 std::string tempFilePath =
937 "/var/oob/temp" + std::to_string(payloadType);
938 unlink(tempFilePath.c_str());
939 flushNVOOBdata();
940 return ipmi::responseSuccess();
941 }
942 break;
943 default:
944 return ipmi::responseInvalidFieldRequest();
945 }
946 return ipmi::responseResponseError();
947}
948
949ipmi::RspType<message::Payload>
950 ipmiOEMGetPayload(ipmi::Context::ptr ctx, uint8_t paramSel,
951 uint8_t payloadType, ipmi::message::Payload& payload)
952{
953 // 1-OOB BIOS config is supported
954 message::Payload retValue;
955
956 if (!(gNVOOBdata.mBIOSCapabilities.OOBCapability & (biosCapOffsetBit)))
957 {
958 return ipmi::response(ipmiCCBIOSCapabilityInitNotDone);
959 }
960 // Validate the Payload Type
961 if (payloadType > maxPayloadSupported)
962 {
963 return ipmi::responseInvalidFieldRequest();
964 }
965
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000966 if (payloadType == static_cast<uint8_t>(ipmi::PType::IntelXMLType1))
967 {
968 if (!payload1::update(ctx))
969 {
970 phosphor::logging::log<phosphor::logging::level::ERR>(
971 "ipmiOEMGetPayload: unable to update NVOOBdata for payloadType "
972 "= IntelXMLType1");
973 return ipmi::response(ipmi::ccUnspecifiedError);
974 }
975 }
976
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800977 struct PayloadInfo res = gNVOOBdata.payloadInfo[payloadType];
978
979 switch (static_cast<GetPayloadParameter>(paramSel))
980 {
981 case ipmi::GetPayloadParameter::GetPayloadInfo:
982 {
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000983 std::string payloadFilePath =
984 "/var/oob/Payload" + std::to_string(payloadType);
985
986 std::ifstream ifs(payloadFilePath,
987 std::ios::in | std::ios::binary | std::ios::ate);
988
989 if (!ifs.good())
990 {
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000991 phosphor::logging::log<phosphor::logging::level::ERR>(
992 "ipmiOEMGetPayload: Payload File Error");
993 // File does not exist code here
994 return ipmi::response(ipmi::ccUnspecifiedError);
995 }
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000996
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000997 ifs.close();
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800998 retValue.pack(res.payloadVersion);
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000999 retValue.pack(payloadType);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001000 retValue.pack(res.payloadTotalSize);
1001 retValue.pack(res.payloadTotalChecksum);
1002 retValue.pack(res.payloadflag);
1003 retValue.pack(res.payloadStatus);
1004 retValue.pack(res.payloadTimeStamp);
1005
1006 return ipmi::responseSuccess(std::move(retValue));
1007 }
1008
1009 break;
1010 case ipmi::GetPayloadParameter::GetPayloadData:
1011 {
1012 if (res.payloadStatus ==
1013 (static_cast<uint8_t>(ipmi::PStatus::Valid)))
1014 {
1015 std::vector<uint32_t> reqData;
1016 if (payload.unpack(reqData) || !payload.fullyUnpacked())
1017 {
1018 return ipmi::responseReqDataLenInvalid();
1019 }
1020 uint32_t offset = reqData.at(0);
1021 uint32_t length = reqData.at(1);
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +00001022 std::string payloadFilePath =
1023 "/var/oob/Payload" + std::to_string(payloadType);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001024
Snehalatha Venkatesh0d0dc342022-01-20 11:36:56 +00001025 if (length > static_cast<uint32_t>(maxGetPayloadDataSize))
Snehalatha Venkatesh2ff15bf2021-12-30 11:51:14 +00001026 {
1027 phosphor::logging::log<phosphor::logging::level::ERR>(
1028 "ipmiOEMGetPayload: length > maxGetPayloadDataSize",
1029 phosphor::logging::entry("LENGTH=%d", length),
1030 phosphor::logging::entry("maxGetPayloadDataSize=%d",
1031 maxGetPayloadDataSize));
1032 return ipmi::responseInvalidFieldRequest();
1033 }
1034
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +00001035 std::ifstream ifs(payloadFilePath, std::ios::in |
1036 std::ios::binary |
1037 std::ios::ate);
1038
1039 if (!ifs.good())
1040 {
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +00001041 phosphor::logging::log<phosphor::logging::level::ERR>(
1042 "ipmiOEMGetPayload: Payload File Error");
1043 // File does not exist code here
1044 return ipmi::response(ipmi::ccUnspecifiedError);
1045 }
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001046 std::ifstream::pos_type fileSize = ifs.tellg();
1047 // Total file data within given offset
1048 if (fileSize < static_cast<uint64_t>(offset))
1049 {
Snehalatha Venkatesh2ff15bf2021-12-30 11:51:14 +00001050 phosphor::logging::log<phosphor::logging::level::ERR>(
1051 "ipmiOEMGetPayload: filesize < offset");
1052 return ipmi::responseInvalidFieldRequest();
1053 }
1054
1055 if ((static_cast<uint64_t>(fileSize) - offset) < length)
1056 {
1057 phosphor::logging::log<phosphor::logging::level::ERR>(
1058 "ipmiOEMGetPayload: (filesize - offset) < length ");
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001059 return ipmi::responseInvalidFieldRequest();
1060 }
1061
1062 ifs.seekg(offset, std::ios::beg);
1063 std::array<uint8_t, maxGetPayloadDataSize> Buffer;
1064 ifs.read(reinterpret_cast<char*>(Buffer.data()), length);
1065 uint32_t readCount = ifs.gcount();
1066 ifs.close();
1067
1068 boost::crc_32_type calcChecksum;
1069 calcChecksum.process_bytes(
1070 reinterpret_cast<char*>(Buffer.data()), readCount);
1071 uint32_t chkSum = calcChecksum.checksum();
1072 retValue.pack(payloadType);
1073 retValue.pack(readCount);
1074 retValue.pack(chkSum);
1075
1076 for (int i = 0; i < readCount; i++)
1077 {
1078 retValue.pack(Buffer.at(i));
1079 }
Arun Lal K Mb0caca02021-09-05 22:09:33 +00001080
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001081 return ipmi::responseSuccess(std::move(retValue));
1082 }
1083 else
1084 {
1085 return ipmi::responseResponseError();
1086 }
1087 }
1088 break;
1089 case ipmi::GetPayloadParameter::GetPayloadStatus:
1090 {
1091 retValue.pack(gNVOOBdata.payloadInfo[payloadType].payloadStatus);
1092 return ipmi::responseSuccess(std::move(retValue));
1093 }
1094 break;
1095 default:
1096 return ipmi::responseInvalidFieldRequest();
1097 }
1098 return ipmi::responseInvalidFieldRequest();
1099}
1100
1101ipmi::RspType<> ipmiOEMSetBIOSHashInfo(
1102 ipmi::Context::ptr ctx, std::array<uint8_t, maxSeedSize>& pwdSeed,
Ayushi Smriti32381872021-06-23 11:05:48 +05301103 uint8_t algoInfo, std::array<uint8_t, maxHashSize>& adminPwdHash)
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001104{
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001105 // We should support this command only in KCS Interface
1106 if (!IsSystemInterface(ctx))
1107 {
1108 return ipmi::responseCommandNotAvailable();
1109 }
Arun Lal K M382dc972022-01-20 22:18:23 +00001110
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001111 // We should not support this command after System Booted - After Exit Boot
1112 // service called
Arun Lal K M382dc972022-01-20 22:18:23 +00001113 if (getPostCompleted())
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001114 {
Ayushi Smriti32381872021-06-23 11:05:48 +05301115 return ipmi::response(ipmiCCNotSupportedInCurrentState);
1116 }
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001117
Ayushi Smriti32381872021-06-23 11:05:48 +05301118 nlohmann::json json;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001119
Ayushi Smriti32381872021-06-23 11:05:48 +05301120 if ((algoInfo & 0xF) == algoSHA384)
1121 {
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001122 json["HashAlgo"] = "SHA384";
Ayushi Smriti32381872021-06-23 11:05:48 +05301123 }
1124 else if ((algoInfo & 0xF) == algoSHA256)
1125 {
1126 json["HashAlgo"] = "SHA256";
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001127 }
1128 else
1129 {
Ayushi Smriti32381872021-06-23 11:05:48 +05301130 return ipmi::responseInvalidFieldRequest();
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001131 }
Ayushi Smriti32381872021-06-23 11:05:48 +05301132
1133 json["Seed"] = pwdSeed;
1134 json["IsAdminPwdChanged"] = false;
1135 json["AdminPwdHash"] = adminPwdHash;
1136 json["IsUserPwdChanged"] = false;
1137
1138 std::array<uint8_t, maxHashSize> userPwdHash;
1139 userPwdHash.fill({}); // initializing with 0 as user password hash field
1140 // is not used presently
1141 json["UserPwdHash"] = userPwdHash;
1142 json["StatusFlag"] = algoInfo;
1143
1144 std::string hashFilePath = "/var/lib/bios-settings-manager/seedData";
1145 std::ofstream ofs(hashFilePath, std::ios::out);
1146 const auto& writeData = json.dump();
1147 ofs << writeData;
1148 ofs.close();
1149 return ipmi::responseSuccess();
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001150}
1151
Ayushi Smriti32381872021-06-23 11:05:48 +05301152ipmi::RspType<std::array<uint8_t, maxSeedSize>, uint8_t,
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001153 std::array<uint8_t, maxHashSize>>
1154 ipmiOEMGetBIOSHash(ipmi::Context::ptr ctx)
1155{
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001156 nlohmann::json data = nullptr;
1157
1158 // We should support this command only in KCS Interface
1159 if (!IsSystemInterface(ctx))
1160 {
1161 return ipmi::responseCommandNotAvailable();
1162 }
1163
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001164 // We should not support this command after System Booted - After Exit Boot
1165 // service called
Arun Lal K M382dc972022-01-20 22:18:23 +00001166 if (!getPostCompleted())
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001167 {
Suryakanth Sekarcc402592021-04-01 15:02:10 +05301168 std::string HashFilePath = "/var/lib/bios-settings-manager/seedData";
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001169
1170 std::ifstream devIdFile(HashFilePath);
1171 if (devIdFile.is_open())
1172 {
1173
1174 try
1175 {
1176 data = nlohmann::json::parse(devIdFile, nullptr, false);
1177 }
1178 catch (const nlohmann::json::parse_error& e)
1179 {
1180 return ipmi::responseResponseError();
1181 }
1182
1183 if (data.is_discarded())
1184 {
1185 return ipmi::responseResponseError();
1186 }
1187
1188 std::array<uint8_t, maxHashSize> newAdminHash;
Ayushi Smriti32381872021-06-23 11:05:48 +05301189 std::array<uint8_t, maxSeedSize> seed;
1190
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001191 uint8_t flag = 0;
1192 uint8_t adminPwdChangedFlag = 0;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001193 if (!data.is_discarded())
1194 {
1195
1196 adminPwdChangedFlag = data["IsAdminPwdChanged"];
1197 newAdminHash = data["AdminPwdHash"];
Ayushi Smriti32381872021-06-23 11:05:48 +05301198 seed = data["Seed"];
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001199 }
1200
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001201 auto status = getResetBIOSSettings(flag);
1202 if (status)
1203 {
1204 return ipmi::responseResponseError();
1205 }
1206 if (adminPwdChangedFlag)
1207 {
1208 flag |= adminPasswordChanged;
1209 }
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001210
1211 std::copy(std::begin(newAdminHash), std::end(newAdminHash),
1212 std::begin(newAdminHash));
Ayushi Smriti32381872021-06-23 11:05:48 +05301213
1214 return ipmi::responseSuccess(seed, flag, newAdminHash);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001215 }
1216 else
1217 {
1218 return ipmi::responseResponseError();
1219 }
1220 }
1221 else
1222 {
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001223 return ipmi::response(ipmiCCNotSupportedInCurrentState);
1224 }
1225}
1226
1227static void registerBIOSConfigFunctions(void)
1228{
1229 phosphor::logging::log<phosphor::logging::level::INFO>(
1230 "BIOSConfig module initialization");
1231 InitNVOOBdata();
1232
1233 registerHandler(prioOemBase, intel::netFnGeneral,
1234 intel::general::cmdSetBIOSCap, Privilege::Admin,
1235 ipmiOEMSetBIOSCap);
1236
1237 registerHandler(prioOemBase, intel::netFnGeneral,
1238 intel::general::cmdGetBIOSCap, Privilege::User,
1239 ipmiOEMGetBIOSCap);
1240 registerHandler(prioOemBase, intel::netFnGeneral,
1241 intel::general::cmdSetBIOSPwdHashInfo, Privilege::Admin,
1242 ipmiOEMSetBIOSHashInfo);
1243
1244 registerHandler(prioOemBase, intel::netFnGeneral,
1245 intel::general::cmdGetBIOSPwdHash, Privilege::User,
1246 ipmiOEMGetBIOSHash);
1247
1248 registerHandler(prioOemBase, intel::netFnGeneral,
1249 intel::general::cmdGetPayload, Privilege::User,
1250 ipmiOEMGetPayload);
1251 registerHandler(prioOemBase, intel::netFnGeneral,
1252 intel::general::cmdSetPayload, Privilege::Admin,
1253 ipmiOEMSetPayload);
1254
1255 return;
1256}
1257
1258} // namespace ipmi