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