blob: 673474557cdf941f3dfebbe5113c9f1b39a18c8f [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
17#include <openssl/sha.h>
18#include <tinyxml2.h>
19
20#include <biosconfigcommands.hpp>
21#include <boost/crc.hpp>
22#include <boost/process/child.hpp>
23#include <boost/process/io.hpp>
24#include <ipmid/api.hpp>
25#include <ipmid/message.hpp>
26#include <ipmid/message/types.hpp>
27#include <ipmid/types.hpp>
28#include <ipmid/utils.hpp>
29#include <nlohmann/json.hpp>
30#include <oemcommands.hpp>
31#include <phosphor-logging/elog-errors.hpp>
32#include <phosphor-logging/log.hpp>
33#include <sdbusplus/bus.hpp>
34#include <sdbusplus/message/types.hpp>
35
36#include <filesystem>
Suryakanth Sekarcc402592021-04-01 15:02:10 +053037#include <string_view>
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +080038
39namespace ipmi
40{
41static 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*/
Kuiying Wang01fbd012021-04-22 11:32:56 +080075using BiosBaseTableType =
76 std::map<std::string,
77 std::tuple<std::string, bool, std::string, std::string,
78 std::string, std::variant<int64_t, std::string>,
79 std::variant<int64_t, std::string>,
80 std::vector<std::tuple<
81 std::string, std::variant<int64_t, std::string>>>>>;
82using OptionType =
83 std::vector<std::tuple<std::string, std::variant<int64_t, std::string>>>;
84BiosBaseTableType attributesData;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +080085
86NVOOBdata gNVOOBdata;
87
88enum class PTState : uint8_t
89{
90 StartTransfer = 0,
91 InProgress = 1,
92 EndTransfer = 2,
93 UserAbort = 3
94};
95enum class PStatus : uint8_t
96{
97 Unknown = 0,
98 Valid = 1,
99 Corrupted = 2
100};
101enum class PType : uint8_t
102{
103 IntelXMLType0 = 0,
104 IntelXMLType1 = 1,
105 OTAPayload = 5,
106};
107
108//
109// GetPayload Payload status enumeration
110//
111enum class GetPayloadParameter : uint8_t
112{
113 GetPayloadInfo = 0, // 0
114 GetPayloadData = 1, // 1
115 GetPayloadStatus = 2
116};
117
118/** @brief implement to set the BaseBIOSTable property
119 * @returns status
120 */
121static int sendAllAttributes(ipmi::Context::ptr ctx)
122{
123 boost::system::error_code ec;
124 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
125 std::string service =
126 getService(*dbus, biosConfigIntf, biosConfigBaseMgrPath);
127 ec.clear();
128 ctx->bus->yield_method_call<>(
129 ctx->yield, ec, service, biosConfigBaseMgrPath,
130 "org.freedesktop.DBus.Properties", "Set", biosConfigIntf,
Kuiying Wang01fbd012021-04-22 11:32:56 +0800131 "BaseBIOSTable", std::variant<BiosBaseTableType>(attributesData));
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800132 if (ec)
133 {
134 phosphor::logging::log<phosphor::logging::level::ERR>(
135 "Failed to sendAllAttributes");
136 return -1;
137 }
138 return 0;
139}
140
141/** @brief implement to flush the updated data in nv space
142 * @returns status
143 */
144static uint8_t flushNVOOBdata()
145{
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000146 std::ofstream outFile(biosConfigNVPath, std::ios::binary);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800147 if (outFile.good())
148 {
149 outFile.seekp(std::ios_base::beg);
150 const char* writedata = reinterpret_cast<const char*>(&gNVOOBdata);
151 outFile.write(writedata, sizeof(struct NVOOBdata));
152 outFile.close();
153 }
154 return 0;
155}
156
157/** @brief implement to get the System State
158 * @returns status
159 */
160
161static int getSystemOSState(std::string& OsStatus)
162{
163
164 try
165 {
166 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
167 Value variant =
168 getDbusProperty(*dbus, "xyz.openbmc_project.State.OperatingSystem",
169 "/xyz/openbmc_project/state/os",
170 "xyz.openbmc_project.State.OperatingSystem.Status",
171 "OperatingSystemState");
172 OsStatus = std::get<std::string>(variant);
173 return ipmi::ccSuccess;
174 }
175 catch (const std::exception& e)
176 {
177 return ipmi::ccUnspecifiedError;
178 }
179}
180
181/** @brief implement to get the Rest BIOS property
182 * @returns status
183 */
184static int getResetBIOSSettings(uint8_t& ResetFlag)
185{
186
187 try
188 {
189 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
190 std::string service =
191 getService(*dbus, biosConfigIntf, biosConfigBaseMgrPath);
192 Value variant = getDbusProperty(*dbus, service, biosConfigBaseMgrPath,
193 biosConfigIntf, resetBIOSSettingsProp);
Suryakanth Sekarcc402592021-04-01 15:02:10 +0530194
195 std::string_view ResetStr = std::get<std::string>(variant);
196 if (ResetStr ==
197 "xyz.openbmc_project.BIOSConfig.Manager.ResetFlag.NoAction")
198 {
199 ResetFlag = 0;
200 }
201 else if (ResetStr == "xyz.openbmc_project.BIOSConfig.Manager.ResetFlag."
202 "FactoryDefaults")
203 {
204 ResetFlag = 1;
205 }
206 else if (ResetStr == "xyz.openbmc_project.BIOSConfig.Manager.ResetFlag."
207 "FailSafeDefaults")
208 {
209 ResetFlag = 2;
210 }
211 else
212 {
213 return ipmi::ccUnspecifiedError;
214 }
215
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800216 return ipmi::ccSuccess;
217 }
218 catch (const std::exception& e)
219 {
220 return ipmi::ccUnspecifiedError;
221 }
222}
223
224/** @brief implement generate naive- dbus from XML file
225 * @returns status
226 */
227static int generateAttributesData()
228{
229 // Open the bios.xml and parse it
230 // Extract the needed data and store it in AttributesData variable
231 // Close the bios.xml
232 phosphor::logging::log<phosphor::logging::level::ERR>(
233 "generateAttributesData");
234 tinyxml2::XMLDocument xmlDoc;
235
236 xmlDoc.LoadFile(biosXMLFilePath);
237 tinyxml2::XMLNode* pRoot = xmlDoc.FirstChild();
238 if (pRoot == nullptr)
239 {
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000240 return ipmi::ccUnspecifiedError;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800241 }
242 tinyxml2::XMLElement* pElement = pRoot->FirstChildElement("biosknobs");
243 if (pElement == nullptr)
244 {
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000245 return ipmi::ccUnspecifiedError;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800246 }
247 tinyxml2::XMLElement* pKnobsElement = pElement->FirstChildElement("knob");
248
249 while (pKnobsElement != nullptr)
250 {
251 bool readOnlyStatus = false;
252 std::string attrType =
253 "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.String";
254 std::string name, curvalue, dname, menupath, defaultvalue, description;
255 name = pKnobsElement->Attribute("name")
256 ? pKnobsElement->Attribute("name")
257 : "";
258 curvalue = pKnobsElement->Attribute("CurrentVal")
259 ? pKnobsElement->Attribute("CurrentVal")
260 : "";
261 dname = pKnobsElement->Attribute("prompt")
262 ? pKnobsElement->Attribute("prompt")
263 : "";
264 menupath = pKnobsElement->Attribute("SetupPgPtr")
265 ? pKnobsElement->Attribute("SetupPgPtr")
266 : "";
267 defaultvalue = pKnobsElement->Attribute("default")
268 ? pKnobsElement->Attribute("default")
269 : "";
270 description = pKnobsElement->Attribute("description")
271 ? pKnobsElement->Attribute("description")
272 : "";
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800273 if (!name.empty() && !curvalue.empty() && !dname.empty() &&
274 !menupath.empty() && !defaultvalue.empty())
275 {
276 std::string rootPath = "./" + std::string(menupath);
277
Kuiying Wang01fbd012021-04-22 11:32:56 +0800278 OptionType optionArray;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800279 tinyxml2::XMLElement* pOptionsElement =
280 pKnobsElement->FirstChildElement("options");
281 nlohmann::json optionsArray = nlohmann::json::array();
282 if (pOptionsElement != nullptr)
283 {
284 tinyxml2::XMLElement* pOptionElement =
285 pOptionsElement->FirstChildElement("option");
286 while (pOptionElement != nullptr)
287 {
Kuiying Wang01fbd012021-04-22 11:32:56 +0800288 const std::string optType =
289 "xyz.openbmc_project.BIOSConfig.Manager.BoundType."
290 "OneOf";
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800291 const std::string attrValue =
292 pOptionElement->Attribute("value");
Kuiying Wang01fbd012021-04-22 11:32:56 +0800293 if (!optType.empty() && !attrValue.empty())
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800294 {
295
Kuiying Wang01fbd012021-04-22 11:32:56 +0800296 optionArray.push_back(
297 std::make_pair(optType, attrValue));
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800298 }
299 pOptionElement =
300 pOptionElement->NextSiblingElement("option");
301 }
302 }
303
Kuiying Wang01fbd012021-04-22 11:32:56 +0800304 attributesData.emplace(std::make_pair(
305 name, std::make_tuple(attrType, readOnlyStatus, dname,
306 description, rootPath, curvalue,
307 defaultvalue, optionArray)));
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800308 }
309 pKnobsElement = pKnobsElement->NextSiblingElement("knob");
310 }
311
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000312 return ipmi::ccSuccess;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800313}
314
315/** @brief implement executing the linux command to uncompress and generate the
316 * xmlfile
317 * @param[in] linux command
318 * @returns status
319 */
320template <typename... ArgTypes>
321static int generateBIOSXMLFile(const char* path, ArgTypes&&... tArgs)
322{
323
324 boost::process::child execProg(path, const_cast<char*>(tArgs)...,
325 boost::process::std_out > biosXMLFilePath);
326 execProg.wait();
327 return execProg.exit_code();
328}
329
330/** @brief implements to clean up the temp/ existing payload file
331 **/
332static void cleanUpPayloadFile(uint8_t& payloadType)
333{
334 // Clear the payload Information
335 std::string FilePath = "/var/oob/temp" + std::to_string(payloadType);
336 unlink(FilePath.c_str());
337 FilePath = "/var/oob/Payload" + std::to_string(payloadType);
338 unlink(FilePath.c_str());
339 if (payloadType == static_cast<uint8_t>(ipmi::PType::IntelXMLType0))
340 {
341 unlink("/var/oob/Payload1");
342 gNVOOBdata.payloadInfo[static_cast<uint8_t>(ipmi::PType::IntelXMLType1)]
343 .payloadStatus = static_cast<uint8_t>(ipmi::PStatus::Unknown);
344 }
345}
346
347/** @brief implements to create the oob folders and nv space
348 **/
349static Cc InitNVOOBdata()
350{
351 FILE* fptr;
352 uint16_t size;
353
354 if (!(std::filesystem::exists(biosConfigFolder)))
355 {
356 std::filesystem::create_directory(biosConfigFolder);
357 }
358
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000359 std::ifstream ifs(biosConfigNVPath, std::ios::in | std::ios::binary);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800360
361 if (ifs.good())
362 {
363
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000364 ifs.seekg(std::ios_base::beg);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800365 ifs.read(reinterpret_cast<char*>(&gNVOOBdata),
366 sizeof(struct NVOOBdata));
367 ifs.close();
368 return ipmi::ccSuccess;
369 }
370 return ipmi::ccResponseError;
371}
372
373/** @brief implements check the command interface is
374 ** system interface or not
375 ** true mean System interface and false mean LAN or IPMB
376 **/
377static bool IsSystemInterface(ipmi::Context::ptr ctx)
378{
379 ChannelInfo chInfo;
380 Cc status = false;
381
382 try
383 {
384 getChannelInfo(ctx->channel, chInfo);
385 }
386 catch (sdbusplus::exception_t& e)
387 {
388 return false;
389 }
390 if (chInfo.mediumType !=
391 static_cast<uint8_t>(EChannelMediumType::systemInterface))
392 {
393 return false;
394 }
395 return true;
396}
397
398ipmi::RspType<> ipmiOEMSetBIOSCap(ipmi::Context::ptr ctx,
399 uint8_t BIOSCapabilties, uint8_t reserved1,
400 uint8_t reserved2, uint8_t reserved3)
401{
402 std::string OSState;
403 getSystemOSState(OSState);
404
405 if (OSState != "OperatingState" && IsSystemInterface(ctx))
406 {
407 if (reserved1 != 0 || reserved2 != 0 || reserved3 != 0)
408 {
409 return ipmi::responseInvalidFieldRequest();
410 }
411
412 gNVOOBdata.mBIOSCapabilities.OOBCapability = BIOSCapabilties;
413 gNVOOBdata.mIsBIOSCapInitDone = true;
414
415 flushNVOOBdata();
416 return ipmi::responseSuccess();
417 }
418 else
419 {
420
421 return ipmi::response(ipmiCCNotSupportedInCurrentState);
422 }
423}
424
425ipmi::RspType<uint8_t, uint8_t, uint8_t, uint8_t>
426 ipmiOEMGetBIOSCap(ipmi::Context::ptr ctx)
427{
428 if (gNVOOBdata.mIsBIOSCapInitDone)
429 {
430 return ipmi::responseSuccess(gNVOOBdata.mBIOSCapabilities.OOBCapability,
431 0, 0, 0);
432 }
433 else
434 {
435 return ipmi::response(ipmiCCBIOSCapabilityInitNotDone);
436 }
437}
438
439ipmi::RspType<uint32_t> ipmiOEMSetPayload(ipmi::Context::ptr ctx,
440 uint8_t paramSel, uint8_t payloadType,
441 std::vector<uint8_t> payload)
442{
443 uint8_t biosCapOffsetBit = 2; // BIT:1 0-OOB BIOS config not supported
444 // 1-OOB BIOS config is supported
445
446 if (!(gNVOOBdata.mBIOSCapabilities.OOBCapability & (biosCapOffsetBit)))
447 {
448 return ipmi::response(ipmiCCBIOSCapabilityInitNotDone);
449 }
450 // Validate the Payload Type
451 if (payloadType > maxPayloadSupported)
452 {
453 return ipmi::responseInvalidFieldRequest();
454 }
455
456 // We should support this Payload type 0 command only in KCS Interface
457 if (payloadType == static_cast<uint8_t>(ipmi::PType::IntelXMLType0))
458 {
459 std::string OSState;
460
461 getSystemOSState(OSState);
462 if (!IsSystemInterface(ctx) || OSState == "OperatingState")
463 {
464 return ipmi::responseCommandNotAvailable();
465 }
466 }
467
468 switch (static_cast<PTState>(paramSel))
469 {
470 case ipmi::PTState::StartTransfer:
471 {
472 PayloadStartTransfer* pPayloadStartTransfer =
473 reinterpret_cast<PayloadStartTransfer*>(payload.data());
474 if (payload.size() < sizeof(PayloadStartTransfer))
475 {
476 phosphor::logging::log<phosphor::logging::level::ERR>(
477 "ipmiOEMSetPayload: BIOS Config Payload size is not "
478 "correct");
479 return ipmi::responseReqDataLenInvalid();
480 }
481 cleanUpPayloadFile(payloadType);
482
483 gNVOOBdata.payloadInfo[payloadType].payloadReservationID = rand();
484 gNVOOBdata.payloadInfo[payloadType].payloadTotalChecksum =
485 pPayloadStartTransfer->payloadTotalChecksum;
486 gNVOOBdata.payloadInfo[payloadType].payloadTotalSize =
487 pPayloadStartTransfer->payloadTotalSize;
488 gNVOOBdata.payloadInfo[payloadType].payloadVersion =
489 pPayloadStartTransfer->payloadVersion;
490 gNVOOBdata.payloadInfo[payloadType].actualTotalPayloadWritten = 0;
491 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
492 static_cast<uint8_t>(ipmi::PStatus::Unknown);
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000493 gNVOOBdata.payloadInfo[payloadType].payloadType = payloadType;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800494
495 return ipmi::responseSuccess(
496 gNVOOBdata.payloadInfo[payloadType].payloadReservationID);
497 }
498 break;
499
500 case ipmi::PTState::InProgress:
501 {
502 PayloadInProgress* pPayloadInProgress =
503 reinterpret_cast<PayloadInProgress*>(payload.data());
504 PayloadInfo payloadInfo = gNVOOBdata.payloadInfo[payloadType];
505
506 if (payload.size() < sizeof(PayloadInProgress))
507 {
508 phosphor::logging::log<phosphor::logging::level::ERR>(
509 "BIOS Config Payload size is not correct");
510 return ipmi::responseReqDataLenInvalid();
511 }
512
513 if (pPayloadInProgress->payloadReservationID !=
514 payloadInfo.payloadReservationID)
515 {
516 return ipmi::responseInvalidReservationId();
517 }
518 payloadInfo.payloadCurrentSize =
519 pPayloadInProgress->payloadCurrentSize;
520 // Need to verify the current Payload Checksum
521 const uint8_t* data =
522 reinterpret_cast<const uint8_t*>(payload.data());
523 // we have to remove the current size, current offset, current
524 // length,checksum bytes , reservation bytes
525 boost::crc_32_type calcChecksum;
526 calcChecksum.process_bytes(data + 16, payload.size() - 16);
527 if (calcChecksum.checksum() !=
528 pPayloadInProgress->payloadCurrentChecksum)
529 {
530 phosphor::logging::log<phosphor::logging::level::ERR>(
531 "ipmiOEMSetPayload: Payload Checksum Failed");
532 return ipmi::response(ipmiCCPayloadChecksumFailed);
533 }
534 // store the data in temp file
535 std::string FilePath =
536 "/var/oob/temp" + std::to_string(payloadType);
537
538 std::ofstream outFile(FilePath, std::ios::binary | std::ios::app);
539 outFile.seekp(pPayloadInProgress->payloadOffset);
540 // we have to remove the current size, current offset, current
541 // length,checksum bytes , reservation bytes
542
543 const char* writedata =
544 reinterpret_cast<const char*>(payload.data());
545 outFile.write(writedata + 16, payload.size() - 16);
546 outFile.close();
547
548 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
549 static_cast<uint8_t>(ipmi::PStatus::Unknown);
550 gNVOOBdata.payloadInfo[payloadType].actualTotalPayloadWritten +=
551 payloadInfo.payloadCurrentSize;
552 return ipmi::responseSuccess(payloadInfo.payloadCurrentSize);
553 }
554 break;
555 case ipmi::PTState::EndTransfer:
556 {
557 PayloadEndTransfer* pPayloadEndTransfer =
558 reinterpret_cast<PayloadEndTransfer*>(payload.data());
559 PayloadInfo payloadInfo = gNVOOBdata.payloadInfo[payloadType];
560 if (pPayloadEndTransfer->payloadReservationID !=
561 payloadInfo.payloadReservationID)
562 {
563 return ipmi::responseInvalidReservationId();
564 }
565 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
566 static_cast<uint8_t>(ipmi::PStatus::Unknown);
567
568 if (gNVOOBdata.payloadInfo[payloadType].actualTotalPayloadWritten !=
569 gNVOOBdata.payloadInfo[payloadType].payloadTotalSize)
570 {
571
572 return ipmi::response(ipmiCCPayloadPayloadInComplete);
573 }
574 std::string tempFilePath =
575 "/var/oob/temp" + std::to_string(payloadType);
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000576 std::string payloadFilePath =
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800577 "/var/oob/Payload" + std::to_string(payloadType);
578 auto renamestatus =
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000579 std::rename(tempFilePath.c_str(), payloadFilePath.c_str());
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800580 if (renamestatus)
581 {
582 phosphor::logging::log<phosphor::logging::level::ERR>(
583 "ipmiOEMSetPayload: Renaming Payload file - failed");
584 }
585
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800586 if (payloadType == static_cast<uint8_t>(ipmi::PType::IntelXMLType0))
587 {
588 // Unzip the Intel format XML file type 0
589 auto response = generateBIOSXMLFile("/usr/bin/lzcat", "-d",
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000590 payloadFilePath.c_str());
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800591 if (response)
592 {
593
594 phosphor::logging::log<phosphor::logging::level::ERR>(
595 "ipmiOEMSetPayload: generateBIOSXMLFile - failed");
596 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
597 static_cast<uint8_t>(ipmi::PStatus::Corrupted);
598 return ipmi::response(ipmiCCPayloadPayloadPacketMissed);
599 }
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000600 phosphor::logging::log<phosphor::logging::level::INFO>(
601 " ipmiOEMSetPayload : Convert XML into native-dbus DONE");
602 response = generateAttributesData();
603 if (response)
604 {
605 phosphor::logging::log<phosphor::logging::level::ERR>(
606 "ipmiOEMSetPayload: generateAttributesData - failed");
607 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
608 static_cast<uint8_t>(ipmi::PStatus::Corrupted);
609 return ipmi::responseResponseError();
610 }
611
612 phosphor::logging::log<phosphor::logging::level::INFO>(
613 " ipmiOEMSetPayload : BaseBIOSTable Property is set");
614 response = sendAllAttributes(ctx);
615 if (response)
616 {
617 phosphor::logging::log<phosphor::logging::level::ERR>(
618 "ipmiOEMSetPayload: sendAllAttributes - failed");
619 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
620 static_cast<uint8_t>(ipmi::PStatus::Corrupted);
621 return ipmi::responseResponseError();
622 }
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800623 }
624 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
625 static_cast<uint8_t>(ipmi::PStatus::Valid);
626
627 struct stat filestat;
628
629 /* Get entry's information. */
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000630 if (!stat(payloadFilePath.c_str(), &filestat))
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800631 {
632 gNVOOBdata.payloadInfo[payloadType].payloadTimeStamp =
633 filestat.st_mtime;
634 gNVOOBdata.payloadInfo[payloadType].payloadTotalSize =
635 filestat.st_size;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800636 }
637 else
638 {
639 return ipmi::responseResponseError();
640 }
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800641 flushNVOOBdata();
642 return ipmi::responseSuccess(
643 gNVOOBdata.payloadInfo[payloadType].actualTotalPayloadWritten);
644 }
645 break;
646 case ipmi::PTState::UserAbort:
647 {
648 PayloadEndTransfer* pPayloadEndTransfer =
649 reinterpret_cast<PayloadEndTransfer*>(payload.data());
650 PayloadInfo payloadInfo = gNVOOBdata.payloadInfo[payloadType];
651 if (pPayloadEndTransfer->payloadReservationID !=
652 payloadInfo.payloadReservationID)
653 {
654 return ipmi::responseInvalidReservationId();
655 }
656 gNVOOBdata.payloadInfo[payloadType].payloadReservationID = 0;
657 gNVOOBdata.payloadInfo[payloadType].payloadType = 0;
658 gNVOOBdata.payloadInfo[payloadType].payloadTotalSize = 0;
659 // Delete the temp file
660 std::string tempFilePath =
661 "/var/oob/temp" + std::to_string(payloadType);
662 unlink(tempFilePath.c_str());
663 flushNVOOBdata();
664 return ipmi::responseSuccess();
665 }
666 break;
667 default:
668 return ipmi::responseInvalidFieldRequest();
669 }
670 return ipmi::responseResponseError();
671}
672
673ipmi::RspType<message::Payload>
674 ipmiOEMGetPayload(ipmi::Context::ptr ctx, uint8_t paramSel,
675 uint8_t payloadType, ipmi::message::Payload& payload)
676{
677 // 1-OOB BIOS config is supported
678 message::Payload retValue;
679
680 if (!(gNVOOBdata.mBIOSCapabilities.OOBCapability & (biosCapOffsetBit)))
681 {
682 return ipmi::response(ipmiCCBIOSCapabilityInitNotDone);
683 }
684 // Validate the Payload Type
685 if (payloadType > maxPayloadSupported)
686 {
687 return ipmi::responseInvalidFieldRequest();
688 }
689
690 struct PayloadInfo res = gNVOOBdata.payloadInfo[payloadType];
691
692 switch (static_cast<GetPayloadParameter>(paramSel))
693 {
694 case ipmi::GetPayloadParameter::GetPayloadInfo:
695 {
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000696
697 std::string payloadFilePath =
698 "/var/oob/Payload" + std::to_string(payloadType);
699
700 std::ifstream ifs(payloadFilePath,
701 std::ios::in | std::ios::binary | std::ios::ate);
702
703 if (!ifs.good())
704 {
705
706 phosphor::logging::log<phosphor::logging::level::ERR>(
707 "ipmiOEMGetPayload: Payload File Error");
708 // File does not exist code here
709 return ipmi::response(ipmi::ccUnspecifiedError);
710 }
711 ifs.close();
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800712 retValue.pack(res.payloadVersion);
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000713 retValue.pack(payloadType);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800714 retValue.pack(res.payloadTotalSize);
715 retValue.pack(res.payloadTotalChecksum);
716 retValue.pack(res.payloadflag);
717 retValue.pack(res.payloadStatus);
718 retValue.pack(res.payloadTimeStamp);
719
720 return ipmi::responseSuccess(std::move(retValue));
721 }
722
723 break;
724 case ipmi::GetPayloadParameter::GetPayloadData:
725 {
726 if (res.payloadStatus ==
727 (static_cast<uint8_t>(ipmi::PStatus::Valid)))
728 {
729 std::vector<uint32_t> reqData;
730 if (payload.unpack(reqData) || !payload.fullyUnpacked())
731 {
732 return ipmi::responseReqDataLenInvalid();
733 }
734 uint32_t offset = reqData.at(0);
735 uint32_t length = reqData.at(1);
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000736 std::string payloadFilePath =
737 "/var/oob/Payload" + std::to_string(payloadType);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800738
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000739 std::ifstream ifs(payloadFilePath, std::ios::in |
740 std::ios::binary |
741 std::ios::ate);
742
743 if (!ifs.good())
744 {
745
746 phosphor::logging::log<phosphor::logging::level::ERR>(
747 "ipmiOEMGetPayload: Payload File Error");
748 // File does not exist code here
749 return ipmi::response(ipmi::ccUnspecifiedError);
750 }
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800751 std::ifstream::pos_type fileSize = ifs.tellg();
752 // Total file data within given offset
753 if (fileSize < static_cast<uint64_t>(offset))
754 {
755 ifs.close();
756 return ipmi::responseInvalidFieldRequest();
757 }
758
759 ifs.seekg(offset, std::ios::beg);
760 std::array<uint8_t, maxGetPayloadDataSize> Buffer;
761 ifs.read(reinterpret_cast<char*>(Buffer.data()), length);
762 uint32_t readCount = ifs.gcount();
763 ifs.close();
764
765 boost::crc_32_type calcChecksum;
766 calcChecksum.process_bytes(
767 reinterpret_cast<char*>(Buffer.data()), readCount);
768 uint32_t chkSum = calcChecksum.checksum();
769 retValue.pack(payloadType);
770 retValue.pack(readCount);
771 retValue.pack(chkSum);
772
773 for (int i = 0; i < readCount; i++)
774 {
775 retValue.pack(Buffer.at(i));
776 }
777 return ipmi::responseSuccess(std::move(retValue));
778 }
779 else
780 {
781 return ipmi::responseResponseError();
782 }
783 }
784 break;
785 case ipmi::GetPayloadParameter::GetPayloadStatus:
786 {
787 retValue.pack(gNVOOBdata.payloadInfo[payloadType].payloadStatus);
788 return ipmi::responseSuccess(std::move(retValue));
789 }
790 break;
791 default:
792 return ipmi::responseInvalidFieldRequest();
793 }
794 return ipmi::responseInvalidFieldRequest();
795}
796
797ipmi::RspType<> ipmiOEMSetBIOSHashInfo(
798 ipmi::Context::ptr ctx, std::array<uint8_t, maxSeedSize>& pwdSeed,
Ayushi Smriti32381872021-06-23 11:05:48 +0530799 uint8_t algoInfo, std::array<uint8_t, maxHashSize>& adminPwdHash)
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800800{
801
802 std::string OSState;
803
804 // We should support this command only in KCS Interface
805 if (!IsSystemInterface(ctx))
806 {
807 return ipmi::responseCommandNotAvailable();
808 }
809 getSystemOSState(OSState);
810 // We should not support this command after System Booted - After Exit Boot
811 // service called
812
Ayushi Smriti32381872021-06-23 11:05:48 +0530813 if (OSState == "OperatingState")
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800814 {
Ayushi Smriti32381872021-06-23 11:05:48 +0530815 return ipmi::response(ipmiCCNotSupportedInCurrentState);
816 }
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800817
Ayushi Smriti32381872021-06-23 11:05:48 +0530818 nlohmann::json json;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800819
Ayushi Smriti32381872021-06-23 11:05:48 +0530820 if ((algoInfo & 0xF) == algoSHA384)
821 {
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800822 json["HashAlgo"] = "SHA384";
Ayushi Smriti32381872021-06-23 11:05:48 +0530823 }
824 else if ((algoInfo & 0xF) == algoSHA256)
825 {
826 json["HashAlgo"] = "SHA256";
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800827 }
828 else
829 {
Ayushi Smriti32381872021-06-23 11:05:48 +0530830 return ipmi::responseInvalidFieldRequest();
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800831 }
Ayushi Smriti32381872021-06-23 11:05:48 +0530832
833 json["Seed"] = pwdSeed;
834 json["IsAdminPwdChanged"] = false;
835 json["AdminPwdHash"] = adminPwdHash;
836 json["IsUserPwdChanged"] = false;
837
838 std::array<uint8_t, maxHashSize> userPwdHash;
839 userPwdHash.fill({}); // initializing with 0 as user password hash field
840 // is not used presently
841 json["UserPwdHash"] = userPwdHash;
842 json["StatusFlag"] = algoInfo;
843
844 std::string hashFilePath = "/var/lib/bios-settings-manager/seedData";
845 std::ofstream ofs(hashFilePath, std::ios::out);
846 const auto& writeData = json.dump();
847 ofs << writeData;
848 ofs.close();
849 return ipmi::responseSuccess();
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800850}
851
Ayushi Smriti32381872021-06-23 11:05:48 +0530852ipmi::RspType<std::array<uint8_t, maxSeedSize>, uint8_t,
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800853 std::array<uint8_t, maxHashSize>>
854 ipmiOEMGetBIOSHash(ipmi::Context::ptr ctx)
855{
856
857 std::string OSState;
858 nlohmann::json data = nullptr;
859
860 // We should support this command only in KCS Interface
861 if (!IsSystemInterface(ctx))
862 {
863 return ipmi::responseCommandNotAvailable();
864 }
865
866 getSystemOSState(OSState);
867 // We should not support this command after System Booted - After Exit Boot
868 // service called
869
870 if (OSState != "OperatingState")
871 {
Suryakanth Sekarcc402592021-04-01 15:02:10 +0530872 std::string HashFilePath = "/var/lib/bios-settings-manager/seedData";
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800873
874 std::ifstream devIdFile(HashFilePath);
875 if (devIdFile.is_open())
876 {
877
878 try
879 {
880 data = nlohmann::json::parse(devIdFile, nullptr, false);
881 }
882 catch (const nlohmann::json::parse_error& e)
883 {
884 return ipmi::responseResponseError();
885 }
886
887 if (data.is_discarded())
888 {
889 return ipmi::responseResponseError();
890 }
891
892 std::array<uint8_t, maxHashSize> newAdminHash;
Ayushi Smriti32381872021-06-23 11:05:48 +0530893 std::array<uint8_t, maxSeedSize> seed;
894
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800895 uint8_t flag = 0;
896 uint8_t adminPwdChangedFlag = 0;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800897 if (!data.is_discarded())
898 {
899
900 adminPwdChangedFlag = data["IsAdminPwdChanged"];
901 newAdminHash = data["AdminPwdHash"];
Ayushi Smriti32381872021-06-23 11:05:48 +0530902 seed = data["Seed"];
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800903 }
904
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800905 auto status = getResetBIOSSettings(flag);
906 if (status)
907 {
908 return ipmi::responseResponseError();
909 }
910 if (adminPwdChangedFlag)
911 {
912 flag |= adminPasswordChanged;
913 }
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800914
915 std::copy(std::begin(newAdminHash), std::end(newAdminHash),
916 std::begin(newAdminHash));
Ayushi Smriti32381872021-06-23 11:05:48 +0530917
918 return ipmi::responseSuccess(seed, flag, newAdminHash);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800919 }
920 else
921 {
922 return ipmi::responseResponseError();
923 }
924 }
925 else
926 {
927
928 return ipmi::response(ipmiCCNotSupportedInCurrentState);
929 }
930}
931
932static void registerBIOSConfigFunctions(void)
933{
934 phosphor::logging::log<phosphor::logging::level::INFO>(
935 "BIOSConfig module initialization");
936 InitNVOOBdata();
937
938 registerHandler(prioOemBase, intel::netFnGeneral,
939 intel::general::cmdSetBIOSCap, Privilege::Admin,
940 ipmiOEMSetBIOSCap);
941
942 registerHandler(prioOemBase, intel::netFnGeneral,
943 intel::general::cmdGetBIOSCap, Privilege::User,
944 ipmiOEMGetBIOSCap);
945 registerHandler(prioOemBase, intel::netFnGeneral,
946 intel::general::cmdSetBIOSPwdHashInfo, Privilege::Admin,
947 ipmiOEMSetBIOSHashInfo);
948
949 registerHandler(prioOemBase, intel::netFnGeneral,
950 intel::general::cmdGetBIOSPwdHash, Privilege::User,
951 ipmiOEMGetBIOSHash);
952
953 registerHandler(prioOemBase, intel::netFnGeneral,
954 intel::general::cmdGetPayload, Privilege::User,
955 ipmiOEMGetPayload);
956 registerHandler(prioOemBase, intel::netFnGeneral,
957 intel::general::cmdSetPayload, Privilege::Admin,
958 ipmiOEMSetPayload);
959
960 return;
961}
962
963} // namespace ipmi