blob: 6d48f8f90628953d70f50144f20f9cf862388fac [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{
40static void registerBIOSConfigFunctions() __attribute__((constructor));
41
42// Define BIOS config related Completion Code
43using Cc = uint8_t;
44static constexpr Cc ipmiCCPayloadPayloadPacketMissed = 0x80;
45static constexpr Cc ipmiCCBIOSPasswordInitNotDone = 0x80;
46static constexpr Cc ipmiCCPayloadChecksumFailed = 0x81;
47static constexpr Cc ipmiCCNotSupportedInCurrentState = 0x82;
48static constexpr Cc ipmiCCPayloadPayloadInComplete = 0x83;
49static constexpr Cc ipmiCCBIOSCapabilityInitNotDone = 0x85;
50static constexpr Cc ipmiCCPayloadLengthIllegal = 0x85;
51
52static constexpr uint8_t userPasswordChanged = (1 << 5);
53static constexpr uint8_t adminPasswordChanged = (1 << 4);
54
55static constexpr const char* biosConfigFolder = "/var/oob";
56static constexpr const char* biosConfigNVPath = "/var/oob/nvoobdata.dat";
57static constexpr const uint8_t algoSHA384 = 2;
Ayushi Smriti32381872021-06-23 11:05:48 +053058static constexpr const uint8_t algoSHA256 = 1;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +080059static 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*/
Arun Lal K Me7725612021-07-15 18:20:58 +000074
75bios::BiosBaseTableType attributesData;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +080076
77NVOOBdata gNVOOBdata;
78
79enum class PTState : uint8_t
80{
81 StartTransfer = 0,
82 InProgress = 1,
83 EndTransfer = 2,
84 UserAbort = 3
85};
86enum class PStatus : uint8_t
87{
88 Unknown = 0,
89 Valid = 1,
90 Corrupted = 2
91};
92enum class PType : uint8_t
93{
94 IntelXMLType0 = 0,
95 IntelXMLType1 = 1,
96 OTAPayload = 5,
97};
98
99//
100// GetPayload Payload status enumeration
101//
102enum class GetPayloadParameter : uint8_t
103{
104 GetPayloadInfo = 0, // 0
105 GetPayloadData = 1, // 1
106 GetPayloadStatus = 2
107};
108
109/** @brief implement to set the BaseBIOSTable property
110 * @returns status
111 */
Arun Lal K Me7725612021-07-15 18:20:58 +0000112static bool sendAllAttributes(std::string service)
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800113{
Arun Lal K Me7725612021-07-15 18:20:58 +0000114 std::shared_ptr<sdbusplus::asio::connection> pSdBusPlus = getSdBus();
115
116 if (pSdBusPlus)
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800117 {
Arun Lal K Me7725612021-07-15 18:20:58 +0000118 try
119 {
120 pSdBusPlus->async_method_call(
121 [](const boost::system::error_code ec) {
122 /* No more need to keep attributes data in memory */
123 attributesData.clear();
124
125 if (ec)
126 {
127 phosphor::logging::log<phosphor::logging::level::ERR>(
128 "sendAllAttributes error: send all attributes - "
129 "failed");
130 return;
131 }
132
133 phosphor::logging::log<phosphor::logging::level::INFO>(
134 "sendAllAttributes: send all attributes - done");
135 },
136 service, biosConfigBaseMgrPath,
137 "org.freedesktop.DBus.Properties", "Set", biosConfigIntf,
138 "BaseBIOSTable",
139 std::variant<bios::BiosBaseTableType>(attributesData));
140
141 return true;
142 }
143 catch (std::exception& ex)
144 {
145 phosphor::logging::log<phosphor::logging::level::ERR>(ex.what());
146 }
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800147 }
Arun Lal K Me7725612021-07-15 18:20:58 +0000148
149 return false;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800150}
151
152/** @brief implement to flush the updated data in nv space
153 * @returns status
154 */
155static uint8_t flushNVOOBdata()
156{
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000157 std::ofstream outFile(biosConfigNVPath, std::ios::binary);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800158 if (outFile.good())
159 {
160 outFile.seekp(std::ios_base::beg);
161 const char* writedata = reinterpret_cast<const char*>(&gNVOOBdata);
162 outFile.write(writedata, sizeof(struct NVOOBdata));
163 outFile.close();
164 }
165 return 0;
166}
167
168/** @brief implement to get the System State
169 * @returns status
170 */
171
172static int getSystemOSState(std::string& OsStatus)
173{
174
175 try
176 {
177 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
178 Value variant =
179 getDbusProperty(*dbus, "xyz.openbmc_project.State.OperatingSystem",
180 "/xyz/openbmc_project/state/os",
181 "xyz.openbmc_project.State.OperatingSystem.Status",
182 "OperatingSystemState");
183 OsStatus = std::get<std::string>(variant);
184 return ipmi::ccSuccess;
185 }
186 catch (const std::exception& e)
187 {
188 return ipmi::ccUnspecifiedError;
189 }
190}
191
192/** @brief implement to get the Rest BIOS property
193 * @returns status
194 */
195static int getResetBIOSSettings(uint8_t& ResetFlag)
196{
197
198 try
199 {
200 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
201 std::string service =
202 getService(*dbus, biosConfigIntf, biosConfigBaseMgrPath);
203 Value variant = getDbusProperty(*dbus, service, biosConfigBaseMgrPath,
204 biosConfigIntf, resetBIOSSettingsProp);
Suryakanth Sekarcc402592021-04-01 15:02:10 +0530205
206 std::string_view ResetStr = std::get<std::string>(variant);
207 if (ResetStr ==
208 "xyz.openbmc_project.BIOSConfig.Manager.ResetFlag.NoAction")
209 {
210 ResetFlag = 0;
211 }
212 else if (ResetStr == "xyz.openbmc_project.BIOSConfig.Manager.ResetFlag."
213 "FactoryDefaults")
214 {
215 ResetFlag = 1;
216 }
217 else if (ResetStr == "xyz.openbmc_project.BIOSConfig.Manager.ResetFlag."
218 "FailSafeDefaults")
219 {
220 ResetFlag = 2;
221 }
222 else
223 {
224 return ipmi::ccUnspecifiedError;
225 }
226
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800227 return ipmi::ccSuccess;
228 }
229 catch (const std::exception& e)
230 {
231 return ipmi::ccUnspecifiedError;
232 }
233}
234
Arun Lal K Me7725612021-07-15 18:20:58 +0000235/** @brief Get attributes data (bios base table) from bios.xml
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800236 */
Arun Lal K Me7725612021-07-15 18:20:58 +0000237static bool generateAttributesData()
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800238{
Arun Lal K Me7725612021-07-15 18:20:58 +0000239 try
240 {
241 bios::Xml biosxml(biosXMLFilePath);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800242
Arun Lal K Me7725612021-07-15 18:20:58 +0000243 if (!biosxml.doDepexCompute())
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800244 {
Arun Lal K Me7725612021-07-15 18:20:58 +0000245 phosphor::logging::log<phosphor::logging::level::ERR>(
246 "'depex' compute failed");
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800247 }
Arun Lal K Me7725612021-07-15 18:20:58 +0000248
249 if (!biosxml.getBaseTable(attributesData))
250 {
251 phosphor::logging::log<phosphor::logging::level::ERR>(
252 "Failed to get bios base table");
253 }
254 }
255 catch (std::exception& ex)
256 {
257 phosphor::logging::log<phosphor::logging::level::ERR>(ex.what());
258 return false;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800259 }
260
Arun Lal K Me7725612021-07-15 18:20:58 +0000261 return true;
262}
263
264/** @brief Generate attributes data from bios.xml
265 * and send attributes data (bios base table) to dbus using set method.
266 */
267static void generateAndSendAttributesData(std::string service,
268 uint8_t payloadType)
269{
270 if (!generateAttributesData())
271 {
272 phosphor::logging::log<phosphor::logging::level::ERR>(
273 "generateAndSendAttributesData: generateAttributesData - failed");
274 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
275 static_cast<uint8_t>(ipmi::PStatus::Corrupted);
276 return;
277 }
278
279 phosphor::logging::log<phosphor::logging::level::INFO>(
280 "generateAndSendAttributesData : generateAttributesData is done");
281
282 if (!sendAllAttributes(service))
283 {
284 phosphor::logging::log<phosphor::logging::level::ERR>(
285 "generateAndSendAttributesData: sendAllAttributes - failed");
286 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
287 static_cast<uint8_t>(ipmi::PStatus::Corrupted);
288 return;
289 }
290
291 phosphor::logging::log<phosphor::logging::level::INFO>(
292 "generateAndSendAttributesData : sendAllAttributes is done");
293 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
294 static_cast<uint8_t>(ipmi::PStatus::Valid);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800295}
296
297/** @brief implement executing the linux command to uncompress and generate the
298 * xmlfile
299 * @param[in] linux command
300 * @returns status
301 */
302template <typename... ArgTypes>
303static int generateBIOSXMLFile(const char* path, ArgTypes&&... tArgs)
304{
305
306 boost::process::child execProg(path, const_cast<char*>(tArgs)...,
307 boost::process::std_out > biosXMLFilePath);
308 execProg.wait();
309 return execProg.exit_code();
310}
311
312/** @brief implements to clean up the temp/ existing payload file
313 **/
314static void cleanUpPayloadFile(uint8_t& payloadType)
315{
316 // Clear the payload Information
317 std::string FilePath = "/var/oob/temp" + std::to_string(payloadType);
318 unlink(FilePath.c_str());
319 FilePath = "/var/oob/Payload" + std::to_string(payloadType);
320 unlink(FilePath.c_str());
321 if (payloadType == static_cast<uint8_t>(ipmi::PType::IntelXMLType0))
322 {
323 unlink("/var/oob/Payload1");
324 gNVOOBdata.payloadInfo[static_cast<uint8_t>(ipmi::PType::IntelXMLType1)]
325 .payloadStatus = static_cast<uint8_t>(ipmi::PStatus::Unknown);
326 }
327}
328
329/** @brief implements to create the oob folders and nv space
330 **/
331static Cc InitNVOOBdata()
332{
333 FILE* fptr;
334 uint16_t size;
335
336 if (!(std::filesystem::exists(biosConfigFolder)))
337 {
338 std::filesystem::create_directory(biosConfigFolder);
339 }
340
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000341 std::ifstream ifs(biosConfigNVPath, std::ios::in | std::ios::binary);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800342
343 if (ifs.good())
344 {
345
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000346 ifs.seekg(std::ios_base::beg);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800347 ifs.read(reinterpret_cast<char*>(&gNVOOBdata),
348 sizeof(struct NVOOBdata));
349 ifs.close();
350 return ipmi::ccSuccess;
351 }
352 return ipmi::ccResponseError;
353}
354
355/** @brief implements check the command interface is
356 ** system interface or not
357 ** true mean System interface and false mean LAN or IPMB
358 **/
359static bool IsSystemInterface(ipmi::Context::ptr ctx)
360{
361 ChannelInfo chInfo;
362 Cc status = false;
363
364 try
365 {
366 getChannelInfo(ctx->channel, chInfo);
367 }
368 catch (sdbusplus::exception_t& e)
369 {
370 return false;
371 }
372 if (chInfo.mediumType !=
373 static_cast<uint8_t>(EChannelMediumType::systemInterface))
374 {
375 return false;
376 }
377 return true;
378}
379
380ipmi::RspType<> ipmiOEMSetBIOSCap(ipmi::Context::ptr ctx,
381 uint8_t BIOSCapabilties, uint8_t reserved1,
382 uint8_t reserved2, uint8_t reserved3)
383{
384 std::string OSState;
385 getSystemOSState(OSState);
386
387 if (OSState != "OperatingState" && IsSystemInterface(ctx))
388 {
389 if (reserved1 != 0 || reserved2 != 0 || reserved3 != 0)
390 {
391 return ipmi::responseInvalidFieldRequest();
392 }
393
394 gNVOOBdata.mBIOSCapabilities.OOBCapability = BIOSCapabilties;
395 gNVOOBdata.mIsBIOSCapInitDone = true;
396
397 flushNVOOBdata();
398 return ipmi::responseSuccess();
399 }
400 else
401 {
402
403 return ipmi::response(ipmiCCNotSupportedInCurrentState);
404 }
405}
406
407ipmi::RspType<uint8_t, uint8_t, uint8_t, uint8_t>
408 ipmiOEMGetBIOSCap(ipmi::Context::ptr ctx)
409{
410 if (gNVOOBdata.mIsBIOSCapInitDone)
411 {
412 return ipmi::responseSuccess(gNVOOBdata.mBIOSCapabilities.OOBCapability,
413 0, 0, 0);
414 }
415 else
416 {
417 return ipmi::response(ipmiCCBIOSCapabilityInitNotDone);
418 }
419}
420
421ipmi::RspType<uint32_t> ipmiOEMSetPayload(ipmi::Context::ptr ctx,
422 uint8_t paramSel, uint8_t payloadType,
423 std::vector<uint8_t> payload)
424{
425 uint8_t biosCapOffsetBit = 2; // BIT:1 0-OOB BIOS config not supported
426 // 1-OOB BIOS config is supported
427
428 if (!(gNVOOBdata.mBIOSCapabilities.OOBCapability & (biosCapOffsetBit)))
429 {
430 return ipmi::response(ipmiCCBIOSCapabilityInitNotDone);
431 }
432 // Validate the Payload Type
433 if (payloadType > maxPayloadSupported)
434 {
435 return ipmi::responseInvalidFieldRequest();
436 }
437
438 // We should support this Payload type 0 command only in KCS Interface
439 if (payloadType == static_cast<uint8_t>(ipmi::PType::IntelXMLType0))
440 {
441 std::string OSState;
442
443 getSystemOSState(OSState);
444 if (!IsSystemInterface(ctx) || OSState == "OperatingState")
445 {
446 return ipmi::responseCommandNotAvailable();
447 }
448 }
449
450 switch (static_cast<PTState>(paramSel))
451 {
452 case ipmi::PTState::StartTransfer:
453 {
454 PayloadStartTransfer* pPayloadStartTransfer =
455 reinterpret_cast<PayloadStartTransfer*>(payload.data());
456 if (payload.size() < sizeof(PayloadStartTransfer))
457 {
458 phosphor::logging::log<phosphor::logging::level::ERR>(
459 "ipmiOEMSetPayload: BIOS Config Payload size is not "
460 "correct");
461 return ipmi::responseReqDataLenInvalid();
462 }
463 cleanUpPayloadFile(payloadType);
464
465 gNVOOBdata.payloadInfo[payloadType].payloadReservationID = rand();
466 gNVOOBdata.payloadInfo[payloadType].payloadTotalChecksum =
467 pPayloadStartTransfer->payloadTotalChecksum;
468 gNVOOBdata.payloadInfo[payloadType].payloadTotalSize =
469 pPayloadStartTransfer->payloadTotalSize;
470 gNVOOBdata.payloadInfo[payloadType].payloadVersion =
471 pPayloadStartTransfer->payloadVersion;
472 gNVOOBdata.payloadInfo[payloadType].actualTotalPayloadWritten = 0;
473 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
474 static_cast<uint8_t>(ipmi::PStatus::Unknown);
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000475 gNVOOBdata.payloadInfo[payloadType].payloadType = payloadType;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800476
477 return ipmi::responseSuccess(
478 gNVOOBdata.payloadInfo[payloadType].payloadReservationID);
479 }
480 break;
481
482 case ipmi::PTState::InProgress:
483 {
484 PayloadInProgress* pPayloadInProgress =
485 reinterpret_cast<PayloadInProgress*>(payload.data());
486 PayloadInfo payloadInfo = gNVOOBdata.payloadInfo[payloadType];
487
488 if (payload.size() < sizeof(PayloadInProgress))
489 {
490 phosphor::logging::log<phosphor::logging::level::ERR>(
491 "BIOS Config Payload size is not correct");
492 return ipmi::responseReqDataLenInvalid();
493 }
494
495 if (pPayloadInProgress->payloadReservationID !=
496 payloadInfo.payloadReservationID)
497 {
498 return ipmi::responseInvalidReservationId();
499 }
500 payloadInfo.payloadCurrentSize =
501 pPayloadInProgress->payloadCurrentSize;
502 // Need to verify the current Payload Checksum
503 const uint8_t* data =
504 reinterpret_cast<const uint8_t*>(payload.data());
505 // we have to remove the current size, current offset, current
506 // length,checksum bytes , reservation bytes
507 boost::crc_32_type calcChecksum;
508 calcChecksum.process_bytes(data + 16, payload.size() - 16);
509 if (calcChecksum.checksum() !=
510 pPayloadInProgress->payloadCurrentChecksum)
511 {
512 phosphor::logging::log<phosphor::logging::level::ERR>(
513 "ipmiOEMSetPayload: Payload Checksum Failed");
514 return ipmi::response(ipmiCCPayloadChecksumFailed);
515 }
516 // store the data in temp file
517 std::string FilePath =
518 "/var/oob/temp" + std::to_string(payloadType);
519
520 std::ofstream outFile(FilePath, std::ios::binary | std::ios::app);
521 outFile.seekp(pPayloadInProgress->payloadOffset);
522 // we have to remove the current size, current offset, current
523 // length,checksum bytes , reservation bytes
524
525 const char* writedata =
526 reinterpret_cast<const char*>(payload.data());
527 outFile.write(writedata + 16, payload.size() - 16);
528 outFile.close();
529
530 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
531 static_cast<uint8_t>(ipmi::PStatus::Unknown);
532 gNVOOBdata.payloadInfo[payloadType].actualTotalPayloadWritten +=
533 payloadInfo.payloadCurrentSize;
534 return ipmi::responseSuccess(payloadInfo.payloadCurrentSize);
535 }
536 break;
537 case ipmi::PTState::EndTransfer:
538 {
539 PayloadEndTransfer* pPayloadEndTransfer =
540 reinterpret_cast<PayloadEndTransfer*>(payload.data());
541 PayloadInfo payloadInfo = gNVOOBdata.payloadInfo[payloadType];
542 if (pPayloadEndTransfer->payloadReservationID !=
543 payloadInfo.payloadReservationID)
544 {
545 return ipmi::responseInvalidReservationId();
546 }
547 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
548 static_cast<uint8_t>(ipmi::PStatus::Unknown);
549
550 if (gNVOOBdata.payloadInfo[payloadType].actualTotalPayloadWritten !=
551 gNVOOBdata.payloadInfo[payloadType].payloadTotalSize)
552 {
553
554 return ipmi::response(ipmiCCPayloadPayloadInComplete);
555 }
556 std::string tempFilePath =
557 "/var/oob/temp" + std::to_string(payloadType);
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000558 std::string payloadFilePath =
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800559 "/var/oob/Payload" + std::to_string(payloadType);
560 auto renamestatus =
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000561 std::rename(tempFilePath.c_str(), payloadFilePath.c_str());
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800562 if (renamestatus)
563 {
564 phosphor::logging::log<phosphor::logging::level::ERR>(
565 "ipmiOEMSetPayload: Renaming Payload file - failed");
566 }
567
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800568 if (payloadType == static_cast<uint8_t>(ipmi::PType::IntelXMLType0))
569 {
570 // Unzip the Intel format XML file type 0
571 auto response = generateBIOSXMLFile("/usr/bin/lzcat", "-d",
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000572 payloadFilePath.c_str());
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800573 if (response)
574 {
575
576 phosphor::logging::log<phosphor::logging::level::ERR>(
577 "ipmiOEMSetPayload: generateBIOSXMLFile - failed");
578 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
579 static_cast<uint8_t>(ipmi::PStatus::Corrupted);
580 return ipmi::response(ipmiCCPayloadPayloadPacketMissed);
581 }
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000582 phosphor::logging::log<phosphor::logging::level::INFO>(
583 " ipmiOEMSetPayload : Convert XML into native-dbus DONE");
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000584
Arun Lal K Me7725612021-07-15 18:20:58 +0000585 /* So that we don't block the call */
586 auto io = getIoContext();
587 auto dbus = getSdBus();
588 if (io && dbus)
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000589 {
Arun Lal K Me7725612021-07-15 18:20:58 +0000590 std::string service = getService(*dbus, biosConfigIntf,
591 biosConfigBaseMgrPath);
592
593 boost::asio::post(*io, [service, payloadType] {
594 generateAndSendAttributesData(service, payloadType);
595 });
596 }
597 else
598 {
599 phosphor::logging::log<phosphor::logging::level::INFO>(
600 "ipmiOEMSetPayload: Unable to get io context or sdbus");
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000601 return ipmi::responseResponseError();
602 }
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800603 }
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800604
605 struct stat filestat;
606
607 /* Get entry's information. */
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000608 if (!stat(payloadFilePath.c_str(), &filestat))
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800609 {
610 gNVOOBdata.payloadInfo[payloadType].payloadTimeStamp =
611 filestat.st_mtime;
612 gNVOOBdata.payloadInfo[payloadType].payloadTotalSize =
613 filestat.st_size;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800614 }
615 else
616 {
617 return ipmi::responseResponseError();
618 }
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800619 flushNVOOBdata();
620 return ipmi::responseSuccess(
621 gNVOOBdata.payloadInfo[payloadType].actualTotalPayloadWritten);
622 }
623 break;
624 case ipmi::PTState::UserAbort:
625 {
626 PayloadEndTransfer* pPayloadEndTransfer =
627 reinterpret_cast<PayloadEndTransfer*>(payload.data());
628 PayloadInfo payloadInfo = gNVOOBdata.payloadInfo[payloadType];
629 if (pPayloadEndTransfer->payloadReservationID !=
630 payloadInfo.payloadReservationID)
631 {
632 return ipmi::responseInvalidReservationId();
633 }
634 gNVOOBdata.payloadInfo[payloadType].payloadReservationID = 0;
635 gNVOOBdata.payloadInfo[payloadType].payloadType = 0;
636 gNVOOBdata.payloadInfo[payloadType].payloadTotalSize = 0;
637 // Delete the temp file
638 std::string tempFilePath =
639 "/var/oob/temp" + std::to_string(payloadType);
640 unlink(tempFilePath.c_str());
641 flushNVOOBdata();
642 return ipmi::responseSuccess();
643 }
644 break;
645 default:
646 return ipmi::responseInvalidFieldRequest();
647 }
648 return ipmi::responseResponseError();
649}
650
651ipmi::RspType<message::Payload>
652 ipmiOEMGetPayload(ipmi::Context::ptr ctx, uint8_t paramSel,
653 uint8_t payloadType, ipmi::message::Payload& payload)
654{
655 // 1-OOB BIOS config is supported
656 message::Payload retValue;
657
658 if (!(gNVOOBdata.mBIOSCapabilities.OOBCapability & (biosCapOffsetBit)))
659 {
660 return ipmi::response(ipmiCCBIOSCapabilityInitNotDone);
661 }
662 // Validate the Payload Type
663 if (payloadType > maxPayloadSupported)
664 {
665 return ipmi::responseInvalidFieldRequest();
666 }
667
668 struct PayloadInfo res = gNVOOBdata.payloadInfo[payloadType];
669
670 switch (static_cast<GetPayloadParameter>(paramSel))
671 {
672 case ipmi::GetPayloadParameter::GetPayloadInfo:
673 {
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000674
675 std::string payloadFilePath =
676 "/var/oob/Payload" + std::to_string(payloadType);
677
678 std::ifstream ifs(payloadFilePath,
679 std::ios::in | std::ios::binary | std::ios::ate);
680
681 if (!ifs.good())
682 {
683
684 phosphor::logging::log<phosphor::logging::level::ERR>(
685 "ipmiOEMGetPayload: Payload File Error");
686 // File does not exist code here
687 return ipmi::response(ipmi::ccUnspecifiedError);
688 }
689 ifs.close();
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800690 retValue.pack(res.payloadVersion);
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000691 retValue.pack(payloadType);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800692 retValue.pack(res.payloadTotalSize);
693 retValue.pack(res.payloadTotalChecksum);
694 retValue.pack(res.payloadflag);
695 retValue.pack(res.payloadStatus);
696 retValue.pack(res.payloadTimeStamp);
697
698 return ipmi::responseSuccess(std::move(retValue));
699 }
700
701 break;
702 case ipmi::GetPayloadParameter::GetPayloadData:
703 {
704 if (res.payloadStatus ==
705 (static_cast<uint8_t>(ipmi::PStatus::Valid)))
706 {
707 std::vector<uint32_t> reqData;
708 if (payload.unpack(reqData) || !payload.fullyUnpacked())
709 {
710 return ipmi::responseReqDataLenInvalid();
711 }
712 uint32_t offset = reqData.at(0);
713 uint32_t length = reqData.at(1);
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000714 std::string payloadFilePath =
715 "/var/oob/Payload" + std::to_string(payloadType);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800716
Suryakanth Sekar5dd161f2021-06-16 13:02:25 +0000717 std::ifstream ifs(payloadFilePath, std::ios::in |
718 std::ios::binary |
719 std::ios::ate);
720
721 if (!ifs.good())
722 {
723
724 phosphor::logging::log<phosphor::logging::level::ERR>(
725 "ipmiOEMGetPayload: Payload File Error");
726 // File does not exist code here
727 return ipmi::response(ipmi::ccUnspecifiedError);
728 }
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800729 std::ifstream::pos_type fileSize = ifs.tellg();
730 // Total file data within given offset
731 if (fileSize < static_cast<uint64_t>(offset))
732 {
733 ifs.close();
734 return ipmi::responseInvalidFieldRequest();
735 }
736
737 ifs.seekg(offset, std::ios::beg);
738 std::array<uint8_t, maxGetPayloadDataSize> Buffer;
739 ifs.read(reinterpret_cast<char*>(Buffer.data()), length);
740 uint32_t readCount = ifs.gcount();
741 ifs.close();
742
743 boost::crc_32_type calcChecksum;
744 calcChecksum.process_bytes(
745 reinterpret_cast<char*>(Buffer.data()), readCount);
746 uint32_t chkSum = calcChecksum.checksum();
747 retValue.pack(payloadType);
748 retValue.pack(readCount);
749 retValue.pack(chkSum);
750
751 for (int i = 0; i < readCount; i++)
752 {
753 retValue.pack(Buffer.at(i));
754 }
755 return ipmi::responseSuccess(std::move(retValue));
756 }
757 else
758 {
759 return ipmi::responseResponseError();
760 }
761 }
762 break;
763 case ipmi::GetPayloadParameter::GetPayloadStatus:
764 {
765 retValue.pack(gNVOOBdata.payloadInfo[payloadType].payloadStatus);
766 return ipmi::responseSuccess(std::move(retValue));
767 }
768 break;
769 default:
770 return ipmi::responseInvalidFieldRequest();
771 }
772 return ipmi::responseInvalidFieldRequest();
773}
774
775ipmi::RspType<> ipmiOEMSetBIOSHashInfo(
776 ipmi::Context::ptr ctx, std::array<uint8_t, maxSeedSize>& pwdSeed,
Ayushi Smriti32381872021-06-23 11:05:48 +0530777 uint8_t algoInfo, std::array<uint8_t, maxHashSize>& adminPwdHash)
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800778{
779
780 std::string OSState;
781
782 // We should support this command only in KCS Interface
783 if (!IsSystemInterface(ctx))
784 {
785 return ipmi::responseCommandNotAvailable();
786 }
787 getSystemOSState(OSState);
788 // We should not support this command after System Booted - After Exit Boot
789 // service called
790
Ayushi Smriti32381872021-06-23 11:05:48 +0530791 if (OSState == "OperatingState")
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800792 {
Ayushi Smriti32381872021-06-23 11:05:48 +0530793 return ipmi::response(ipmiCCNotSupportedInCurrentState);
794 }
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800795
Ayushi Smriti32381872021-06-23 11:05:48 +0530796 nlohmann::json json;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800797
Ayushi Smriti32381872021-06-23 11:05:48 +0530798 if ((algoInfo & 0xF) == algoSHA384)
799 {
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800800 json["HashAlgo"] = "SHA384";
Ayushi Smriti32381872021-06-23 11:05:48 +0530801 }
802 else if ((algoInfo & 0xF) == algoSHA256)
803 {
804 json["HashAlgo"] = "SHA256";
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800805 }
806 else
807 {
Ayushi Smriti32381872021-06-23 11:05:48 +0530808 return ipmi::responseInvalidFieldRequest();
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800809 }
Ayushi Smriti32381872021-06-23 11:05:48 +0530810
811 json["Seed"] = pwdSeed;
812 json["IsAdminPwdChanged"] = false;
813 json["AdminPwdHash"] = adminPwdHash;
814 json["IsUserPwdChanged"] = false;
815
816 std::array<uint8_t, maxHashSize> userPwdHash;
817 userPwdHash.fill({}); // initializing with 0 as user password hash field
818 // is not used presently
819 json["UserPwdHash"] = userPwdHash;
820 json["StatusFlag"] = algoInfo;
821
822 std::string hashFilePath = "/var/lib/bios-settings-manager/seedData";
823 std::ofstream ofs(hashFilePath, std::ios::out);
824 const auto& writeData = json.dump();
825 ofs << writeData;
826 ofs.close();
827 return ipmi::responseSuccess();
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800828}
829
Ayushi Smriti32381872021-06-23 11:05:48 +0530830ipmi::RspType<std::array<uint8_t, maxSeedSize>, uint8_t,
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800831 std::array<uint8_t, maxHashSize>>
832 ipmiOEMGetBIOSHash(ipmi::Context::ptr ctx)
833{
834
835 std::string OSState;
836 nlohmann::json data = nullptr;
837
838 // We should support this command only in KCS Interface
839 if (!IsSystemInterface(ctx))
840 {
841 return ipmi::responseCommandNotAvailable();
842 }
843
844 getSystemOSState(OSState);
845 // We should not support this command after System Booted - After Exit Boot
846 // service called
847
848 if (OSState != "OperatingState")
849 {
Suryakanth Sekarcc402592021-04-01 15:02:10 +0530850 std::string HashFilePath = "/var/lib/bios-settings-manager/seedData";
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800851
852 std::ifstream devIdFile(HashFilePath);
853 if (devIdFile.is_open())
854 {
855
856 try
857 {
858 data = nlohmann::json::parse(devIdFile, nullptr, false);
859 }
860 catch (const nlohmann::json::parse_error& e)
861 {
862 return ipmi::responseResponseError();
863 }
864
865 if (data.is_discarded())
866 {
867 return ipmi::responseResponseError();
868 }
869
870 std::array<uint8_t, maxHashSize> newAdminHash;
Ayushi Smriti32381872021-06-23 11:05:48 +0530871 std::array<uint8_t, maxSeedSize> seed;
872
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800873 uint8_t flag = 0;
874 uint8_t adminPwdChangedFlag = 0;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800875 if (!data.is_discarded())
876 {
877
878 adminPwdChangedFlag = data["IsAdminPwdChanged"];
879 newAdminHash = data["AdminPwdHash"];
Ayushi Smriti32381872021-06-23 11:05:48 +0530880 seed = data["Seed"];
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800881 }
882
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800883 auto status = getResetBIOSSettings(flag);
884 if (status)
885 {
886 return ipmi::responseResponseError();
887 }
888 if (adminPwdChangedFlag)
889 {
890 flag |= adminPasswordChanged;
891 }
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800892
893 std::copy(std::begin(newAdminHash), std::end(newAdminHash),
894 std::begin(newAdminHash));
Ayushi Smriti32381872021-06-23 11:05:48 +0530895
896 return ipmi::responseSuccess(seed, flag, newAdminHash);
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800897 }
898 else
899 {
900 return ipmi::responseResponseError();
901 }
902 }
903 else
904 {
905
906 return ipmi::response(ipmiCCNotSupportedInCurrentState);
907 }
908}
909
910static void registerBIOSConfigFunctions(void)
911{
912 phosphor::logging::log<phosphor::logging::level::INFO>(
913 "BIOSConfig module initialization");
914 InitNVOOBdata();
915
916 registerHandler(prioOemBase, intel::netFnGeneral,
917 intel::general::cmdSetBIOSCap, Privilege::Admin,
918 ipmiOEMSetBIOSCap);
919
920 registerHandler(prioOemBase, intel::netFnGeneral,
921 intel::general::cmdGetBIOSCap, Privilege::User,
922 ipmiOEMGetBIOSCap);
923 registerHandler(prioOemBase, intel::netFnGeneral,
924 intel::general::cmdSetBIOSPwdHashInfo, Privilege::Admin,
925 ipmiOEMSetBIOSHashInfo);
926
927 registerHandler(prioOemBase, intel::netFnGeneral,
928 intel::general::cmdGetBIOSPwdHash, Privilege::User,
929 ipmiOEMGetBIOSHash);
930
931 registerHandler(prioOemBase, intel::netFnGeneral,
932 intel::general::cmdGetPayload, Privilege::User,
933 ipmiOEMGetPayload);
934 registerHandler(prioOemBase, intel::netFnGeneral,
935 intel::general::cmdSetPayload, Privilege::Admin,
936 ipmiOEMSetPayload);
937
938 return;
939}
940
941} // namespace ipmi