blob: 37a3a5454fa4004d6de6fb0162b767bfa94178e5 [file] [log] [blame]
Ed Tanous1da66f72018-07-27 16:13:37 -07001/*
2// Copyright (c) 2018 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#pragma once
17
18#include "node.hpp"
19
20#include <boost/container/flat_map.hpp>
21#include <experimental/filesystem>
22
23namespace redfish
24{
25
Ed Tanous4ed77cd2018-10-15 08:08:07 -070026constexpr char const *cpuLogObject = "com.intel.CpuDebugLog";
27constexpr char const *cpuLogPath = "/com/intel/CpuDebugLog";
28constexpr char const *cpuLogImmediatePath = "/com/intel/CpuDebugLog/Immediate";
29constexpr char const *cpuLogInterface = "com.intel.CpuDebugLog";
30constexpr char const *cpuLogImmediateInterface =
Ed Tanous1da66f72018-07-27 16:13:37 -070031 "com.intel.CpuDebugLog.Immediate";
Ed Tanous4ed77cd2018-10-15 08:08:07 -070032constexpr char const *cpuLogRawPeciInterface =
Ed Tanous1da66f72018-07-27 16:13:37 -070033 "com.intel.CpuDebugLog.SendRawPeci";
34
35namespace fs = std::experimental::filesystem;
36
37class LogServiceCollection : public Node
38{
39 public:
40 template <typename CrowApp>
41 LogServiceCollection(CrowApp &app) :
Ed Tanous4ed77cd2018-10-15 08:08:07 -070042 Node(app, "/redfish/v1/Managers/bmc/LogServices/")
Ed Tanous1da66f72018-07-27 16:13:37 -070043 {
44 // Collections use static ID for SubRoute to add to its parent, but only
45 // load dynamic data so the duplicate static members don't get displayed
Ed Tanous4ed77cd2018-10-15 08:08:07 -070046 Node::json["@odata.id"] = "/redfish/v1/Managers/bmc/LogServices";
Ed Tanous1da66f72018-07-27 16:13:37 -070047 entityPrivileges = {
48 {boost::beast::http::verb::get, {{"ConfigureComponents"}}},
49 {boost::beast::http::verb::head, {{"ConfigureComponents"}}},
50 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
51 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
52 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
53 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
54 }
55
56 private:
57 /**
58 * Functions triggers appropriate requests on DBus
59 */
60 void doGet(crow::Response &res, const crow::Request &req,
61 const std::vector<std::string> &params) override
62 {
63 // Collections don't include the static data added by SubRoute because
64 // it has a duplicate entry for members
65 res.jsonValue["@odata.type"] =
66 "#LogServiceCollection.LogServiceCollection";
67 res.jsonValue["@odata.context"] =
68 "/redfish/v1/"
69 "$metadata#LogServiceCollection.LogServiceCollection";
Ed Tanous4ed77cd2018-10-15 08:08:07 -070070 res.jsonValue["@odata.id"] = "/redfish/v1/Managers/bmc/LogServices";
Ed Tanous1da66f72018-07-27 16:13:37 -070071 res.jsonValue["Name"] = "Open BMC Log Services Collection";
72 res.jsonValue["Description"] =
73 "Collection of LogServices for this Manager";
74 nlohmann::json &logserviceArray = res.jsonValue["Members"];
75 logserviceArray = nlohmann::json::array();
76#ifdef BMCWEB_ENABLE_REDFISH_CPU_LOG
77 logserviceArray.push_back(
Ed Tanous4ed77cd2018-10-15 08:08:07 -070078 {{"@odata.id", "/redfish/v1/Managers/bmc/LogServices/CpuLog"}});
Ed Tanous1da66f72018-07-27 16:13:37 -070079#endif
80 res.jsonValue["Members@odata.count"] = logserviceArray.size();
81 res.end();
82 }
83};
84
85class CpuLogService : public Node
86{
87 public:
88 template <typename CrowApp>
89 CpuLogService(CrowApp &app) :
Ed Tanous4ed77cd2018-10-15 08:08:07 -070090 Node(app, "/redfish/v1/Managers/bmc/LogServices/CpuLog")
Ed Tanous1da66f72018-07-27 16:13:37 -070091 {
92 // Set the id for SubRoute
Ed Tanous4ed77cd2018-10-15 08:08:07 -070093 Node::json["@odata.id"] = "/redfish/v1/Managers/bmc/LogServices/CpuLog";
Ed Tanous1da66f72018-07-27 16:13:37 -070094 entityPrivileges = {
95 {boost::beast::http::verb::get, {{"ConfigureComponents"}}},
96 {boost::beast::http::verb::head, {{"ConfigureComponents"}}},
97 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
98 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
99 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
100 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
101 }
102
103 private:
104 /**
105 * Functions triggers appropriate requests on DBus
106 */
107 void doGet(crow::Response &res, const crow::Request &req,
108 const std::vector<std::string> &params) override
109 {
110 // Copy over the static data to include the entries added by SubRoute
111 res.jsonValue = Node::json;
112 res.jsonValue["@odata.type"] = "#LogService.v1_1_0.LogService";
113 res.jsonValue["@odata.context"] = "/redfish/v1/"
114 "$metadata#LogService.LogService";
115 res.jsonValue["Name"] = "Open BMC CPU Log Service";
116 res.jsonValue["Description"] = "CPU Log Service";
117 res.jsonValue["Id"] = "CPU Log";
118 res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
119 res.jsonValue["MaxNumberOfRecords"] = 3;
120 res.jsonValue["Actions"] = {
121 {"Oem",
122 {{"#CpuLog.Immediate",
123 {{"target",
Ed Tanous4ed77cd2018-10-15 08:08:07 -0700124 "/redfish/v1/Managers/bmc/LogServices/CpuLog/Actions/Oem/"
Ed Tanous1da66f72018-07-27 16:13:37 -0700125 "CpuLog.Immediate"}}}}}};
126
127#ifdef BMCWEB_ENABLE_REDFISH_RAW_PECI
128 res.jsonValue["Actions"]["Oem"].push_back(
129 {"#CpuLog.SendRawPeci",
130 {{"target",
Ed Tanous4ed77cd2018-10-15 08:08:07 -0700131 "/redfish/v1/Managers/bmc/LogServices/CpuLog/Actions/Oem/"
Ed Tanous1da66f72018-07-27 16:13:37 -0700132 "CpuLog.SendRawPeci"}}});
133#endif
134 res.end();
135 }
136};
137
138class CpuLogEntryCollection : public Node
139{
140 public:
141 template <typename CrowApp>
142 CpuLogEntryCollection(CrowApp &app) :
Ed Tanous4ed77cd2018-10-15 08:08:07 -0700143 Node(app, "/redfish/v1/Managers/bmc/LogServices/CpuLog/Entries")
Ed Tanous1da66f72018-07-27 16:13:37 -0700144 {
145 // Collections use static ID for SubRoute to add to its parent, but only
146 // load dynamic data so the duplicate static members don't get displayed
147 Node::json["@odata.id"] =
Ed Tanous4ed77cd2018-10-15 08:08:07 -0700148 "/redfish/v1/Managers/bmc/LogServices/CpuLog/Entries";
Ed Tanous1da66f72018-07-27 16:13:37 -0700149 entityPrivileges = {
150 {boost::beast::http::verb::get, {{"ConfigureComponents"}}},
151 {boost::beast::http::verb::head, {{"ConfigureComponents"}}},
152 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
153 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
154 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
155 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
156 }
157
158 private:
159 /**
160 * Functions triggers appropriate requests on DBus
161 */
162 void doGet(crow::Response &res, const crow::Request &req,
163 const std::vector<std::string> &params) override
164 {
165 // Collections don't include the static data added by SubRoute because
166 // it has a duplicate entry for members
167 auto getLogEntriesCallback =
168 [&res](const boost::system::error_code ec,
169 const std::vector<std::string> &resp) {
170 if (ec)
171 {
172 if (ec.value() !=
173 boost::system::errc::no_such_file_or_directory)
174 {
175 BMCWEB_LOG_DEBUG << "failed to get entries ec: "
176 << ec.message();
177 res.result(
178 boost::beast::http::status::internal_server_error);
179 res.end();
180 return;
181 }
182 }
183 res.jsonValue["@odata.type"] =
184 "#LogEntryCollection.LogEntryCollection";
185 res.jsonValue["@odata.context"] =
186 "/redfish/v1/"
187 "$metadata#LogEntryCollection.LogEntryCollection";
188 res.jsonValue["Name"] = "Open BMC CPU Log Entries";
189 res.jsonValue["Description"] = "Collection of CPU Log Entries";
Ed Tanous4ed77cd2018-10-15 08:08:07 -0700190 nlohmann::json &logentryArray = res.jsonValue["Members"];
191 logentryArray = nlohmann::json::array();
Ed Tanous1da66f72018-07-27 16:13:37 -0700192 for (const std::string &objpath : resp)
193 {
194 // Don't list the immediate log
Ed Tanous4ed77cd2018-10-15 08:08:07 -0700195 if (objpath.compare(cpuLogImmediatePath) == 0)
Ed Tanous1da66f72018-07-27 16:13:37 -0700196 {
197 continue;
198 }
Ed Tanous4ed77cd2018-10-15 08:08:07 -0700199 std::size_t lastPos = objpath.rfind("/");
200 if (lastPos != std::string::npos)
Ed Tanous1da66f72018-07-27 16:13:37 -0700201 {
Ed Tanous4ed77cd2018-10-15 08:08:07 -0700202 logentryArray.push_back(
203 {{"@odata.id", "/redfish/v1/Managers/bmc/"
Ed Tanous1da66f72018-07-27 16:13:37 -0700204 "LogServices/CpuLog/Entries/" +
Ed Tanous4ed77cd2018-10-15 08:08:07 -0700205 objpath.substr(lastPos + 1)}});
Ed Tanous1da66f72018-07-27 16:13:37 -0700206 }
207 }
Ed Tanous4ed77cd2018-10-15 08:08:07 -0700208 res.jsonValue["Members@odata.count"] = logentryArray.size();
Ed Tanous1da66f72018-07-27 16:13:37 -0700209 res.end();
210 };
211 crow::connections::systemBus->async_method_call(
212 std::move(getLogEntriesCallback),
213 "xyz.openbmc_project.ObjectMapper",
214 "/xyz/openbmc_project/object_mapper",
215 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "", 0,
Ed Tanous4ed77cd2018-10-15 08:08:07 -0700216 std::array<const char *, 1>{cpuLogInterface});
Ed Tanous1da66f72018-07-27 16:13:37 -0700217 }
218};
219
220std::string getLogCreatedTime(const nlohmann::json &cpuLog)
221{
222 nlohmann::json::const_iterator metaIt = cpuLog.find("metadata");
223 if (metaIt != cpuLog.end())
224 {
225 nlohmann::json::const_iterator tsIt = metaIt->find("timestamp");
226 if (tsIt != metaIt->end())
227 {
228 const std::string *logTime = tsIt->get_ptr<const std::string *>();
229 if (logTime != nullptr)
230 {
231 return *logTime;
232 }
233 }
234 }
235 BMCWEB_LOG_DEBUG << "failed to find log timestamp";
236
237 return std::string();
238}
239
240class CpuLogEntry : public Node
241{
242 public:
243 CpuLogEntry(CrowApp &app) :
Ed Tanous4ed77cd2018-10-15 08:08:07 -0700244 Node(app, "/redfish/v1/Managers/bmc/LogServices/CpuLog/Entries/<str>/",
Ed Tanous1da66f72018-07-27 16:13:37 -0700245 std::string())
246 {
247 entityPrivileges = {
248 {boost::beast::http::verb::get, {{"ConfigureComponents"}}},
249 {boost::beast::http::verb::head, {{"ConfigureComponents"}}},
250 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
251 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
252 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
253 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
254 }
255
256 private:
257 void doGet(crow::Response &res, const crow::Request &req,
258 const std::vector<std::string> &params) override
259 {
260 if (params.size() != 1)
261 {
262 res.result(boost::beast::http::status::internal_server_error);
263 res.end();
264 return;
265 }
Ed Tanous4ed77cd2018-10-15 08:08:07 -0700266 const uint8_t logId = std::atoi(params[0].c_str());
Ed Tanous1da66f72018-07-27 16:13:37 -0700267 auto getStoredLogCallback = [&res,
Ed Tanous4ed77cd2018-10-15 08:08:07 -0700268 logId](const boost::system::error_code ec,
269 const sdbusplus::message::variant<
270 std::string> &resp) {
Ed Tanous1da66f72018-07-27 16:13:37 -0700271 if (ec)
272 {
273 BMCWEB_LOG_DEBUG << "failed to get log ec: " << ec.message();
274 res.result(boost::beast::http::status::internal_server_error);
275 res.end();
276 return;
277 }
278 const std::string *log = mapbox::getPtr<const std::string>(resp);
279 if (log == nullptr)
280 {
281 res.result(boost::beast::http::status::internal_server_error);
282 res.end();
283 return;
284 }
285 nlohmann::json j = nlohmann::json::parse(*log, nullptr, false);
286 if (j.is_discarded())
287 {
288 res.result(boost::beast::http::status::internal_server_error);
289 res.end();
290 return;
291 }
292 std::string t = getLogCreatedTime(j);
293 res.jsonValue = {
294 {"@odata.type", "#LogEntry.v1_3_0.LogEntry"},
295 {"@odata.context", "/redfish/v1/$metadata#LogEntry.LogEntry"},
296 {"@odata.id",
Ed Tanous4ed77cd2018-10-15 08:08:07 -0700297 "/redfish/v1/Managers/bmc/LogServices/CpuLog/Entries/" +
298 std::to_string(logId)},
Ed Tanous1da66f72018-07-27 16:13:37 -0700299 {"Name", "CPU Debug Log"},
Ed Tanous4ed77cd2018-10-15 08:08:07 -0700300 {"Id", logId},
Ed Tanous1da66f72018-07-27 16:13:37 -0700301 {"EntryType", "Oem"},
302 {"OemRecordFormat", "Intel CPU Log"},
303 {"Oem", {{"Intel", std::move(j)}}},
304 {"Created", std::move(t)}};
305 res.end();
306 };
307 crow::connections::systemBus->async_method_call(
Ed Tanous4ed77cd2018-10-15 08:08:07 -0700308 std::move(getStoredLogCallback), cpuLogObject,
309 cpuLogPath + std::string("/") + std::to_string(logId),
310 "org.freedesktop.DBus.Properties", "Get", cpuLogInterface, "Log");
Ed Tanous1da66f72018-07-27 16:13:37 -0700311 }
312};
313
314class ImmediateCpuLog : public Node
315{
316 public:
317 ImmediateCpuLog(CrowApp &app) :
Ed Tanous4ed77cd2018-10-15 08:08:07 -0700318 Node(app, "/redfish/v1/Managers/bmc/LogServices/CpuLog/Actions/Oem/"
Ed Tanous1da66f72018-07-27 16:13:37 -0700319 "CpuLog.Immediate")
320 {
321 entityPrivileges = {
322 {boost::beast::http::verb::get, {{"ConfigureComponents"}}},
323 {boost::beast::http::verb::head, {{"ConfigureComponents"}}},
324 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
325 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
326 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
327 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
328 }
329
330 private:
331 void doPost(crow::Response &res, const crow::Request &req,
332 const std::vector<std::string> &params) override
333 {
334 static std::unique_ptr<sdbusplus::bus::match::match>
335 immediateLogMatcher;
336
337 // Only allow one Immediate Log request at a time
338 if (immediateLogMatcher != nullptr)
339 {
340 res.addHeader("Retry-After", "30");
341 res.result(boost::beast::http::status::service_unavailable);
342 messages::addMessageToJson(
343 res.jsonValue, messages::serviceTemporarilyUnavailable("30"),
344 "/CpuLog.Immediate");
345 res.end();
346 return;
347 }
348 // Make this static so it survives outside this method
349 static boost::asio::deadline_timer timeout(*req.ioService);
350
351 timeout.expires_from_now(boost::posix_time::seconds(30));
352 timeout.async_wait([&res](const boost::system::error_code &ec) {
353 immediateLogMatcher = nullptr;
354 if (ec)
355 {
356 // operation_aborted is expected if timer is canceled before
357 // completion.
358 if (ec != boost::asio::error::operation_aborted)
359 {
360 BMCWEB_LOG_ERROR << "Async_wait failed " << ec;
361 }
362 return;
363 }
364 BMCWEB_LOG_ERROR << "Timed out waiting for immediate log";
365
366 res.result(boost::beast::http::status::internal_server_error);
367 res.end();
368 });
369
370 auto immediateLogMatcherCallback = [&res](
371 sdbusplus::message::message &m) {
372 BMCWEB_LOG_DEBUG << "Immediate log available match fired";
373 boost::system::error_code ec;
374 timeout.cancel(ec);
375 if (ec)
376 {
377 BMCWEB_LOG_ERROR << "error canceling timer " << ec;
378 }
Ed Tanous4ed77cd2018-10-15 08:08:07 -0700379 sdbusplus::message::object_path objPath;
Ed Tanous1da66f72018-07-27 16:13:37 -0700380 boost::container::flat_map<
381 std::string,
382 boost::container::flat_map<
383 std::string, sdbusplus::message::variant<std::string>>>
Ed Tanous4ed77cd2018-10-15 08:08:07 -0700384 interfacesAdded;
385 m.read(objPath, interfacesAdded);
Ed Tanous1da66f72018-07-27 16:13:37 -0700386 const std::string *log = mapbox::getPtr<const std::string>(
Ed Tanous4ed77cd2018-10-15 08:08:07 -0700387 interfacesAdded[cpuLogInterface]["Log"]);
Ed Tanous1da66f72018-07-27 16:13:37 -0700388 if (log == nullptr)
389 {
390 res.result(boost::beast::http::status::internal_server_error);
391 res.end();
392 // Careful with immediateLogMatcher. It is a unique_ptr to the
393 // match object inside which this lambda is executing. Once it
394 // is set to nullptr, the match object will be destroyed and the
395 // lambda will lose its context, including res, so it needs to
396 // be the last thing done.
397 immediateLogMatcher = nullptr;
398 return;
399 }
400 nlohmann::json j = nlohmann::json::parse(*log, nullptr, false);
401 if (j.is_discarded())
402 {
403 res.result(boost::beast::http::status::internal_server_error);
404 res.end();
405 // Careful with immediateLogMatcher. It is a unique_ptr to the
406 // match object inside which this lambda is executing. Once it
407 // is set to nullptr, the match object will be destroyed and the
408 // lambda will lose its context, including res, so it needs to
409 // be the last thing done.
410 immediateLogMatcher = nullptr;
411 return;
412 }
413 std::string t = getLogCreatedTime(j);
414 res.jsonValue = {
415 {"@odata.type", "#LogEntry.v1_3_0.LogEntry"},
416 {"@odata.context", "/redfish/v1/$metadata#LogEntry.LogEntry"},
417 {"Name", "CPU Debug Log"},
418 {"EntryType", "Oem"},
419 {"OemRecordFormat", "Intel CPU Log"},
420 {"Oem", {{"Intel", std::move(j)}}},
421 {"Created", std::move(t)}};
422 res.end();
423 // Careful with immediateLogMatcher. It is a unique_ptr to the
424 // match object inside which this lambda is executing. Once it is
425 // set to nullptr, the match object will be destroyed and the lambda
426 // will lose its context, including res, so it needs to be the last
427 // thing done.
428 immediateLogMatcher = nullptr;
429 };
430 immediateLogMatcher = std::make_unique<sdbusplus::bus::match::match>(
431 *crow::connections::systemBus,
432 sdbusplus::bus::match::rules::interfacesAdded() +
Ed Tanous4ed77cd2018-10-15 08:08:07 -0700433 sdbusplus::bus::match::rules::argNpath(0, cpuLogImmediatePath),
Ed Tanous1da66f72018-07-27 16:13:37 -0700434 std::move(immediateLogMatcherCallback));
435
436 auto generateImmediateLogCallback =
437 [&res](const boost::system::error_code ec,
438 const std::string &resp) {
439 if (ec)
440 {
441 if (ec.value() ==
442 boost::system::errc::operation_not_supported)
443 {
444 messages::addMessageToJson(
445 res.jsonValue, messages::resourceInStandby(),
446 "/CpuLog.Immediate");
447 res.result(
448 boost::beast::http::status::service_unavailable);
449 }
450 else
451 {
452 res.result(
453 boost::beast::http::status::internal_server_error);
454 }
455 res.end();
456 boost::system::error_code timeoutec;
457 timeout.cancel(timeoutec);
458 if (timeoutec)
459 {
460 BMCWEB_LOG_ERROR << "error canceling timer "
461 << timeoutec;
462 }
463 immediateLogMatcher = nullptr;
464 return;
465 }
466 };
467 crow::connections::systemBus->async_method_call(
Ed Tanous4ed77cd2018-10-15 08:08:07 -0700468 std::move(generateImmediateLogCallback), cpuLogObject, cpuLogPath,
469 cpuLogImmediateInterface, "GenerateImmediateLog");
Ed Tanous1da66f72018-07-27 16:13:37 -0700470 }
471};
472
473class SendRawPeci : public Node
474{
475 public:
476 SendRawPeci(CrowApp &app) :
Ed Tanous4ed77cd2018-10-15 08:08:07 -0700477 Node(app, "/redfish/v1/Managers/bmc/LogServices/CpuLog/Actions/Oem/"
Ed Tanous1da66f72018-07-27 16:13:37 -0700478 "CpuLog.SendRawPeci")
479 {
480 entityPrivileges = {
481 {boost::beast::http::verb::get, {{"ConfigureComponents"}}},
482 {boost::beast::http::verb::head, {{"ConfigureComponents"}}},
483 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
484 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
485 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
486 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
487 }
488
489 private:
490 void doPost(crow::Response &res, const crow::Request &req,
491 const std::vector<std::string> &params) override
492 {
493 // Get the Raw PECI command from the request
494 nlohmann::json rawPeciCmd;
495 if (!json_util::processJsonFromRequest(res, req, rawPeciCmd))
496 {
497 return;
498 }
499 // Get the Client Address from the request
500 nlohmann::json::const_iterator caIt = rawPeciCmd.find("ClientAddress");
501 if (caIt == rawPeciCmd.end())
502 {
503 messages::addMessageToJson(
504 res.jsonValue, messages::propertyMissing("ClientAddress"),
505 "/ClientAddress");
506 res.result(boost::beast::http::status::bad_request);
507 res.end();
508 return;
509 }
510 const uint64_t *ca = caIt->get_ptr<const uint64_t *>();
511 if (ca == nullptr)
512 {
513 messages::addMessageToJson(
514 res.jsonValue,
515 messages::propertyValueTypeError(caIt->dump(), "ClientAddress"),
516 "/ClientAddress");
517 res.result(boost::beast::http::status::bad_request);
518 res.end();
519 return;
520 }
521 // Get the Read Length from the request
522 const uint8_t clientAddress = static_cast<uint8_t>(*ca);
523 nlohmann::json::const_iterator rlIt = rawPeciCmd.find("ReadLength");
524 if (rlIt == rawPeciCmd.end())
525 {
526 messages::addMessageToJson(res.jsonValue,
527 messages::propertyMissing("ReadLength"),
528 "/ReadLength");
529 res.result(boost::beast::http::status::bad_request);
530 res.end();
531 return;
532 }
533 const uint64_t *rl = rlIt->get_ptr<const uint64_t *>();
534 if (rl == nullptr)
535 {
536 messages::addMessageToJson(
537 res.jsonValue,
538 messages::propertyValueTypeError(rlIt->dump(), "ReadLength"),
539 "/ReadLength");
540 res.result(boost::beast::http::status::bad_request);
541 res.end();
542 return;
543 }
544 // Get the PECI Command from the request
545 const uint32_t readLength = static_cast<uint32_t>(*rl);
546 nlohmann::json::const_iterator pcIt = rawPeciCmd.find("PECICommand");
547 if (pcIt == rawPeciCmd.end())
548 {
549 messages::addMessageToJson(res.jsonValue,
550 messages::propertyMissing("PECICommand"),
551 "/PECICommand");
552 res.result(boost::beast::http::status::bad_request);
553 res.end();
554 return;
555 }
556 std::vector<uint8_t> peciCommand;
557 for (auto pc : *pcIt)
558 {
559 const uint64_t *val = pc.get_ptr<const uint64_t *>();
560 if (val == nullptr)
561 {
562 messages::addMessageToJson(
563 res.jsonValue,
564 messages::propertyValueTypeError(
565 pc.dump(),
566 "PECICommand/" + std::to_string(peciCommand.size())),
567 "/PECICommand");
568 res.result(boost::beast::http::status::bad_request);
569 res.end();
570 return;
571 }
572 peciCommand.push_back(static_cast<uint8_t>(*val));
573 }
574 // Callback to return the Raw PECI response
575 auto sendRawPeciCallback = [&res](const boost::system::error_code ec,
576 const std::vector<uint8_t> &resp) {
577 if (ec)
578 {
579 BMCWEB_LOG_DEBUG << "failed to send PECI command ec: "
580 << ec.message();
581 res.result(boost::beast::http::status::internal_server_error);
582 res.end();
583 return;
584 }
585 res.jsonValue = {{"Name", "PECI Command Response"},
586 {"PECIResponse", resp}};
587 res.end();
588 };
589 // Call the SendRawPECI command with the provided data
590 crow::connections::systemBus->async_method_call(
Ed Tanous4ed77cd2018-10-15 08:08:07 -0700591 std::move(sendRawPeciCallback), cpuLogObject, cpuLogPath,
592 cpuLogRawPeciInterface, "SendRawPeci", clientAddress, readLength,
593 peciCommand);
Ed Tanous1da66f72018-07-27 16:13:37 -0700594 }
595};
596
597} // namespace redfish