blob: bce8929aa089466154a49d258deca77c12ccd890 [file] [log] [blame]
Vernon Mauerya3702c12019-05-22 13:20:59 -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
17#include <errno.h>
18#include <ipmid/api.h>
19
20#include <commandutils.hpp>
21#include <cstdint>
22#include <ipmid/utils.hpp>
23#include <phosphor-ipmi-host/ipmid.hpp>
24#include <phosphor-logging/elog-errors.hpp>
25#include <phosphor-logging/log.hpp>
26#include <sdbusplus/bus.hpp>
27#include <smbiosmdrv2.hpp>
28#include <string>
29#include <vector>
30#include <xyz/openbmc_project/Common/error.hpp>
31
32constexpr const char* DBUS_PROPERTIES = "org.freedesktop.DBus.Properties";
33constexpr const char* MDRV2_PATH = "/xyz/openbmc_project/Smbios/MDR_V2";
34constexpr const char* MDRV2_INTERFACE = "xyz.openbmc_project.Smbios.MDR_V2";
35constexpr const int LAST_AGENT_INDEX = -1;
36constexpr const uint16_t LAST_AGENT_ID = 0xFFFF;
37
38static void register_netfn_smbiosmdrv2_functions() __attribute__((constructor));
39static sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
40
Vernon Maueryc7d517e2019-06-18 14:27:00 -070041int gentLookup(const uint16_t& agentId, const std::string& service)
Vernon Mauerya3702c12019-05-22 13:20:59 -070042{
43 int agentIndex = -1;
44
45 if (LAST_AGENT_ID == agentId)
46 {
47 return LAST_AGENT_INDEX;
48 }
49
50 sdbusplus::message::message method = bus.new_method_call(
51 service.c_str(), MDRV2_PATH, MDRV2_INTERFACE, "AgentLookup");
52 method.append(agentId);
53 sdbusplus::message::message reply = bus.call(method);
54 if (reply.is_method_error())
55 {
56 phosphor::logging::log<phosphor::logging::level::ERR>(
57 "Error get agent index, sdbusplus call failed");
58 return -1;
59 }
60 reply.read(agentIndex);
61
62 return agentIndex;
63}
64
65int findLockHandle(const uint16_t& lockHandle, const std::string& service)
66{
67 int idIndex = -1;
68 sdbusplus::message::message method = bus.new_method_call(
69 service.c_str(), MDRV2_PATH, MDRV2_INTERFACE, "FindLockHandle");
70 method.append(lockHandle);
71
72 sdbusplus::message::message reply = bus.call(method);
73 if (reply.is_method_error())
74 {
75 phosphor::logging::log<phosphor::logging::level::ERR>(
76 "Error find lock handle",
77 phosphor::logging::entry("SERVICE=%s", service.c_str()),
78 phosphor::logging::entry("PATH=%s", MDRV2_PATH));
79 return -1;
80 }
81 reply.read(idIndex);
82
83 return idIndex;
84}
85
86int sdplusMdrv2GetProperty(const std::string& name,
87 sdbusplus::message::variant<uint8_t>& value,
88 const std::string& service)
89{
90 sdbusplus::message::message method = bus.new_method_call(
91 service.c_str(), MDRV2_PATH, DBUS_PROPERTIES, "Get");
92 method.append(MDRV2_INTERFACE, name);
93 sdbusplus::message::message reply = bus.call(method);
94 if (reply.is_method_error())
95 {
96 phosphor::logging::log<phosphor::logging::level::ERR>(
97 "Error get property, sdbusplus call failed");
98 return -1;
99 }
100 reply.read(value);
101
102 return 0;
103}
104
105int findDataId(const uint8_t* dataInfo, const size_t& len,
106 const std::string& service)
107{
108 int idIndex = -1;
109 sdbusplus::message::message method = bus.new_method_call(
110 service.c_str(), MDRV2_PATH, MDRV2_INTERFACE, "FindIdIndex");
111 std::vector<uint8_t> info;
112 for (int index = 0; index < len; index++)
113 {
114 info.push_back(dataInfo[index]);
115 }
116 method.append(info);
117
118 sdbusplus::message::message reply = bus.call(method);
119 if (reply.is_method_error())
120 {
121 phosphor::logging::log<phosphor::logging::level::ERR>(
122 "Error find id index",
123 phosphor::logging::entry("SERVICE=%s", service.c_str()),
124 phosphor::logging::entry("PATH=%s", MDRV2_PATH));
125 return -1;
126 }
127 reply.read(idIndex);
128
129 return idIndex;
130}
131
132ipmi_ret_t cmd_mdr2_agent_status(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
133 ipmi_request_t request,
134 ipmi_response_t response,
135 ipmi_data_len_t data_len,
136 ipmi_context_t context)
137{
138 auto requestData = reinterpret_cast<const MDRiiGetAgentStatus*>(request);
139 auto dataOut = reinterpret_cast<uint8_t*>(response);
140 std::vector<uint8_t> status;
141
142 if (*data_len != sizeof(MDRiiGetAgentStatus))
143 {
144 *data_len = 0;
145 return IPMI_CC_REQ_DATA_LEN_INVALID;
146 }
147
148 *data_len = 0;
149
150 std::string service = ipmi::getService(bus, MDRV2_INTERFACE, MDRV2_PATH);
151
152 int agentIndex = agentLookup(requestData->agentId, service);
153 if (agentIndex == -1)
154 {
155 phosphor::logging::log<phosphor::logging::level::ERR>(
156 "Unknown agent id",
157 phosphor::logging::entry("ID=%x", requestData->agentId));
158 return IPMI_CC_PARM_OUT_OF_RANGE;
159 }
160
161 sdbusplus::message::message method = bus.new_method_call(
162 service.c_str(), MDRV2_PATH, MDRV2_INTERFACE, "AgentStatus");
163 method.append(requestData->dirVersion);
164 sdbusplus::message::message reply = bus.call(method);
165 if (reply.is_method_error())
166 {
167 phosphor::logging::log<phosphor::logging::level::ERR>(
168 "Error get agent status",
169 phosphor::logging::entry("SERVICE=%s", service.c_str()),
170 phosphor::logging::entry("PATH=%s", MDRV2_PATH));
171 return IPMI_CC_UNSPECIFIED_ERROR;
172 }
173 reply.read(status);
174
175 if (status.size() != sizeof(MDRiiAgentStatusResponse))
176 {
177 phosphor::logging::log<phosphor::logging::level::ERR>(
178 "Get agent status response length not valid");
179 return IPMI_CC_UNSPECIFIED_ERROR;
180 }
181 *data_len = static_cast<size_t>(status.size());
182 std::copy(&status[0], &status[*data_len], dataOut);
183 return IPMI_CC_OK;
184}
185
186ipmi_ret_t cmd_mdr2_get_dir(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
187 ipmi_request_t request, ipmi_response_t response,
188 ipmi_data_len_t data_len, ipmi_context_t context)
189{
190 auto requestData = reinterpret_cast<const MDRiiGetDirRequest*>(request);
191 auto dataOut = reinterpret_cast<uint8_t*>(response);
192 std::vector<uint8_t> dirInfo;
193
194 if (*data_len != sizeof(MDRiiGetDirRequest))
195 {
196 *data_len = 0;
197 return IPMI_CC_REQ_DATA_LEN_INVALID;
198 }
199
200 *data_len = 0;
201
202 std::string service = ipmi::getService(bus, MDRV2_INTERFACE, MDRV2_PATH);
203
204 int agentIndex = agentLookup(requestData->agentId, service);
205 if (agentIndex == -1)
206 {
207 phosphor::logging::log<phosphor::logging::level::ERR>(
208 "Unknown agent id",
209 phosphor::logging::entry("ID=%x", requestData->agentId));
210 return IPMI_CC_PARM_OUT_OF_RANGE;
211 }
212
213 sdbusplus::message::variant<uint8_t> value = 0;
214 if (0 != sdplusMdrv2GetProperty("DirEntries", value, service))
215 {
216 phosphor::logging::log<phosphor::logging::level::ERR>(
217 "Error getting DirEnries");
218 return IPMI_CC_UNSPECIFIED_ERROR;
219 }
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700220 if (requestData->dirIndex > std::get<uint8_t>(value))
Vernon Mauerya3702c12019-05-22 13:20:59 -0700221 {
222 return IPMI_CC_PARM_OUT_OF_RANGE;
223 }
224
225 sdbusplus::message::message method = bus.new_method_call(
226 service.c_str(), MDRV2_PATH, MDRV2_INTERFACE, "GetDir");
227
228 method.append(requestData->dirIndex);
229
230 sdbusplus::message::message reply = bus.call(method);
231 if (reply.is_method_error())
232 {
233 phosphor::logging::log<phosphor::logging::level::ERR>(
234 "Error get dir",
235 phosphor::logging::entry("SERVICE=%s", service.c_str()),
236 phosphor::logging::entry("PATH=%s", MDRV2_PATH));
237 return IPMI_CC_UNSPECIFIED_ERROR;
238 }
239 reply.read(dirInfo);
240
241 if (dirInfo.size() < sizeof(MDRiiGetDirResponse))
242 {
243 phosphor::logging::log<phosphor::logging::level::ERR>(
244 "Error get dir, response length invalid");
245 return IPMI_CC_UNSPECIFIED_ERROR;
246 }
247
248 auto responseData = reinterpret_cast<MDRiiGetDirResponse*>(dirInfo.data());
249
250 *data_len = dirInfo.size();
251
252 if (*data_len > MAX_IPMI_BUFFER) // length + completion code should no more
253 // than MAX_IPMI_BUFFER
254 {
255 phosphor::logging::log<phosphor::logging::level::ERR>(
256 "Data length send from service is invalid");
257 *data_len = 0;
258 return IPMI_CC_RESPONSE_ERROR;
259 }
260
261 std::copy(&dirInfo[0], &dirInfo[*data_len], dataOut);
262
263 return IPMI_CC_OK;
264}
265
266ipmi_ret_t cmd_mdr2_get_data_info(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
267 ipmi_request_t request,
268 ipmi_response_t response,
269 ipmi_data_len_t data_len,
270 ipmi_context_t context)
271{
272 auto requestData =
273 reinterpret_cast<const MDRiiGetDataInfoRequest*>(request);
274 auto dataOut = reinterpret_cast<uint8_t*>(response);
275 std::vector<uint8_t> res;
276
277 if (*data_len < sizeof(MDRiiGetDataInfoRequest))
278 {
279 *data_len = 0;
280 return IPMI_CC_REQ_DATA_LEN_INVALID;
281 }
282
283 *data_len = 0;
284
285 std::string service = ipmi::getService(bus, MDRV2_INTERFACE, MDRV2_PATH);
286
287 int agentIndex = agentLookup(requestData->agentId, service);
288 if (agentIndex == -1)
289 {
290 phosphor::logging::log<phosphor::logging::level::ERR>(
291 "Unknown agent id",
292 phosphor::logging::entry("ID=%x", requestData->agentId));
293 return IPMI_CC_PARM_OUT_OF_RANGE;
294 }
295
296 int idIndex =
297 findDataId(requestData->dataSetInfo.dataInfo,
298 sizeof(requestData->dataSetInfo.dataInfo), service);
299
300 if ((idIndex < 0) || (idIndex >= maxDirEntries))
301 {
302 phosphor::logging::log<phosphor::logging::level::ERR>(
303 "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex));
304 return IPMI_CC_PARM_OUT_OF_RANGE;
305 }
306
307 sdbusplus::message::message method = bus.new_method_call(
308 service.c_str(), MDRV2_PATH, MDRV2_INTERFACE, "GetDataInfo");
309
310 method.append(idIndex);
311
312 sdbusplus::message::message reply = bus.call(method);
313 if (reply.is_method_error())
314 {
315 phosphor::logging::log<phosphor::logging::level::ERR>(
316 "Error get data info",
317 phosphor::logging::entry("SERVICE=%s", service.c_str()),
318 phosphor::logging::entry("PATH=%s", MDRV2_PATH));
319 return IPMI_CC_UNSPECIFIED_ERROR;
320 }
321 reply.read(res);
322
323 if (res.size() != sizeof(MDRiiGetDataInfoResponse))
324 {
325 phosphor::logging::log<phosphor::logging::level::ERR>(
326 "Get data info response length not invalid");
327 return IPMI_CC_UNSPECIFIED_ERROR;
328 }
329 *data_len = static_cast<size_t>(res.size());
330 std::copy(&res[0], &res[*data_len], dataOut);
331
332 return IPMI_CC_OK;
333}
334
335ipmi_ret_t cmd_mdr2_lock_data(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
336 ipmi_request_t request, ipmi_response_t response,
337 ipmi_data_len_t data_len, ipmi_context_t context)
338{
339 auto requestData = reinterpret_cast<const MDRiiLockDataRequest*>(request);
340 auto responseData = reinterpret_cast<MDRiiLockDataResponse*>(response);
341
342 std::tuple<bool, uint8_t, uint16_t, uint32_t, uint32_t, uint32_t> res;
343
344 if (*data_len < sizeof(MDRiiLockDataRequest))
345 {
346 *data_len = 0;
347 return IPMI_CC_REQ_DATA_LEN_INVALID;
348 }
349
350 *data_len = 0;
351
352 std::string service = ipmi::getService(bus, MDRV2_INTERFACE, MDRV2_PATH);
353
354 int agentIndex = agentLookup(requestData->agentId, service);
355 if (agentIndex == -1)
356 {
357 phosphor::logging::log<phosphor::logging::level::ERR>(
358 "Unknown agent id",
359 phosphor::logging::entry("ID=%x", requestData->agentId));
360 return IPMI_CC_PARM_OUT_OF_RANGE;
361 }
362
363 int idIndex =
364 findDataId(requestData->dataSetInfo.dataInfo,
365 sizeof(requestData->dataSetInfo.dataInfo), service);
366
367 if ((idIndex < 0) || (idIndex >= maxDirEntries))
368 {
369 phosphor::logging::log<phosphor::logging::level::ERR>(
370 "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex));
371 return IPMI_CC_PARM_OUT_OF_RANGE;
372 }
373
374 sdbusplus::message::message method = bus.new_method_call(
375 service.c_str(), MDRV2_PATH, MDRV2_INTERFACE, "LockData");
376
377 method.append((uint8_t)idIndex, requestData->timeout);
378
379 sdbusplus::message::message reply = bus.call(method);
380 if (reply.is_method_error())
381 {
382 if (reply.get_errno() == EBUSY)
383 {
384 phosphor::logging::log<phosphor::logging::level::ERR>(
385 "Lock Data failed - cannot lock idIndex");
386 return IPMI_CC_PARAMETER_NOT_SUPPORT_IN_PRESENT_STATE;
387 }
388 phosphor::logging::log<phosphor::logging::level::ERR>(
389 "Error lock data",
390 phosphor::logging::entry("SERVICE=%s", service.c_str()),
391 phosphor::logging::entry("PATH=%s", MDRV2_PATH));
392 return IPMI_CC_UNSPECIFIED_ERROR;
393 }
394 reply.read(res);
395
396 if (std::get<0>(res) == false)
397 {
398 return IPMI_CC_PARAMETER_NOT_SUPPORT_IN_PRESENT_STATE;
399 }
400
401 *data_len = sizeof(MDRiiLockDataResponse);
402
403 responseData->mdrVersion = std::get<1>(res);
404 responseData->lockHandle = std::get<2>(res);
405 responseData->dataLength = std::get<3>(res);
406 responseData->xferAddress = std::get<4>(res);
407 responseData->xferLength = std::get<5>(res);
408
409 return IPMI_CC_OK;
410}
411
412ipmi_ret_t cmd_mdr2_unlock_data(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
413 ipmi_request_t request,
414 ipmi_response_t response,
415 ipmi_data_len_t data_len,
416 ipmi_context_t context)
417{
418 auto requestData = reinterpret_cast<const MDRiiUnlockDataRequest*>(request);
419 std::string resStatus;
420
421 if (*data_len != sizeof(MDRiiUnlockDataRequest))
422 {
423 *data_len = 0;
424 return IPMI_CC_REQ_DATA_LEN_INVALID;
425 }
426
427 *data_len = 0;
428
429 std::string service = ipmi::getService(bus, MDRV2_INTERFACE, MDRV2_PATH);
430
431 int agentIndex = agentLookup(requestData->agentId, service);
432 if (agentIndex == -1)
433 {
434 phosphor::logging::log<phosphor::logging::level::ERR>(
435 "Unknown agent id",
436 phosphor::logging::entry("ID=%x", requestData->agentId));
437 return IPMI_CC_PARM_OUT_OF_RANGE;
438 }
439
440 int idIndex = findLockHandle(requestData->lockHandle, service);
441
442 if ((idIndex < 0) || (idIndex >= maxDirEntries))
443 {
444 phosphor::logging::log<phosphor::logging::level::ERR>(
445 "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex));
446 return IPMI_CC_PARM_OUT_OF_RANGE;
447 }
448
449 sdbusplus::message::message method = bus.new_method_call(
450 service.c_str(), MDRV2_PATH, MDRV2_INTERFACE, "UnLockData");
451 method.append((uint8_t)idIndex);
452
453 sdbusplus::message::message reply = bus.call(method);
454 if (reply.is_method_error())
455 {
456 if (reply.get_errno() == EBUSY)
457 {
458 phosphor::logging::log<phosphor::logging::level::ERR>(
459 "Unlock Data failed - cannot unlock idIndex");
460 return IPMI_CC_PARAMETER_NOT_SUPPORT_IN_PRESENT_STATE;
461 }
462 phosphor::logging::log<phosphor::logging::level::ERR>(
463 "Error unlock data",
464 phosphor::logging::entry("SERVICE=%s", service.c_str()),
465 phosphor::logging::entry("PATH=%s", MDRV2_PATH));
466 return IPMI_CC_UNSPECIFIED_ERROR;
467 }
468 reply.read(resStatus);
469
470 if (resStatus != "success")
471 {
472 phosphor::logging::log<phosphor::logging::level::ERR>(
473 "Agent unlock Invalid lock status.");
474 return IPMI_CC_UNSPECIFIED_ERROR;
475 }
476
477 return IPMI_CC_OK;
478}
479
480ipmi_ret_t cmd_mdr2_get_data_block(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
481 ipmi_request_t request,
482 ipmi_response_t response,
483 ipmi_data_len_t data_len,
484 ipmi_context_t context)
485{
486 auto requestData =
487 reinterpret_cast<const MDRiiGetDataBlockRequest*>(request);
488 auto responseData = reinterpret_cast<MDRiiGetDataBlockResponse*>(response);
489 std::tuple<uint8_t, uint32_t, uint32_t, std::vector<uint8_t>> res;
490 std::vector<uint8_t> resData;
491 uint8_t status = 1;
492
493 if (*data_len != sizeof(MDRiiGetDataBlockRequest))
494 {
495 *data_len = 0;
496 return IPMI_CC_REQ_DATA_LEN_INVALID;
497 }
498
499 *data_len = 0;
500
501 std::string service = ipmi::getService(bus, MDRV2_INTERFACE, MDRV2_PATH);
502
503 int agentIndex = agentLookup(requestData->agentId, service);
504 if (agentIndex == -1)
505 {
506 phosphor::logging::log<phosphor::logging::level::ERR>(
507 "Unknown agent id",
508 phosphor::logging::entry("ID=%x", requestData->agentId));
509 return IPMI_CC_PARM_OUT_OF_RANGE;
510 }
511
512 int idIndex = findLockHandle(requestData->lockHandle, service);
513
514 if ((idIndex < 0) || (idIndex >= maxDirEntries))
515 {
516 phosphor::logging::log<phosphor::logging::level::ERR>(
517 "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex));
518 return IPMI_CC_PARM_OUT_OF_RANGE;
519 }
520
521 sdbusplus::message::message method = bus.new_method_call(
522 service.c_str(), MDRV2_PATH, MDRV2_INTERFACE, "GetDataBlock");
523 method.append((uint8_t)idIndex, requestData->xferOffset,
524 requestData->xferLength);
525
526 sdbusplus::message::message reply = bus.call(method);
527 if (reply.is_method_error())
528 {
529 phosphor::logging::log<phosphor::logging::level::ERR>(
530 "Error get data block",
531 phosphor::logging::entry("SERVICE=%s", service.c_str()),
532 phosphor::logging::entry("PATH=%s", MDRV2_PATH));
533 return IPMI_CC_UNSPECIFIED_ERROR;
534 }
535 reply.read(res);
536
537 // Get the status of get data block, 0 means succeed
538 status = std::get<0>(res);
539 if (status == 1)
540 {
541 phosphor::logging::log<phosphor::logging::level::ERR>(
542 "Request data offset is outside of range.");
543 return IPMI_CC_CANNOT_RETURN_NUMBER_OF_REQUESTED_DATA_BYTES;
544 }
545 else if (status != 0)
546 {
547 phosphor::logging::log<phosphor::logging::level::ERR>(
548 "Get data block unexpected error.");
549 return IPMI_CC_UNSPECIFIED_ERROR;
550 }
551
552 responseData->xferLength = std::get<1>(res);
553 if (responseData->xferLength > requestData->xferLength)
554 {
555 phosphor::logging::log<phosphor::logging::level::ERR>(
556 "Get data block unexpected error.");
557 return IPMI_CC_UNSPECIFIED_ERROR;
558 }
559
560 responseData->checksum = std::get<2>(res);
561
562 resData = std::get<3>(res);
563
564 *data_len = sizeof(responseData->xferLength) +
565 sizeof(responseData->checksum) + resData.size();
566
567 if (*data_len > MAX_IPMI_BUFFER) // length + completion code should no more
568 // than MAX_IPMI_BUFFER
569 {
570 phosphor::logging::log<phosphor::logging::level::ERR>(
571 "Data length send from service is invalid");
572 *data_len = 0;
573 return IPMI_CC_RESPONSE_ERROR;
574 }
575
576 std::copy(resData.begin(), resData.end(), responseData->data);
577
578 return IPMI_CC_OK;
579}
580
581ipmi_ret_t cmd_mdr2_send_dir(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
582 ipmi_request_t request, ipmi_response_t response,
583 ipmi_data_len_t data_len, ipmi_context_t context)
584{
585 auto requestData = reinterpret_cast<const MDRiiSendDirRequest*>(request);
586 std::vector<uint8_t> idVector;
587 bool teminate = false;
588
589 if (*data_len != sizeof(MDRiiSendDirRequest))
590 {
591 *data_len = 0;
592 return IPMI_CC_REQ_DATA_LEN_INVALID;
593 }
594
595 *data_len = 0;
596
597 std::string service = ipmi::getService(bus, MDRV2_INTERFACE, MDRV2_PATH);
598
599 int agentIndex = agentLookup(requestData->agentId, service);
600 if (agentIndex == -1)
601 {
602 phosphor::logging::log<phosphor::logging::level::ERR>(
603 "Unknown agent id",
604 phosphor::logging::entry("ID=%x", requestData->agentId));
605 return IPMI_CC_PARM_OUT_OF_RANGE;
606 }
607
608 if ((requestData->dirIndex + requestData->returnedEntries) > maxDirEntries)
609 {
610 phosphor::logging::log<phosphor::logging::level::ERR>(
611 "Too many directory entries");
612 return IPMI_CC_STORGE_LEAK;
613 }
614
615 sdbusplus::message::message method = bus.new_method_call(
616 service.c_str(), MDRV2_PATH, MDRV2_INTERFACE, "SendDir");
617 method.append(requestData->dirVersion, requestData->dirIndex,
618 requestData->returnedEntries, requestData->remainingEntries);
619 uint8_t* reqPoint;
620 for (int index = 0; index < requestData->returnedEntries; index++)
621 {
622 reqPoint = (uint8_t*)&(requestData->data[index]);
623 std::copy(reqPoint, sizeof(Mdr2DirEntry) + reqPoint, idVector.data());
624 }
625 method.append(idVector);
626
627 sdbusplus::message::message reply = bus.call(method);
628 if (reply.is_method_error())
629 {
630 phosphor::logging::log<phosphor::logging::level::ERR>(
631 "Error send dir",
632 phosphor::logging::entry("SERVICE=%s", service.c_str()),
633 phosphor::logging::entry("PATH=%s", MDRV2_PATH));
634 return IPMI_CC_UNSPECIFIED_ERROR;
635 }
636 reply.read(teminate);
637
638 *data_len = 1;
639 if (teminate == false)
640 *(static_cast<uint8_t*>(response)) = 0;
641 else
642 *(static_cast<uint8_t*>(response)) = 1;
643 return IPMI_CC_OK;
644}
645
646ipmi_ret_t cmd_mdr2_data_info_offer(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
647 ipmi_request_t request,
648 ipmi_response_t response,
649 ipmi_data_len_t data_len,
650 ipmi_context_t context)
651{
652 auto requestData = reinterpret_cast<const MDRiiOfferDataInfo*>(request);
653 auto dataOut = reinterpret_cast<uint8_t*>(response);
654 std::vector<uint8_t> dataInfo;
655
656 if (*data_len != sizeof(MDRiiOfferDataInfo))
657 {
658 *data_len = 0;
659 return IPMI_CC_REQ_DATA_LEN_INVALID;
660 }
661
662 *data_len = 0;
663
664 std::string service = ipmi::getService(bus, MDRV2_INTERFACE, MDRV2_PATH);
665
666 int agentIndex = agentLookup(requestData->agentId, service);
667 if (agentIndex == -1)
668 {
669 phosphor::logging::log<phosphor::logging::level::ERR>(
670 "Unknown agent id",
671 phosphor::logging::entry("ID=%x", requestData->agentId));
672 return IPMI_CC_PARM_OUT_OF_RANGE;
673 }
674
675 sdbusplus::message::message method = bus.new_method_call(
676 service.c_str(), MDRV2_PATH, MDRV2_INTERFACE, "GetDataOffer");
677
678 sdbusplus::message::message reply = bus.call(method);
679 if (reply.is_method_error())
680 {
681 if (reply.get_errno() == EBUSY)
682 {
683 phosphor::logging::log<phosphor::logging::level::ERR>(
684 "Send data info offer failed - not available to update data "
685 "into agent at present");
686 return IPMI_CC_PARAMETER_NOT_SUPPORT_IN_PRESENT_STATE;
687 }
688 phosphor::logging::log<phosphor::logging::level::ERR>(
689 "Error send data info offer",
690 phosphor::logging::entry("SERVICE=%s", service.c_str()),
691 phosphor::logging::entry("PATH=%s", MDRV2_PATH));
692 return IPMI_CC_UNSPECIFIED_ERROR;
693 }
694 reply.read(dataInfo);
695 if (dataInfo.size() != sizeof(MDRiiOfferDataInfoResponse))
696 {
697 phosphor::logging::log<phosphor::logging::level::ERR>(
698 "Error send data info offer, return length invalid");
699 return IPMI_CC_UNSPECIFIED_ERROR;
700 }
701
702 *data_len = dataInfo.size();
703 std::copy(dataInfo.begin(), dataInfo.end(), dataOut);
704 return IPMI_CC_OK;
705}
706
707ipmi_ret_t cmd_mdr2_send_data_info(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
708 ipmi_request_t request,
709 ipmi_response_t response,
710 ipmi_data_len_t data_len,
711 ipmi_context_t context)
712{
713 auto requestData =
714 reinterpret_cast<const MDRiiSendDataInfoRequest*>(request);
715 bool entryChanged = true;
716
717 if (*data_len != sizeof(MDRiiSendDataInfoRequest))
718 {
719 *data_len = 0;
720 return IPMI_CC_REQ_DATA_LEN_INVALID;
721 }
722
723 *data_len = 0;
724
725 if (requestData->dataLength > smbiosTableStorageSize)
726 {
727 phosphor::logging::log<phosphor::logging::level::ERR>(
728 "Requested data length is out of SMBIOS Table storage size.");
729 return IPMI_CC_PARM_OUT_OF_RANGE;
730 }
731
732 std::string service = ipmi::getService(bus, MDRV2_INTERFACE, MDRV2_PATH);
733
734 int agentIndex = agentLookup(requestData->agentId, service);
735 if (agentIndex == -1)
736 {
737 phosphor::logging::log<phosphor::logging::level::ERR>(
738 "Unknown agent id",
739 phosphor::logging::entry("ID=%x", requestData->agentId));
740 return IPMI_CC_PARM_OUT_OF_RANGE;
741 }
742
743 int idIndex =
744 findDataId(requestData->dataSetInfo.dataInfo,
745 sizeof(requestData->dataSetInfo.dataInfo), service);
746
747 if ((idIndex < 0) || (idIndex >= maxDirEntries))
748 {
749 phosphor::logging::log<phosphor::logging::level::ERR>(
750 "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex));
751 return IPMI_CC_PARM_OUT_OF_RANGE;
752 }
753
754 sdbusplus::message::message method = bus.new_method_call(
755 service.c_str(), MDRV2_PATH, MDRV2_INTERFACE, "SendDataInfo");
756
757 method.append((uint8_t)idIndex, requestData->validFlag,
758 requestData->dataLength, requestData->dataVersion,
759 requestData->timeStamp);
760
761 sdbusplus::message::message reply = bus.call(method);
762 if (reply.is_method_error())
763 {
764 phosphor::logging::log<phosphor::logging::level::ERR>(
765 "Error send data info",
766 phosphor::logging::entry("SERVICE=%s", service.c_str()),
767 phosphor::logging::entry("PATH=%s", MDRV2_PATH));
768 return IPMI_CC_UNSPECIFIED_ERROR;
769 }
770 reply.read(entryChanged);
771
772 *data_len = 1;
773
774 if (entryChanged)
775 {
776 *(static_cast<uint8_t*>(response)) = 1;
777 }
778 else
779 {
780 *(static_cast<uint8_t*>(response)) = 0;
781 }
782
783 return IPMI_CC_OK;
784}
785
786ipmi_ret_t cmd_mdr2_data_start(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
787 ipmi_request_t request, ipmi_response_t response,
788 ipmi_data_len_t data_len, ipmi_context_t context)
789{
790 auto requestData = reinterpret_cast<const MDRiiDataStartRequest*>(request);
791 auto responseData = reinterpret_cast<MDRiiDataStartResponse*>(response);
792 std::vector<uint8_t> idVector;
793
794 if (*data_len != sizeof(MDRiiDataStartRequest))
795 {
796 *data_len = 0;
797 return IPMI_CC_REQ_DATA_LEN_INVALID;
798 }
799
800 *data_len = 0;
801
802 if (requestData->dataLength > smbiosTableStorageSize)
803 {
804 phosphor::logging::log<phosphor::logging::level::ERR>(
805 "Requested data length is out of SMBIOS Table storage size.");
806 return IPMI_CC_PARM_OUT_OF_RANGE;
807 }
808
809 if ((requestData->xferLength + requestData->xferAddress) > mdriiSMSize)
810 {
811 phosphor::logging::log<phosphor::logging::level::ERR>(
812 "Invalid data address and size");
813 return IPMI_CC_PARM_OUT_OF_RANGE;
814 }
815
816 std::string service = ipmi::getService(bus, MDRV2_INTERFACE, MDRV2_PATH);
817
818 int agentIndex = agentLookup(requestData->agentId, service);
819 if (agentIndex == -1)
820 {
821 phosphor::logging::log<phosphor::logging::level::ERR>(
822 "Unknown agent id",
823 phosphor::logging::entry("ID=%x", requestData->agentId));
824 return IPMI_CC_PARM_OUT_OF_RANGE;
825 }
826
827 int idIndex =
828 findDataId(requestData->dataSetInfo.dataInfo,
829 sizeof(requestData->dataSetInfo.dataInfo), service);
830
831 if ((idIndex < 0) || (idIndex >= maxDirEntries))
832 {
833 phosphor::logging::log<phosphor::logging::level::ERR>(
834 "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex));
835 return IPMI_CC_PARM_OUT_OF_RANGE;
836 }
837
838 sdbusplus::message::message method = bus.new_method_call(
839 service.c_str(), MDRV2_PATH, MDRV2_INTERFACE, "DataStart");
840
841 for (uint8_t infoIndex = 0; infoIndex < sizeof(DataIdStruct); infoIndex++)
842 {
843 idVector.push_back(requestData->dataSetInfo.dataInfo[infoIndex]);
844 }
845 method.append((uint8_t)idIndex, idVector, requestData->dataLength,
846 requestData->xferAddress, requestData->xferLength,
847 requestData->timeout);
848
849 sdbusplus::message::message reply = bus.call(method);
850 if (reply.is_method_error())
851 {
852 int errNumber = reply.get_errno();
853 if (errNumber == ENOMEM)
854 {
855 phosphor::logging::log<phosphor::logging::level::ERR>(
856 "Send data start failed - cannot map share memory");
857 return IPMI_CC_UNSPECIFIED_ERROR;
858 }
859 else if (errNumber == EINVAL)
860 {
861 phosphor::logging::log<phosphor::logging::level::ERR>(
862 "Invalid data address and size");
863 return IPMI_CC_PARM_OUT_OF_RANGE;
864 }
865 else
866 {
867 phosphor::logging::log<phosphor::logging::level::ERR>(
868 "Error Send Data Start",
869 phosphor::logging::entry("SERVICE=%s", service.c_str()),
870 phosphor::logging::entry("PATH=%s", MDRV2_PATH));
871 return IPMI_CC_UNSPECIFIED_ERROR;
872 }
873 }
874 uint8_t xferStartAck = 0;
875 uint16_t sessionHandle = 0;
876 reply.read(xferStartAck, sessionHandle);
877 responseData->sessionHandle = sessionHandle;
878 responseData->xferStartAck = xferStartAck;
879 if (responseData->xferStartAck == 0)
880 {
881 phosphor::logging::log<phosphor::logging::level::ERR>(
882 "Send data start unexpected error");
883 return IPMI_CC_UNSPECIFIED_ERROR;
884 }
885
886 *data_len = sizeof(MDRiiDataStartResponse);
887 return IPMI_CC_OK;
888}
889
890ipmi_ret_t cmd_mdr2_data_done(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
891 ipmi_request_t request, ipmi_response_t response,
892 ipmi_data_len_t data_len, ipmi_context_t context)
893{
894 auto requestData = reinterpret_cast<const MDRiiDataDoneRequest*>(request);
895 std::string resStatus;
896
897 if (*data_len != sizeof(MDRiiDataDoneRequest))
898 {
899 *data_len = 0;
900 return IPMI_CC_REQ_DATA_LEN_INVALID;
901 }
902
903 *data_len = 0;
904
905 std::string service = ipmi::getService(bus, MDRV2_INTERFACE, MDRV2_PATH);
906
907 int agentIndex = agentLookup(requestData->agentId, service);
908 if (agentIndex == -1)
909 {
910 phosphor::logging::log<phosphor::logging::level::ERR>(
911 "Unknown agent id",
912 phosphor::logging::entry("ID=%x", requestData->agentId));
913 return IPMI_CC_PARM_OUT_OF_RANGE;
914 }
915
916 int idIndex = findLockHandle(requestData->lockHandle, service);
917
918 if ((idIndex < 0) || (idIndex >= maxDirEntries))
919 {
920 phosphor::logging::log<phosphor::logging::level::ERR>(
921 "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex));
922 return IPMI_CC_PARM_OUT_OF_RANGE;
923 }
924
925 sdbusplus::message::message method = bus.new_method_call(
926 service.c_str(), MDRV2_PATH, MDRV2_INTERFACE, "DataDone");
927 method.append((uint8_t)idIndex);
928
929 sdbusplus::message::message reply = bus.call(method);
930 if (reply.is_method_error())
931 {
932 if (reply.get_errno() == EBUSY)
933 {
934 phosphor::logging::log<phosphor::logging::level::ERR>(
935 "Send data done failed - cannot unlock idIndex");
936 return IPMI_CC_DESTINATION_UNAVAILABLE;
937 }
938 phosphor::logging::log<phosphor::logging::level::ERR>(
939 "Error Send Data done",
940 phosphor::logging::entry("SERVICE=%s", service.c_str()),
941 phosphor::logging::entry("PATH=%s", MDRV2_PATH));
942 return IPMI_CC_UNSPECIFIED_ERROR;
943 }
944 reply.read(resStatus);
945
946 if (resStatus != "success")
947 {
948 phosphor::logging::log<phosphor::logging::level::ERR>(
949 "Data done failure.");
950 return IPMI_CC_DESTINATION_UNAVAILABLE;
951 }
952
953 return IPMI_CC_OK;
954}
955
956ipmi_ret_t cmd_mdr2_send_data_block(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
957 ipmi_request_t request,
958 ipmi_response_t response,
959 ipmi_data_len_t data_len,
960 ipmi_context_t context)
961{
962 auto requestData =
963 reinterpret_cast<const MDRiiSendDataBlockRequest*>(request);
964 std::string resStatus;
965
966 if (*data_len != sizeof(MDRiiSendDataBlockRequest))
967 {
968 *data_len = 0;
969 return IPMI_CC_REQ_DATA_LEN_INVALID;
970 }
971
972 *data_len = 0;
973
974 std::string service = ipmi::getService(bus, MDRV2_INTERFACE, MDRV2_PATH);
975
976 int agentIndex = agentLookup(requestData->agentId, service);
977 if (agentIndex == -1)
978 {
979 phosphor::logging::log<phosphor::logging::level::ERR>(
980 "Unknown agent id",
981 phosphor::logging::entry("ID=%x", requestData->agentId));
982 return IPMI_CC_PARM_OUT_OF_RANGE;
983 }
984
985 int idIndex = findLockHandle(requestData->lockHandle, service);
986
987 if ((idIndex < 0) || (idIndex >= maxDirEntries))
988 {
989 phosphor::logging::log<phosphor::logging::level::ERR>(
990 "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex));
991 return IPMI_CC_PARM_OUT_OF_RANGE;
992 }
993
994 sdbusplus::message::message method = bus.new_method_call(
995 service.c_str(), MDRV2_PATH, MDRV2_INTERFACE, "SendDataBlock");
996 method.append((uint8_t)idIndex, requestData->xferOffset,
997 requestData->xferLength, requestData->checksum);
998
999 sdbusplus::message::message reply = bus.call(method);
1000 if (reply.is_method_error())
1001 {
1002 int errNumber = reply.get_errno();
1003 if (errNumber == EINVAL)
1004 {
1005 phosphor::logging::log<phosphor::logging::level::ERR>(
1006 "Send data block Invalid checksum");
1007 return IPMI_CC_OEM_INVALID_CHECKSUM;
1008 }
1009 else if (errNumber == ENOBUFS)
1010 {
1011 phosphor::logging::log<phosphor::logging::level::ERR>(
1012 "Send data block Invalid offset/length");
1013 return IPMI_CC_REQUEST_DATA_FIELD_LENGTH_LIMIT_EXCEEDED;
1014 }
1015 else if (errNumber == EBUSY)
1016 {
1017 phosphor::logging::log<phosphor::logging::level::ERR>(
1018 "Send data block failed, other data is updating");
1019 return IPMI_CC_DESTINATION_UNAVAILABLE;
1020 }
1021 else
1022 {
1023 phosphor::logging::log<phosphor::logging::level::ERR>(
1024 "Error Send data block",
1025 phosphor::logging::entry("SERVICE=%s", service.c_str()),
1026 phosphor::logging::entry("PATH=%s", MDRV2_PATH));
1027 return IPMI_CC_UNSPECIFIED_ERROR;
1028 }
1029 }
1030 reply.read(resStatus);
1031
1032 if (resStatus != "success")
1033 {
1034 phosphor::logging::log<phosphor::logging::level::ERR>(
1035 "send data block failure.");
1036 return IPMI_CC_DESTINATION_UNAVAILABLE;
1037 }
1038
1039 return IPMI_CC_OK;
1040}
1041
1042static void register_netfn_smbiosmdrv2_functions(void)
1043{
1044 // MDR V2 Command
1045 // <Get MDRII Status Command>
1046 ipmi_register_callback(NETFUN_INTEL_APP_OEM,
1047 IPMI_NETFN_INTEL_OEM_APP_CMD::MDRII_AGENT_STATUS,
1048 NULL, cmd_mdr2_agent_status, PRIVILEGE_OPERATOR);
1049
1050 // <Get MDRII Directory Command>
1051 ipmi_register_callback(NETFUN_INTEL_APP_OEM,
1052 IPMI_NETFN_INTEL_OEM_APP_CMD::MDRII_GET_DIR, NULL,
1053 cmd_mdr2_get_dir, PRIVILEGE_OPERATOR);
1054
1055 // <Get MDRII Data Info Command>
1056 ipmi_register_callback(NETFUN_INTEL_APP_OEM,
1057 IPMI_NETFN_INTEL_OEM_APP_CMD::MDRII_GET_DATA_INFO,
1058 NULL, cmd_mdr2_get_data_info, PRIVILEGE_OPERATOR);
1059
1060 // <Lock MDRII Data Command>
1061 ipmi_register_callback(NETFUN_INTEL_APP_OEM,
1062 IPMI_NETFN_INTEL_OEM_APP_CMD::MDRII_LOCK_DATA, NULL,
1063 cmd_mdr2_lock_data, PRIVILEGE_OPERATOR);
1064
1065 // <Unlock MDRII Data Command>
1066 ipmi_register_callback(NETFUN_INTEL_APP_OEM,
1067 IPMI_NETFN_INTEL_OEM_APP_CMD::MDRII_UNLOCK_DATA,
1068 NULL, cmd_mdr2_unlock_data, PRIVILEGE_OPERATOR);
1069
1070 // <Get MDRII Data Block Command>
1071 ipmi_register_callback(NETFUN_INTEL_APP_OEM,
1072 IPMI_NETFN_INTEL_OEM_APP_CMD::MDRII_GET_DATA_BLOCK,
1073 NULL, cmd_mdr2_get_data_block, PRIVILEGE_OPERATOR);
1074
1075 // <Send MDRII Directory Command>
1076 ipmi_register_callback(NETFUN_INTEL_APP_OEM,
1077 IPMI_NETFN_INTEL_OEM_APP_CMD::MDRII_SEND_DIR, NULL,
1078 cmd_mdr2_send_dir, PRIVILEGE_OPERATOR);
1079
1080 // <Send MDRII Info Offer>
1081 ipmi_register_callback(
1082 NETFUN_INTEL_APP_OEM,
1083 IPMI_NETFN_INTEL_OEM_APP_CMD::MDRII_SEND_DATA_INFO_OFFER, NULL,
1084 cmd_mdr2_data_info_offer, PRIVILEGE_OPERATOR);
1085
1086 // <Send MDRII Data Info>
1087 ipmi_register_callback(NETFUN_INTEL_APP_OEM,
1088 IPMI_NETFN_INTEL_OEM_APP_CMD::MDRII_SEND_DATA_INFO,
1089 NULL, cmd_mdr2_send_data_info, PRIVILEGE_OPERATOR);
1090
1091 // <Send MDRII Data Start>
1092 ipmi_register_callback(NETFUN_INTEL_APP_OEM,
1093 IPMI_NETFN_INTEL_OEM_APP_CMD::MDRII_DATA_START, NULL,
1094 cmd_mdr2_data_start, PRIVILEGE_OPERATOR);
1095
1096 // <Send MDRII Data Done>
1097 ipmi_register_callback(NETFUN_INTEL_APP_OEM,
1098 IPMI_NETFN_INTEL_OEM_APP_CMD::MDRII_DATA_DONE, NULL,
1099 cmd_mdr2_data_done, PRIVILEGE_OPERATOR);
1100
1101 // <Send MDRII Data Block>
1102 ipmi_register_callback(NETFUN_INTEL_APP_OEM,
1103 IPMI_NETFN_INTEL_OEM_APP_CMD::MDRII_SEND_DATA_BLOCK,
1104 NULL, cmd_mdr2_send_data_block, PRIVILEGE_OPERATOR);
1105}