blob: 217d2f6ba6bf933189fc6320c9a339bf5acb69be [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;
59static constexpr const uint8_t biosCapOffsetBit = 0x3;
60static constexpr uint16_t maxGetPayloadDataSize = 4096;
61static constexpr const char* biosXMLFilePath = "/var/oob/bios.xml";
62static constexpr const char* biosXMLFilePath1 = "/var/oob/tempbios.xml";
63
64static constexpr const char* biosConfigBaseMgrPath =
65 "/xyz/openbmc_project/bios_config/manager";
66static constexpr const char* biosConfigIntf =
67 "xyz.openbmc_project.BIOSConfig.Manager";
68static constexpr const char* resetBIOSSettingsProp = "ResetBIOSSettings";
69/*baseBIOSTable
70map{attributeName,struct{attributeType,readonlyStatus,displayname,
71 description,menuPath,current,default,
72 array{struct{optionstring,optionvalue}}}}
73*/
Kuiying Wang01fbd012021-04-22 11:32:56 +080074using BiosBaseTableType =
75 std::map<std::string,
76 std::tuple<std::string, bool, std::string, std::string,
77 std::string, std::variant<int64_t, std::string>,
78 std::variant<int64_t, std::string>,
79 std::vector<std::tuple<
80 std::string, std::variant<int64_t, std::string>>>>>;
81using OptionType =
82 std::vector<std::tuple<std::string, std::variant<int64_t, std::string>>>;
83BiosBaseTableType attributesData;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +080084
85NVOOBdata gNVOOBdata;
86
87enum class PTState : uint8_t
88{
89 StartTransfer = 0,
90 InProgress = 1,
91 EndTransfer = 2,
92 UserAbort = 3
93};
94enum class PStatus : uint8_t
95{
96 Unknown = 0,
97 Valid = 1,
98 Corrupted = 2
99};
100enum class PType : uint8_t
101{
102 IntelXMLType0 = 0,
103 IntelXMLType1 = 1,
104 OTAPayload = 5,
105};
106
107//
108// GetPayload Payload status enumeration
109//
110enum class GetPayloadParameter : uint8_t
111{
112 GetPayloadInfo = 0, // 0
113 GetPayloadData = 1, // 1
114 GetPayloadStatus = 2
115};
116
117/** @brief implement to set the BaseBIOSTable property
118 * @returns status
119 */
120static int sendAllAttributes(ipmi::Context::ptr ctx)
121{
122 boost::system::error_code ec;
123 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
124 std::string service =
125 getService(*dbus, biosConfigIntf, biosConfigBaseMgrPath);
126 ec.clear();
127 ctx->bus->yield_method_call<>(
128 ctx->yield, ec, service, biosConfigBaseMgrPath,
129 "org.freedesktop.DBus.Properties", "Set", biosConfigIntf,
Kuiying Wang01fbd012021-04-22 11:32:56 +0800130 "BaseBIOSTable", std::variant<BiosBaseTableType>(attributesData));
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800131 if (ec)
132 {
133 phosphor::logging::log<phosphor::logging::level::ERR>(
134 "Failed to sendAllAttributes");
135 return -1;
136 }
137 return 0;
138}
139
140/** @brief implement to flush the updated data in nv space
141 * @returns status
142 */
143static uint8_t flushNVOOBdata()
144{
145 std::ofstream outFile(biosConfigNVPath, std::ios::binary | std::ios::app);
146 if (outFile.good())
147 {
148 outFile.seekp(std::ios_base::beg);
149 const char* writedata = reinterpret_cast<const char*>(&gNVOOBdata);
150 outFile.write(writedata, sizeof(struct NVOOBdata));
151 outFile.close();
152 }
153 return 0;
154}
155
156/** @brief implement to get the System State
157 * @returns status
158 */
159
160static int getSystemOSState(std::string& OsStatus)
161{
162
163 try
164 {
165 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
166 Value variant =
167 getDbusProperty(*dbus, "xyz.openbmc_project.State.OperatingSystem",
168 "/xyz/openbmc_project/state/os",
169 "xyz.openbmc_project.State.OperatingSystem.Status",
170 "OperatingSystemState");
171 OsStatus = std::get<std::string>(variant);
172 return ipmi::ccSuccess;
173 }
174 catch (const std::exception& e)
175 {
176 return ipmi::ccUnspecifiedError;
177 }
178}
179
180/** @brief implement to get the Rest BIOS property
181 * @returns status
182 */
183static int getResetBIOSSettings(uint8_t& ResetFlag)
184{
185
186 try
187 {
188 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
189 std::string service =
190 getService(*dbus, biosConfigIntf, biosConfigBaseMgrPath);
191 Value variant = getDbusProperty(*dbus, service, biosConfigBaseMgrPath,
192 biosConfigIntf, resetBIOSSettingsProp);
Suryakanth Sekarcc402592021-04-01 15:02:10 +0530193
194 std::string_view ResetStr = std::get<std::string>(variant);
195 if (ResetStr ==
196 "xyz.openbmc_project.BIOSConfig.Manager.ResetFlag.NoAction")
197 {
198 ResetFlag = 0;
199 }
200 else if (ResetStr == "xyz.openbmc_project.BIOSConfig.Manager.ResetFlag."
201 "FactoryDefaults")
202 {
203 ResetFlag = 1;
204 }
205 else if (ResetStr == "xyz.openbmc_project.BIOSConfig.Manager.ResetFlag."
206 "FailSafeDefaults")
207 {
208 ResetFlag = 2;
209 }
210 else
211 {
212 return ipmi::ccUnspecifiedError;
213 }
214
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800215 return ipmi::ccSuccess;
216 }
217 catch (const std::exception& e)
218 {
219 return ipmi::ccUnspecifiedError;
220 }
221}
222
223/** @brief implement generate naive- dbus from XML file
224 * @returns status
225 */
226static int generateAttributesData()
227{
228 // Open the bios.xml and parse it
229 // Extract the needed data and store it in AttributesData variable
230 // Close the bios.xml
231 phosphor::logging::log<phosphor::logging::level::ERR>(
232 "generateAttributesData");
233 tinyxml2::XMLDocument xmlDoc;
234
235 xmlDoc.LoadFile(biosXMLFilePath);
236 tinyxml2::XMLNode* pRoot = xmlDoc.FirstChild();
237 if (pRoot == nullptr)
238 {
239 return 0;
240 }
241 tinyxml2::XMLElement* pElement = pRoot->FirstChildElement("biosknobs");
242 if (pElement == nullptr)
243 {
244 return 0;
245 }
246 tinyxml2::XMLElement* pKnobsElement = pElement->FirstChildElement("knob");
247
248 while (pKnobsElement != nullptr)
249 {
250 bool readOnlyStatus = false;
251 std::string attrType =
252 "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.String";
253 std::string name, curvalue, dname, menupath, defaultvalue, description;
254 name = pKnobsElement->Attribute("name")
255 ? pKnobsElement->Attribute("name")
256 : "";
257 curvalue = pKnobsElement->Attribute("CurrentVal")
258 ? pKnobsElement->Attribute("CurrentVal")
259 : "";
260 dname = pKnobsElement->Attribute("prompt")
261 ? pKnobsElement->Attribute("prompt")
262 : "";
263 menupath = pKnobsElement->Attribute("SetupPgPtr")
264 ? pKnobsElement->Attribute("SetupPgPtr")
265 : "";
266 defaultvalue = pKnobsElement->Attribute("default")
267 ? pKnobsElement->Attribute("default")
268 : "";
269 description = pKnobsElement->Attribute("description")
270 ? pKnobsElement->Attribute("description")
271 : "";
272 phosphor::logging::log<phosphor::logging::level::INFO>(name.c_str());
273 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
312 return 0;
313}
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
359 std::ifstream ifs(biosConfigNVPath,
360 std::ios::in | std::ios::binary | std::ios::ate);
361
362 if (ifs.good())
363 {
364
365 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);
493
494 return ipmi::responseSuccess(
495 gNVOOBdata.payloadInfo[payloadType].payloadReservationID);
496 }
497 break;
498
499 case ipmi::PTState::InProgress:
500 {
501 PayloadInProgress* pPayloadInProgress =
502 reinterpret_cast<PayloadInProgress*>(payload.data());
503 PayloadInfo payloadInfo = gNVOOBdata.payloadInfo[payloadType];
504
505 if (payload.size() < sizeof(PayloadInProgress))
506 {
507 phosphor::logging::log<phosphor::logging::level::ERR>(
508 "BIOS Config Payload size is not correct");
509 return ipmi::responseReqDataLenInvalid();
510 }
511
512 if (pPayloadInProgress->payloadReservationID !=
513 payloadInfo.payloadReservationID)
514 {
515 return ipmi::responseInvalidReservationId();
516 }
517 payloadInfo.payloadCurrentSize =
518 pPayloadInProgress->payloadCurrentSize;
519 // Need to verify the current Payload Checksum
520 const uint8_t* data =
521 reinterpret_cast<const uint8_t*>(payload.data());
522 // we have to remove the current size, current offset, current
523 // length,checksum bytes , reservation bytes
524 boost::crc_32_type calcChecksum;
525 calcChecksum.process_bytes(data + 16, payload.size() - 16);
526 if (calcChecksum.checksum() !=
527 pPayloadInProgress->payloadCurrentChecksum)
528 {
529 phosphor::logging::log<phosphor::logging::level::ERR>(
530 "ipmiOEMSetPayload: Payload Checksum Failed");
531 return ipmi::response(ipmiCCPayloadChecksumFailed);
532 }
533 // store the data in temp file
534 std::string FilePath =
535 "/var/oob/temp" + std::to_string(payloadType);
536
537 std::ofstream outFile(FilePath, std::ios::binary | std::ios::app);
538 outFile.seekp(pPayloadInProgress->payloadOffset);
539 // we have to remove the current size, current offset, current
540 // length,checksum bytes , reservation bytes
541
542 const char* writedata =
543 reinterpret_cast<const char*>(payload.data());
544 outFile.write(writedata + 16, payload.size() - 16);
545 outFile.close();
546
547 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
548 static_cast<uint8_t>(ipmi::PStatus::Unknown);
549 gNVOOBdata.payloadInfo[payloadType].actualTotalPayloadWritten +=
550 payloadInfo.payloadCurrentSize;
551 return ipmi::responseSuccess(payloadInfo.payloadCurrentSize);
552 }
553 break;
554 case ipmi::PTState::EndTransfer:
555 {
556 PayloadEndTransfer* pPayloadEndTransfer =
557 reinterpret_cast<PayloadEndTransfer*>(payload.data());
558 PayloadInfo payloadInfo = gNVOOBdata.payloadInfo[payloadType];
559 if (pPayloadEndTransfer->payloadReservationID !=
560 payloadInfo.payloadReservationID)
561 {
562 return ipmi::responseInvalidReservationId();
563 }
564 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
565 static_cast<uint8_t>(ipmi::PStatus::Unknown);
566
567 if (gNVOOBdata.payloadInfo[payloadType].actualTotalPayloadWritten !=
568 gNVOOBdata.payloadInfo[payloadType].payloadTotalSize)
569 {
570
571 return ipmi::response(ipmiCCPayloadPayloadInComplete);
572 }
573 std::string tempFilePath =
574 "/var/oob/temp" + std::to_string(payloadType);
575 std::string PayloadFilePath =
576 "/var/oob/Payload" + std::to_string(payloadType);
577 auto renamestatus =
578 std::rename(tempFilePath.c_str(), PayloadFilePath.c_str());
579 if (renamestatus)
580 {
581 phosphor::logging::log<phosphor::logging::level::ERR>(
582 "ipmiOEMSetPayload: Renaming Payload file - failed");
583 }
584
585 gNVOOBdata.payloadInfo[payloadType].payloadFilePath =
586 PayloadFilePath;
587 if (payloadType == static_cast<uint8_t>(ipmi::PType::IntelXMLType0))
588 {
589 // Unzip the Intel format XML file type 0
590 auto response = generateBIOSXMLFile("/usr/bin/lzcat", "-d",
591 PayloadFilePath.c_str());
592 if (response)
593 {
594
595 phosphor::logging::log<phosphor::logging::level::ERR>(
596 "ipmiOEMSetPayload: generateBIOSXMLFile - failed");
597 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
598 static_cast<uint8_t>(ipmi::PStatus::Corrupted);
599 return ipmi::response(ipmiCCPayloadPayloadPacketMissed);
600 }
601 }
602 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
603 static_cast<uint8_t>(ipmi::PStatus::Valid);
604
605 struct stat filestat;
606
607 /* Get entry's information. */
608 if (!stat(PayloadFilePath.c_str(), &filestat))
609 {
610 gNVOOBdata.payloadInfo[payloadType].payloadTimeStamp =
611 filestat.st_mtime;
612 gNVOOBdata.payloadInfo[payloadType].payloadTotalSize =
613 filestat.st_size;
614 gNVOOBdata.payloadInfo[payloadType].payloadFilePath =
615 PayloadFilePath;
616 }
617 else
618 {
619 return ipmi::responseResponseError();
620 }
621
622 phosphor::logging::log<phosphor::logging::level::INFO>(
623 " ipmiOEMSetPayload : Convert XML into native-dbus DONE");
624 generateAttributesData();
625
626 phosphor::logging::log<phosphor::logging::level::INFO>(
627 " ipmiOEMSetPayload : BaseBIOSTable Property is set");
628 sendAllAttributes(ctx);
629
630 flushNVOOBdata();
631 return ipmi::responseSuccess(
632 gNVOOBdata.payloadInfo[payloadType].actualTotalPayloadWritten);
633 }
634 break;
635 case ipmi::PTState::UserAbort:
636 {
637 PayloadEndTransfer* pPayloadEndTransfer =
638 reinterpret_cast<PayloadEndTransfer*>(payload.data());
639 PayloadInfo payloadInfo = gNVOOBdata.payloadInfo[payloadType];
640 if (pPayloadEndTransfer->payloadReservationID !=
641 payloadInfo.payloadReservationID)
642 {
643 return ipmi::responseInvalidReservationId();
644 }
645 gNVOOBdata.payloadInfo[payloadType].payloadReservationID = 0;
646 gNVOOBdata.payloadInfo[payloadType].payloadType = 0;
647 gNVOOBdata.payloadInfo[payloadType].payloadTotalSize = 0;
648 // Delete the temp file
649 std::string tempFilePath =
650 "/var/oob/temp" + std::to_string(payloadType);
651 unlink(tempFilePath.c_str());
652 flushNVOOBdata();
653 return ipmi::responseSuccess();
654 }
655 break;
656 default:
657 return ipmi::responseInvalidFieldRequest();
658 }
659 return ipmi::responseResponseError();
660}
661
662ipmi::RspType<message::Payload>
663 ipmiOEMGetPayload(ipmi::Context::ptr ctx, uint8_t paramSel,
664 uint8_t payloadType, ipmi::message::Payload& payload)
665{
666 // 1-OOB BIOS config is supported
667 message::Payload retValue;
668
669 if (!(gNVOOBdata.mBIOSCapabilities.OOBCapability & (biosCapOffsetBit)))
670 {
671 return ipmi::response(ipmiCCBIOSCapabilityInitNotDone);
672 }
673 // Validate the Payload Type
674 if (payloadType > maxPayloadSupported)
675 {
676 return ipmi::responseInvalidFieldRequest();
677 }
678
679 struct PayloadInfo res = gNVOOBdata.payloadInfo[payloadType];
680
681 switch (static_cast<GetPayloadParameter>(paramSel))
682 {
683 case ipmi::GetPayloadParameter::GetPayloadInfo:
684 {
685 retValue.pack(res.payloadVersion);
686 retValue.pack(res.payloadType);
687 retValue.pack(res.payloadTotalSize);
688 retValue.pack(res.payloadTotalChecksum);
689 retValue.pack(res.payloadflag);
690 retValue.pack(res.payloadStatus);
691 retValue.pack(res.payloadTimeStamp);
692
693 return ipmi::responseSuccess(std::move(retValue));
694 }
695
696 break;
697 case ipmi::GetPayloadParameter::GetPayloadData:
698 {
699 if (res.payloadStatus ==
700 (static_cast<uint8_t>(ipmi::PStatus::Valid)))
701 {
702 std::vector<uint32_t> reqData;
703 if (payload.unpack(reqData) || !payload.fullyUnpacked())
704 {
705 return ipmi::responseReqDataLenInvalid();
706 }
707 uint32_t offset = reqData.at(0);
708 uint32_t length = reqData.at(1);
709
710 std::ifstream ifs(res.payloadFilePath, std::ios::in |
711 std::ios::binary |
712 std::ios::ate);
713 std::ifstream::pos_type fileSize = ifs.tellg();
714 // Total file data within given offset
715 if (fileSize < static_cast<uint64_t>(offset))
716 {
717 ifs.close();
718 return ipmi::responseInvalidFieldRequest();
719 }
720
721 ifs.seekg(offset, std::ios::beg);
722 std::array<uint8_t, maxGetPayloadDataSize> Buffer;
723 ifs.read(reinterpret_cast<char*>(Buffer.data()), length);
724 uint32_t readCount = ifs.gcount();
725 ifs.close();
726
727 boost::crc_32_type calcChecksum;
728 calcChecksum.process_bytes(
729 reinterpret_cast<char*>(Buffer.data()), readCount);
730 uint32_t chkSum = calcChecksum.checksum();
731 retValue.pack(payloadType);
732 retValue.pack(readCount);
733 retValue.pack(chkSum);
734
735 for (int i = 0; i < readCount; i++)
736 {
737 retValue.pack(Buffer.at(i));
738 }
739 return ipmi::responseSuccess(std::move(retValue));
740 }
741 else
742 {
743 return ipmi::responseResponseError();
744 }
745 }
746 break;
747 case ipmi::GetPayloadParameter::GetPayloadStatus:
748 {
749 retValue.pack(gNVOOBdata.payloadInfo[payloadType].payloadStatus);
750 return ipmi::responseSuccess(std::move(retValue));
751 }
752 break;
753 default:
754 return ipmi::responseInvalidFieldRequest();
755 }
756 return ipmi::responseInvalidFieldRequest();
757}
758
759ipmi::RspType<> ipmiOEMSetBIOSHashInfo(
760 ipmi::Context::ptr ctx, std::array<uint8_t, maxSeedSize>& pwdSeed,
761 uint8_t algoInfo, std::array<uint8_t, maxHashSize>& adminPwdHash,
762 std::array<uint8_t, maxHashSize>& userPwdHash)
763{
764
765 std::string OSState;
766
767 // We should support this command only in KCS Interface
768 if (!IsSystemInterface(ctx))
769 {
770 return ipmi::responseCommandNotAvailable();
771 }
772 getSystemOSState(OSState);
773 // We should not support this command after System Booted - After Exit Boot
774 // service called
775
776 if (OSState != "OperatingState")
777 {
778
Suryakanth Sekarf4866952021-02-25 16:06:57 +0530779 if ((algoInfo & 0xF) != algoSHA384)
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800780 {
781 // Atpresent, we are supporting only SHA384- HASH algo in BIOS side
782 return ipmi::responseInvalidFieldRequest();
783 }
784 std::string HashFilePath = "/var/lib/bios-settings-manager/seedData";
785
786 nlohmann::json json;
787 json["Seed"] = pwdSeed;
788 json["HashAlgo"] = "SHA384";
789 json["IsAdminPwdChanged"] = false;
790 json["AdminPwdHash"] = adminPwdHash;
791 json["IsUserPwdChanged"] = false;
792 json["UserPwdHash"] = userPwdHash;
Suryakanth Sekarf4866952021-02-25 16:06:57 +0530793 json["StatusFlag"] = algoInfo;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800794 std::ofstream ofs(HashFilePath, std::ios::out);
795 const auto& writeData = json.dump();
796 ofs << writeData;
797 ofs.close();
798 return ipmi::responseSuccess();
799 }
800 else
801 {
802
803 return ipmi::response(ipmiCCNotSupportedInCurrentState);
804 }
805}
806
807ipmi::RspType<uint8_t, std::array<uint8_t, maxHashSize>,
808 std::array<uint8_t, maxHashSize>>
809 ipmiOEMGetBIOSHash(ipmi::Context::ptr ctx)
810{
811
812 std::string OSState;
813 nlohmann::json data = nullptr;
814
815 // We should support this command only in KCS Interface
816 if (!IsSystemInterface(ctx))
817 {
818 return ipmi::responseCommandNotAvailable();
819 }
820
821 getSystemOSState(OSState);
822 // We should not support this command after System Booted - After Exit Boot
823 // service called
824
825 if (OSState != "OperatingState")
826 {
Suryakanth Sekarcc402592021-04-01 15:02:10 +0530827 std::string HashFilePath = "/var/lib/bios-settings-manager/seedData";
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800828
829 std::ifstream devIdFile(HashFilePath);
830 if (devIdFile.is_open())
831 {
832
833 try
834 {
835 data = nlohmann::json::parse(devIdFile, nullptr, false);
836 }
837 catch (const nlohmann::json::parse_error& e)
838 {
839 return ipmi::responseResponseError();
840 }
841
842 if (data.is_discarded())
843 {
844 return ipmi::responseResponseError();
845 }
846
847 std::array<uint8_t, maxHashSize> newAdminHash;
848 std::array<uint8_t, maxHashSize> newUserHash;
849 uint8_t flag = 0;
850 uint8_t adminPwdChangedFlag = 0;
851 uint8_t userPwdChangedFlag = 0;
852 if (!data.is_discarded())
853 {
854
855 adminPwdChangedFlag = data["IsAdminPwdChanged"];
856 newAdminHash = data["AdminPwdHash"];
857 newUserHash = data["UserPwdHash"];
858 userPwdChangedFlag = data["IsUserPwdChanged"];
859 }
860
861 // 0: BIT 4 - New Admin Password Not Present
862 // 1: BIT 4 - New Admin Password Hash Present
863 // 0: BIT 5 - New User Password Not Present
864 // 1: BIT 5 - New User Password Hash Present
865 // 0: BIT 0 - Default Setting flag is not set
866 // 1: BIT 0 - Default Setting flag is set
867 auto status = getResetBIOSSettings(flag);
868 if (status)
869 {
870 return ipmi::responseResponseError();
871 }
872 if (adminPwdChangedFlag)
873 {
874 flag |= adminPasswordChanged;
875 }
876 if (userPwdChangedFlag)
877 {
878 flag |= userPasswordChanged;
879 }
880
881 std::copy(std::begin(newAdminHash), std::end(newAdminHash),
882 std::begin(newAdminHash));
883 std::copy(std::begin(newUserHash), std::end(newUserHash),
884 std::begin(newUserHash));
885 return ipmi::responseSuccess(flag, newAdminHash, newUserHash);
886 }
887 else
888 {
889 return ipmi::responseResponseError();
890 }
891 }
892 else
893 {
894
895 return ipmi::response(ipmiCCNotSupportedInCurrentState);
896 }
897}
898
899static void registerBIOSConfigFunctions(void)
900{
901 phosphor::logging::log<phosphor::logging::level::INFO>(
902 "BIOSConfig module initialization");
903 InitNVOOBdata();
904
905 registerHandler(prioOemBase, intel::netFnGeneral,
906 intel::general::cmdSetBIOSCap, Privilege::Admin,
907 ipmiOEMSetBIOSCap);
908
909 registerHandler(prioOemBase, intel::netFnGeneral,
910 intel::general::cmdGetBIOSCap, Privilege::User,
911 ipmiOEMGetBIOSCap);
912 registerHandler(prioOemBase, intel::netFnGeneral,
913 intel::general::cmdSetBIOSPwdHashInfo, Privilege::Admin,
914 ipmiOEMSetBIOSHashInfo);
915
916 registerHandler(prioOemBase, intel::netFnGeneral,
917 intel::general::cmdGetBIOSPwdHash, Privilege::User,
918 ipmiOEMGetBIOSHash);
919
920 registerHandler(prioOemBase, intel::netFnGeneral,
921 intel::general::cmdGetPayload, Privilege::User,
922 ipmiOEMGetPayload);
923 registerHandler(prioOemBase, intel::netFnGeneral,
924 intel::general::cmdSetPayload, Privilege::Admin,
925 ipmiOEMSetPayload);
926
927 return;
928}
929
930} // namespace ipmi