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