blob: a40c978d6fc2d313a3aceaa56ced54f863e89ad7 [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 M3a1be322022-02-08 21:37:30 +0000685 if (!IsSystemInterface(ctx))
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800686 {
Arun Lal K M3a1be322022-02-08 21:37:30 +0000687 return ipmi::responseCommandNotAvailable();
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800688 }
Arun Lal K M3a1be322022-02-08 21:37:30 +0000689
690 if (getPostCompleted())
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800691 {
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800692 return ipmi::response(ipmiCCNotSupportedInCurrentState);
693 }
Arun Lal K M3a1be322022-02-08 21:37:30 +0000694
695 if (reserved1 != 0 || reserved2 != 0 || reserved3 != 0)
696 {
697 return ipmi::responseInvalidFieldRequest();
698 }
699
700 gNVOOBdata.mBIOSCapabilities.OOBCapability = BIOSCapabilties;
701 gNVOOBdata.mIsBIOSCapInitDone = true;
702
703 flushNVOOBdata();
704 return ipmi::responseSuccess();
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800705}
706
707ipmi::RspType<uint8_t, uint8_t, uint8_t, uint8_t>
708 ipmiOEMGetBIOSCap(ipmi::Context::ptr ctx)
709{
710 if (gNVOOBdata.mIsBIOSCapInitDone)
711 {
712 return ipmi::responseSuccess(gNVOOBdata.mBIOSCapabilities.OOBCapability,
713 0, 0, 0);
714 }
715 else
716 {
717 return ipmi::response(ipmiCCBIOSCapabilityInitNotDone);
718 }
719}
720
721ipmi::RspType<uint32_t> ipmiOEMSetPayload(ipmi::Context::ptr ctx,
722 uint8_t paramSel, uint8_t payloadType,
723 std::vector<uint8_t> payload)
724{
725 uint8_t biosCapOffsetBit = 2; // BIT:1 0-OOB BIOS config not supported
726 // 1-OOB BIOS config is supported
727
728 if (!(gNVOOBdata.mBIOSCapabilities.OOBCapability & (biosCapOffsetBit)))
729 {
730 return ipmi::response(ipmiCCBIOSCapabilityInitNotDone);
731 }
Arun Lal K M382dc972022-01-20 22:18:23 +0000732
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800733 // Validate the Payload Type
734 if (payloadType > maxPayloadSupported)
735 {
736 return ipmi::responseInvalidFieldRequest();
737 }
738
739 // We should support this Payload type 0 command only in KCS Interface
740 if (payloadType == static_cast<uint8_t>(ipmi::PType::IntelXMLType0))
741 {
Arun Lal K M3a1be322022-02-08 21:37:30 +0000742 if (!IsSystemInterface(ctx))
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800743 {
744 return ipmi::responseCommandNotAvailable();
745 }
Arun Lal K M3a1be322022-02-08 21:37:30 +0000746
747 if (getPostCompleted())
748 {
749 return ipmi::response(ipmiCCNotSupportedInCurrentState);
750 }
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800751 }
752
753 switch (static_cast<PTState>(paramSel))
754 {
755 case ipmi::PTState::StartTransfer:
756 {
757 PayloadStartTransfer* pPayloadStartTransfer =
758 reinterpret_cast<PayloadStartTransfer*>(payload.data());
759 if (payload.size() < sizeof(PayloadStartTransfer))
760 {
761 phosphor::logging::log<phosphor::logging::level::ERR>(
762 "ipmiOEMSetPayload: BIOS Config Payload size is not "
763 "correct");
764 return ipmi::responseReqDataLenInvalid();
765 }
766 cleanUpPayloadFile(payloadType);
767
768 gNVOOBdata.payloadInfo[payloadType].payloadReservationID = rand();
769 gNVOOBdata.payloadInfo[payloadType].payloadTotalChecksum =
770 pPayloadStartTransfer->payloadTotalChecksum;
771 gNVOOBdata.payloadInfo[payloadType].payloadTotalSize =
772 pPayloadStartTransfer->payloadTotalSize;
773 gNVOOBdata.payloadInfo[payloadType].payloadVersion =
774 pPayloadStartTransfer->payloadVersion;
775 gNVOOBdata.payloadInfo[payloadType].actualTotalPayloadWritten = 0;
776 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
777 static_cast<uint8_t>(ipmi::PStatus::Unknown);
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000778 gNVOOBdata.payloadInfo[payloadType].payloadType = payloadType;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800779
780 return ipmi::responseSuccess(
781 gNVOOBdata.payloadInfo[payloadType].payloadReservationID);
782 }
783 break;
784
785 case ipmi::PTState::InProgress:
786 {
787 PayloadInProgress* pPayloadInProgress =
788 reinterpret_cast<PayloadInProgress*>(payload.data());
789 PayloadInfo payloadInfo = gNVOOBdata.payloadInfo[payloadType];
790
791 if (payload.size() < sizeof(PayloadInProgress))
792 {
793 phosphor::logging::log<phosphor::logging::level::ERR>(
794 "BIOS Config Payload size is not correct");
795 return ipmi::responseReqDataLenInvalid();
796 }
797
798 if (pPayloadInProgress->payloadReservationID !=
799 payloadInfo.payloadReservationID)
800 {
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000801 phosphor::logging::log<phosphor::logging::level::ERR>(
802 "BIOS Config Payload reservation ID is not correct");
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800803 return ipmi::responseInvalidReservationId();
804 }
805 payloadInfo.payloadCurrentSize =
806 pPayloadInProgress->payloadCurrentSize;
807 // Need to verify the current Payload Checksum
808 const uint8_t* data =
809 reinterpret_cast<const uint8_t*>(payload.data());
810 // we have to remove the current size, current offset, current
811 // length,checksum bytes , reservation bytes
812 boost::crc_32_type calcChecksum;
813 calcChecksum.process_bytes(data + 16, payload.size() - 16);
814 if (calcChecksum.checksum() !=
815 pPayloadInProgress->payloadCurrentChecksum)
816 {
817 phosphor::logging::log<phosphor::logging::level::ERR>(
818 "ipmiOEMSetPayload: Payload Checksum Failed");
819 return ipmi::response(ipmiCCPayloadChecksumFailed);
820 }
821 // store the data in temp file
822 std::string FilePath =
823 "/var/oob/temp" + std::to_string(payloadType);
824
825 std::ofstream outFile(FilePath, std::ios::binary | std::ios::app);
826 outFile.seekp(pPayloadInProgress->payloadOffset);
827 // we have to remove the current size, current offset, current
828 // length,checksum bytes , reservation bytes
829
830 const char* writedata =
831 reinterpret_cast<const char*>(payload.data());
832 outFile.write(writedata + 16, payload.size() - 16);
833 outFile.close();
834
835 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
836 static_cast<uint8_t>(ipmi::PStatus::Unknown);
837 gNVOOBdata.payloadInfo[payloadType].actualTotalPayloadWritten +=
838 payloadInfo.payloadCurrentSize;
839 return ipmi::responseSuccess(payloadInfo.payloadCurrentSize);
840 }
841 break;
842 case ipmi::PTState::EndTransfer:
843 {
844 PayloadEndTransfer* pPayloadEndTransfer =
845 reinterpret_cast<PayloadEndTransfer*>(payload.data());
846 PayloadInfo payloadInfo = gNVOOBdata.payloadInfo[payloadType];
847 if (pPayloadEndTransfer->payloadReservationID !=
848 payloadInfo.payloadReservationID)
849 {
850 return ipmi::responseInvalidReservationId();
851 }
852 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
853 static_cast<uint8_t>(ipmi::PStatus::Unknown);
854
855 if (gNVOOBdata.payloadInfo[payloadType].actualTotalPayloadWritten !=
856 gNVOOBdata.payloadInfo[payloadType].payloadTotalSize)
857 {
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800858 return ipmi::response(ipmiCCPayloadPayloadInComplete);
859 }
860 std::string tempFilePath =
861 "/var/oob/temp" + std::to_string(payloadType);
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000862 std::string payloadFilePath =
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800863 "/var/oob/Payload" + std::to_string(payloadType);
864 auto renamestatus =
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000865 std::rename(tempFilePath.c_str(), payloadFilePath.c_str());
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800866 if (renamestatus)
867 {
868 phosphor::logging::log<phosphor::logging::level::ERR>(
869 "ipmiOEMSetPayload: Renaming Payload file - failed");
870 }
871
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800872 if (payloadType == static_cast<uint8_t>(ipmi::PType::IntelXMLType0))
873 {
874 // Unzip the Intel format XML file type 0
875 auto response = generateBIOSXMLFile("/usr/bin/lzcat", "-d",
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000876 payloadFilePath.c_str());
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800877 if (response)
878 {
879
880 phosphor::logging::log<phosphor::logging::level::ERR>(
881 "ipmiOEMSetPayload: generateBIOSXMLFile - failed");
882 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
883 static_cast<uint8_t>(ipmi::PStatus::Corrupted);
884 return ipmi::response(ipmiCCPayloadPayloadPacketMissed);
885 }
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000886 phosphor::logging::log<phosphor::logging::level::INFO>(
887 " ipmiOEMSetPayload : Convert XML into native-dbus DONE");
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000888
Arun Lal K Me7725612021-07-15 18:20:58 +0000889 /* So that we don't block the call */
890 auto io = getIoContext();
891 auto dbus = getSdBus();
892 if (io && dbus)
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000893 {
Arun Lal K Me7725612021-07-15 18:20:58 +0000894 std::string service = getService(*dbus, biosConfigIntf,
895 biosConfigBaseMgrPath);
896
897 boost::asio::post(*io, [service, payloadType] {
898 generateAndSendAttributesData(service, payloadType);
899 });
900 }
901 else
902 {
903 phosphor::logging::log<phosphor::logging::level::INFO>(
904 "ipmiOEMSetPayload: Unable to get io context or sdbus");
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000905 return ipmi::responseResponseError();
906 }
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800907 }
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800908
909 struct stat filestat;
910
911 /* Get entry's information. */
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000912 if (!stat(payloadFilePath.c_str(), &filestat))
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800913 {
914 gNVOOBdata.payloadInfo[payloadType].payloadTimeStamp =
915 filestat.st_mtime;
916 gNVOOBdata.payloadInfo[payloadType].payloadTotalSize =
917 filestat.st_size;
Snehalatha Venkatesh0d0dc342022-01-20 11:36:56 +0000918 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
919 static_cast<uint8_t>(ipmi::PStatus::Valid);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800920 }
921 else
922 {
923 return ipmi::responseResponseError();
924 }
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800925 flushNVOOBdata();
926 return ipmi::responseSuccess(
927 gNVOOBdata.payloadInfo[payloadType].actualTotalPayloadWritten);
928 }
929 break;
930 case ipmi::PTState::UserAbort:
931 {
932 PayloadEndTransfer* pPayloadEndTransfer =
933 reinterpret_cast<PayloadEndTransfer*>(payload.data());
934 PayloadInfo payloadInfo = gNVOOBdata.payloadInfo[payloadType];
935 if (pPayloadEndTransfer->payloadReservationID !=
936 payloadInfo.payloadReservationID)
937 {
938 return ipmi::responseInvalidReservationId();
939 }
940 gNVOOBdata.payloadInfo[payloadType].payloadReservationID = 0;
941 gNVOOBdata.payloadInfo[payloadType].payloadType = 0;
942 gNVOOBdata.payloadInfo[payloadType].payloadTotalSize = 0;
943 // Delete the temp file
944 std::string tempFilePath =
945 "/var/oob/temp" + std::to_string(payloadType);
946 unlink(tempFilePath.c_str());
947 flushNVOOBdata();
948 return ipmi::responseSuccess();
949 }
950 break;
951 default:
952 return ipmi::responseInvalidFieldRequest();
953 }
954 return ipmi::responseResponseError();
955}
956
957ipmi::RspType<message::Payload>
958 ipmiOEMGetPayload(ipmi::Context::ptr ctx, uint8_t paramSel,
959 uint8_t payloadType, ipmi::message::Payload& payload)
960{
961 // 1-OOB BIOS config is supported
962 message::Payload retValue;
963
964 if (!(gNVOOBdata.mBIOSCapabilities.OOBCapability & (biosCapOffsetBit)))
965 {
966 return ipmi::response(ipmiCCBIOSCapabilityInitNotDone);
967 }
968 // Validate the Payload Type
969 if (payloadType > maxPayloadSupported)
970 {
971 return ipmi::responseInvalidFieldRequest();
972 }
973
Arun Lal K Mb0caca02021-09-05 22:09:33 +0000974 if (payloadType == static_cast<uint8_t>(ipmi::PType::IntelXMLType1))
975 {
976 if (!payload1::update(ctx))
977 {
978 phosphor::logging::log<phosphor::logging::level::ERR>(
979 "ipmiOEMGetPayload: unable to update NVOOBdata for payloadType "
980 "= IntelXMLType1");
981 return ipmi::response(ipmi::ccUnspecifiedError);
982 }
983 }
984
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800985 struct PayloadInfo res = gNVOOBdata.payloadInfo[payloadType];
986
987 switch (static_cast<GetPayloadParameter>(paramSel))
988 {
989 case ipmi::GetPayloadParameter::GetPayloadInfo:
990 {
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000991 std::string payloadFilePath =
992 "/var/oob/Payload" + std::to_string(payloadType);
993
994 std::ifstream ifs(payloadFilePath,
995 std::ios::in | std::ios::binary | std::ios::ate);
996
997 if (!ifs.good())
998 {
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000999 phosphor::logging::log<phosphor::logging::level::ERR>(
1000 "ipmiOEMGetPayload: Payload File Error");
1001 // File does not exist code here
1002 return ipmi::response(ipmi::ccUnspecifiedError);
1003 }
Arun Lal K Mb0caca02021-09-05 22:09:33 +00001004
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +00001005 ifs.close();
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001006 retValue.pack(res.payloadVersion);
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +00001007 retValue.pack(payloadType);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001008 retValue.pack(res.payloadTotalSize);
1009 retValue.pack(res.payloadTotalChecksum);
1010 retValue.pack(res.payloadflag);
1011 retValue.pack(res.payloadStatus);
1012 retValue.pack(res.payloadTimeStamp);
1013
1014 return ipmi::responseSuccess(std::move(retValue));
1015 }
1016
1017 break;
1018 case ipmi::GetPayloadParameter::GetPayloadData:
1019 {
1020 if (res.payloadStatus ==
1021 (static_cast<uint8_t>(ipmi::PStatus::Valid)))
1022 {
1023 std::vector<uint32_t> reqData;
1024 if (payload.unpack(reqData) || !payload.fullyUnpacked())
1025 {
1026 return ipmi::responseReqDataLenInvalid();
1027 }
1028 uint32_t offset = reqData.at(0);
1029 uint32_t length = reqData.at(1);
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +00001030 std::string payloadFilePath =
1031 "/var/oob/Payload" + std::to_string(payloadType);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001032
Snehalatha Venkatesh0d0dc342022-01-20 11:36:56 +00001033 if (length > static_cast<uint32_t>(maxGetPayloadDataSize))
Snehalatha Venkatesh2ff15bf2021-12-30 11:51:14 +00001034 {
1035 phosphor::logging::log<phosphor::logging::level::ERR>(
1036 "ipmiOEMGetPayload: length > maxGetPayloadDataSize",
1037 phosphor::logging::entry("LENGTH=%d", length),
1038 phosphor::logging::entry("maxGetPayloadDataSize=%d",
1039 maxGetPayloadDataSize));
1040 return ipmi::responseInvalidFieldRequest();
1041 }
1042
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +00001043 std::ifstream ifs(payloadFilePath, std::ios::in |
1044 std::ios::binary |
1045 std::ios::ate);
1046
1047 if (!ifs.good())
1048 {
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +00001049 phosphor::logging::log<phosphor::logging::level::ERR>(
1050 "ipmiOEMGetPayload: Payload File Error");
1051 // File does not exist code here
1052 return ipmi::response(ipmi::ccUnspecifiedError);
1053 }
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001054 std::ifstream::pos_type fileSize = ifs.tellg();
1055 // Total file data within given offset
1056 if (fileSize < static_cast<uint64_t>(offset))
1057 {
Snehalatha Venkatesh2ff15bf2021-12-30 11:51:14 +00001058 phosphor::logging::log<phosphor::logging::level::ERR>(
1059 "ipmiOEMGetPayload: filesize < offset");
1060 return ipmi::responseInvalidFieldRequest();
1061 }
1062
1063 if ((static_cast<uint64_t>(fileSize) - offset) < length)
1064 {
1065 phosphor::logging::log<phosphor::logging::level::ERR>(
1066 "ipmiOEMGetPayload: (filesize - offset) < length ");
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001067 return ipmi::responseInvalidFieldRequest();
1068 }
1069
1070 ifs.seekg(offset, std::ios::beg);
1071 std::array<uint8_t, maxGetPayloadDataSize> Buffer;
1072 ifs.read(reinterpret_cast<char*>(Buffer.data()), length);
1073 uint32_t readCount = ifs.gcount();
1074 ifs.close();
1075
1076 boost::crc_32_type calcChecksum;
1077 calcChecksum.process_bytes(
1078 reinterpret_cast<char*>(Buffer.data()), readCount);
1079 uint32_t chkSum = calcChecksum.checksum();
1080 retValue.pack(payloadType);
1081 retValue.pack(readCount);
1082 retValue.pack(chkSum);
1083
1084 for (int i = 0; i < readCount; i++)
1085 {
1086 retValue.pack(Buffer.at(i));
1087 }
Arun Lal K Mb0caca02021-09-05 22:09:33 +00001088
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001089 return ipmi::responseSuccess(std::move(retValue));
1090 }
1091 else
1092 {
1093 return ipmi::responseResponseError();
1094 }
1095 }
1096 break;
1097 case ipmi::GetPayloadParameter::GetPayloadStatus:
1098 {
1099 retValue.pack(gNVOOBdata.payloadInfo[payloadType].payloadStatus);
1100 return ipmi::responseSuccess(std::move(retValue));
1101 }
1102 break;
1103 default:
1104 return ipmi::responseInvalidFieldRequest();
1105 }
1106 return ipmi::responseInvalidFieldRequest();
1107}
1108
1109ipmi::RspType<> ipmiOEMSetBIOSHashInfo(
1110 ipmi::Context::ptr ctx, std::array<uint8_t, maxSeedSize>& pwdSeed,
Ayushi Smriti32381872021-06-23 11:05:48 +05301111 uint8_t algoInfo, std::array<uint8_t, maxHashSize>& adminPwdHash)
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001112{
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001113 // We should support this command only in KCS Interface
1114 if (!IsSystemInterface(ctx))
1115 {
1116 return ipmi::responseCommandNotAvailable();
1117 }
Arun Lal K M382dc972022-01-20 22:18:23 +00001118
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001119 // We should not support this command after System Booted - After Exit Boot
1120 // service called
Arun Lal K M382dc972022-01-20 22:18:23 +00001121 if (getPostCompleted())
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001122 {
Ayushi Smriti32381872021-06-23 11:05:48 +05301123 return ipmi::response(ipmiCCNotSupportedInCurrentState);
1124 }
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001125
Ayushi Smriti32381872021-06-23 11:05:48 +05301126 nlohmann::json json;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001127
Ayushi Smriti32381872021-06-23 11:05:48 +05301128 if ((algoInfo & 0xF) == algoSHA384)
1129 {
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001130 json["HashAlgo"] = "SHA384";
Ayushi Smriti32381872021-06-23 11:05:48 +05301131 }
1132 else if ((algoInfo & 0xF) == algoSHA256)
1133 {
1134 json["HashAlgo"] = "SHA256";
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001135 }
1136 else
1137 {
Ayushi Smriti32381872021-06-23 11:05:48 +05301138 return ipmi::responseInvalidFieldRequest();
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001139 }
Ayushi Smriti32381872021-06-23 11:05:48 +05301140
1141 json["Seed"] = pwdSeed;
1142 json["IsAdminPwdChanged"] = false;
1143 json["AdminPwdHash"] = adminPwdHash;
1144 json["IsUserPwdChanged"] = false;
1145
1146 std::array<uint8_t, maxHashSize> userPwdHash;
1147 userPwdHash.fill({}); // initializing with 0 as user password hash field
1148 // is not used presently
1149 json["UserPwdHash"] = userPwdHash;
1150 json["StatusFlag"] = algoInfo;
1151
1152 std::string hashFilePath = "/var/lib/bios-settings-manager/seedData";
1153 std::ofstream ofs(hashFilePath, std::ios::out);
1154 const auto& writeData = json.dump();
1155 ofs << writeData;
1156 ofs.close();
1157 return ipmi::responseSuccess();
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001158}
1159
Ayushi Smriti32381872021-06-23 11:05:48 +05301160ipmi::RspType<std::array<uint8_t, maxSeedSize>, uint8_t,
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001161 std::array<uint8_t, maxHashSize>>
1162 ipmiOEMGetBIOSHash(ipmi::Context::ptr ctx)
1163{
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001164 nlohmann::json data = nullptr;
1165
1166 // We should support this command only in KCS Interface
Arun Lal K M3a1be322022-02-08 21:37:30 +00001167 if (getPostCompleted())
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001168 {
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001169 return ipmi::response(ipmiCCNotSupportedInCurrentState);
1170 }
Arun Lal K M3a1be322022-02-08 21:37:30 +00001171
1172 std::string HashFilePath = "/var/lib/bios-settings-manager/seedData";
1173
1174 std::ifstream devIdFile(HashFilePath);
1175 if (!devIdFile.is_open())
1176 {
1177 return ipmi::responseResponseError();
1178 }
1179
1180 try
1181 {
1182 data = nlohmann::json::parse(devIdFile, nullptr, false);
1183 }
1184 catch (const nlohmann::json::parse_error& e)
1185 {
1186 return ipmi::responseResponseError();
1187 }
1188
1189 if (data.is_discarded())
1190 {
1191 return ipmi::responseResponseError();
1192 }
1193
1194 std::array<uint8_t, maxHashSize> newAdminHash;
1195 std::array<uint8_t, maxSeedSize> seed;
1196
1197 uint8_t flag = 0;
1198 uint8_t adminPwdChangedFlag = 0;
1199 if (!data.is_discarded())
1200 {
1201
1202 adminPwdChangedFlag = data["IsAdminPwdChanged"];
1203 newAdminHash = data["AdminPwdHash"];
1204 seed = data["Seed"];
1205 }
1206
1207 auto status = getResetBIOSSettings(flag);
1208 if (status)
1209 {
1210 return ipmi::responseResponseError();
1211 }
1212 if (adminPwdChangedFlag)
1213 {
1214 flag |= adminPasswordChanged;
1215 }
1216
1217 std::copy(std::begin(newAdminHash), std::end(newAdminHash),
1218 std::begin(newAdminHash));
1219
1220 return ipmi::responseSuccess(seed, flag, newAdminHash);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001221}
1222
1223static void registerBIOSConfigFunctions(void)
1224{
1225 phosphor::logging::log<phosphor::logging::level::INFO>(
1226 "BIOSConfig module initialization");
1227 InitNVOOBdata();
1228
1229 registerHandler(prioOemBase, intel::netFnGeneral,
1230 intel::general::cmdSetBIOSCap, Privilege::Admin,
1231 ipmiOEMSetBIOSCap);
1232
1233 registerHandler(prioOemBase, intel::netFnGeneral,
1234 intel::general::cmdGetBIOSCap, Privilege::User,
1235 ipmiOEMGetBIOSCap);
1236 registerHandler(prioOemBase, intel::netFnGeneral,
1237 intel::general::cmdSetBIOSPwdHashInfo, Privilege::Admin,
1238 ipmiOEMSetBIOSHashInfo);
1239
1240 registerHandler(prioOemBase, intel::netFnGeneral,
1241 intel::general::cmdGetBIOSPwdHash, Privilege::User,
1242 ipmiOEMGetBIOSHash);
1243
1244 registerHandler(prioOemBase, intel::netFnGeneral,
1245 intel::general::cmdGetPayload, Privilege::User,
1246 ipmiOEMGetPayload);
1247 registerHandler(prioOemBase, intel::netFnGeneral,
1248 intel::general::cmdSetPayload, Privilege::Admin,
1249 ipmiOEMSetPayload);
1250
1251 return;
1252}
1253
1254} // namespace ipmi