blob: c3d5f915d68781f528248cb5ed3c202afbc9c5a0 [file] [log] [blame]
Vernon Mauerye7329c72018-10-08 12:05:16 -07001/**
2 * Copyright © 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
Vernon Mauery03d7a4b2021-01-19 11:22:17 -080017#include <cxxabi.h>
18
Vernon Mauerye7329c72018-10-08 12:05:16 -070019#include <boost/asio/spawn.hpp>
20#include <boost/callable_traits.hpp>
Vernon Mauerye08fbff2019-04-03 09:19:34 -070021#include <ipmid/api-types.hpp>
Vernon Mauerye7329c72018-10-08 12:05:16 -070022#include <ipmid/message.hpp>
George Liub4b40912024-07-17 16:14:17 +080023#include <phosphor-logging/lg2.hpp>
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -050024#include <phosphor-logging/log.hpp>
25#include <user_channel/channel_layer.hpp>
26
27#include <algorithm>
28#include <cstdint>
29#include <exception>
Vernon Mauerye7329c72018-10-08 12:05:16 -070030#include <memory>
31#include <optional>
William A. Kennington III687e9b02021-01-08 10:37:09 -080032#include <stdexcept>
Vernon Mauerye7329c72018-10-08 12:05:16 -070033#include <tuple>
Vernon Mauerye7329c72018-10-08 12:05:16 -070034#include <utility>
35
36#ifdef ALLOW_DEPRECATED_API
37#include <ipmid/api.h>
38
39#include <ipmid/oemrouter.hpp>
40#endif /* ALLOW_DEPRECATED_API */
41
42namespace ipmi
43{
44
45template <typename... Args>
Patrick Williams69b4c282025-03-03 11:19:13 -050046static inline message::Response::ptr errorResponse(
47 message::Request::ptr request, ipmi::Cc cc, Args&&... args)
Vernon Mauerye7329c72018-10-08 12:05:16 -070048{
49 message::Response::ptr response = request->makeResponse();
Vernon Mauerybfe55a12019-03-08 13:48:40 -080050 response->cc = cc;
51 response->pack(args...);
Vernon Mauerye7329c72018-10-08 12:05:16 -070052 return response;
53}
Patrick Williams69b4c282025-03-03 11:19:13 -050054static inline message::Response::ptr errorResponse(
55 message::Request::ptr request, ipmi::Cc cc)
Vernon Mauerye7329c72018-10-08 12:05:16 -070056{
57 message::Response::ptr response = request->makeResponse();
Vernon Mauerybfe55a12019-03-08 13:48:40 -080058 response->cc = cc;
Vernon Mauerye7329c72018-10-08 12:05:16 -070059 return response;
60}
61
William A. Kennington III687e9b02021-01-08 10:37:09 -080062/** @brief Exception extension that allows setting an IPMI return code */
63class HandlerCompletion
64{
65 public:
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -050066 HandlerCompletion(Cc cc) noexcept : cc(cc) {}
William A. Kennington III687e9b02021-01-08 10:37:09 -080067
68 Cc code() const noexcept
69 {
70 return cc;
71 }
72
73 private:
74 Cc cc;
75};
76
77/** @brief Exception extension that allows setting an IPMI return code and
78 * printing out a logged error */
79class HandlerException : public HandlerCompletion, public std::runtime_error
80{
81 public:
82 HandlerException(Cc cc, const char* what) :
83 HandlerCompletion(cc), std::runtime_error(what)
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -050084 {}
William A. Kennington III687e9b02021-01-08 10:37:09 -080085 HandlerException(Cc cc, const std::string& what) :
86 HandlerException(cc, what.c_str())
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -050087 {}
William A. Kennington III687e9b02021-01-08 10:37:09 -080088};
89
Vernon Mauery03d7a4b2021-01-19 11:22:17 -080090static inline const char* currentExceptionType()
91{
92 int status;
Jayanth Othayotha6fb32d2024-12-15 10:55:22 -060093 return abi::__cxa_demangle(abi::__cxa_current_exception_type()->name(),
94 nullptr, nullptr, &status);
Vernon Mauery03d7a4b2021-01-19 11:22:17 -080095}
96
Vernon Mauerye7329c72018-10-08 12:05:16 -070097/**
98 * @brief Handler base class for dealing with IPMI request/response
99 *
100 * The subclasses are all templated so they can provide access to any type
101 * of command callback functions.
102 */
103class HandlerBase
104{
105 public:
106 using ptr = std::shared_ptr<HandlerBase>;
107
Patrick Williams7d7a6852022-07-25 09:53:19 -0500108 virtual ~HandlerBase() = default;
109
Vernon Mauerye7329c72018-10-08 12:05:16 -0700110 /** @brief wrap the call to the registered handler with the request
111 *
112 * This is called from the running queue context after it has already
113 * created a request object that contains all the information required to
114 * execute the ipmi command. This function will return the response object
115 * pointer that owns the response object that will ultimately get sent back
116 * to the requester.
117 *
118 * This is a non-virtual function wrapper to the virtualized executeCallback
119 * function that actually does the work. This is required because of how
120 * templates and virtualization work together.
121 *
122 * @param request a shared_ptr to a Request object
123 *
124 * @return a shared_ptr to a Response object
125 */
126 message::Response::ptr call(message::Request::ptr request)
127 {
128 return executeCallback(request);
129 }
130
131 private:
132 /** @brief call the registered handler with the request
133 *
134 * This is called from the running queue context after it has already
135 * created a request object that contains all the information required to
136 * execute the ipmi command. This function will return the response object
137 * pointer that owns the response object that will ultimately get sent back
138 * to the requester.
139 *
140 * @param request a shared_ptr to a Request object
141 *
142 * @return a shared_ptr to a Response object
143 */
Patrick Williams69b4c282025-03-03 11:19:13 -0500144 virtual message::Response::ptr executeCallback(
145 message::Request::ptr request) = 0;
Vernon Mauerye7329c72018-10-08 12:05:16 -0700146};
147
148/**
149 * @brief Main IPMI handler class
150 *
151 * New IPMI handlers will resolve into this class, which will read the signature
152 * of the registering function, attempt to extract the appropriate arguments
153 * from a request, pass the arguments to the function, and then pack the
154 * response of the function back into an IPMI response.
155 */
156template <typename Handler>
157class IpmiHandler final : public HandlerBase
158{
159 public:
160 explicit IpmiHandler(Handler&& handler) :
161 handler_(std::forward<Handler>(handler))
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500162 {}
Vernon Mauerye7329c72018-10-08 12:05:16 -0700163
164 private:
165 Handler handler_;
166
167 /** @brief call the registered handler with the request
168 *
169 * This is called from the running queue context after it has already
170 * created a request object that contains all the information required to
171 * execute the ipmi command. This function will return the response object
172 * pointer that owns the response object that will ultimately get sent back
173 * to the requester.
174 *
175 * Because this is the new variety of IPMI handler, this is the function
176 * that attempts to extract the requested parameters in order to pass them
177 * onto the callback function and then packages up the response into a plain
178 * old vector to pass back to the caller.
179 *
180 * @param request a shared_ptr to a Request object
181 *
182 * @return a shared_ptr to a Response object
183 */
Patrick Williams69b4c282025-03-03 11:19:13 -0500184 message::Response::ptr executeCallback(
185 message::Request::ptr request) override
Vernon Mauerye7329c72018-10-08 12:05:16 -0700186 {
187 message::Response::ptr response = request->makeResponse();
188
189 using CallbackSig = boost::callable_traits::args_t<Handler>;
190 using InputArgsType = typename utility::DecayTuple<CallbackSig>::type;
191 using UnpackArgsType = typename utility::StripFirstArgs<
192 utility::NonIpmiArgsCount<InputArgsType>::size(),
193 InputArgsType>::type;
194 using ResultType = boost::callable_traits::return_type_t<Handler>;
195
Vernon Maueryed6f4602023-08-25 16:44:06 -0700196 UnpackArgsType unpackArgs{};
William A. Kennington III51694c22019-04-24 01:44:44 -0700197 request->payload.trailingOk = false;
Vernon Mauerye7329c72018-10-08 12:05:16 -0700198 ipmi::Cc unpackError = request->unpack(unpackArgs);
199 if (unpackError != ipmi::ccSuccess)
200 {
201 response->cc = unpackError;
202 return response;
203 }
204 /* callbacks can contain an optional first argument of one of:
205 * 1) boost::asio::yield_context
206 * 2) ipmi::Context::ptr
207 * 3) ipmi::message::Request::ptr
208 *
209 * If any of those is part of the callback signature as the first
210 * argument, it will automatically get packed into the parameter pack
211 * here.
212 *
213 * One more special optional argument is an ipmi::message::Payload.
214 * This argument can be in any position, though logically it makes the
215 * most sense if it is the last. If this class is included in the
216 * handler signature, it will allow for the handler to unpack optional
217 * parameters. For example, the Set LAN Configuration Parameters
218 * command takes variable length (and type) values for each of the LAN
219 * parameters. This means that the only fixed data is the channel and
220 * parameter selector. All the remaining data can be extracted using
221 * the Payload class and the unpack API available to the Payload class.
222 */
Vernon Mauerye7329c72018-10-08 12:05:16 -0700223 ResultType result;
224 try
225 {
William A. Kennington IIIf2fd17a2019-04-24 01:53:52 -0700226 std::optional<InputArgsType> inputArgs;
227 if constexpr (std::tuple_size<InputArgsType>::value > 0)
228 {
229 if constexpr (std::is_same<
230 std::tuple_element_t<0, InputArgsType>,
231 boost::asio::yield_context>::value)
232 {
233 inputArgs.emplace(std::tuple_cat(
James Feistcb09aa02019-09-06 13:41:59 -0700234 std::forward_as_tuple(request->ctx->yield),
William A. Kennington IIIf2fd17a2019-04-24 01:53:52 -0700235 std::move(unpackArgs)));
236 }
237 else if constexpr (std::is_same<
238 std::tuple_element_t<0, InputArgsType>,
239 ipmi::Context::ptr>::value)
240 {
241 inputArgs.emplace(
242 std::tuple_cat(std::forward_as_tuple(request->ctx),
243 std::move(unpackArgs)));
244 }
245 else if constexpr (std::is_same<
246 std::tuple_element_t<0, InputArgsType>,
247 ipmi::message::Request::ptr>::value)
248 {
249 inputArgs.emplace(std::tuple_cat(
250 std::forward_as_tuple(request), std::move(unpackArgs)));
251 }
252 else
253 {
254 // no special parameters were requested (but others were)
255 inputArgs.emplace(std::move(unpackArgs));
256 }
257 }
258 else
259 {
260 // no parameters were requested
261 inputArgs = std::move(unpackArgs);
262 }
263
Vernon Mauerye7329c72018-10-08 12:05:16 -0700264 // execute the registered callback function and get the
265 // ipmi::RspType<>
266 result = std::apply(handler_, *inputArgs);
267 }
William A. Kennington III687e9b02021-01-08 10:37:09 -0800268 catch (const HandlerException& e)
269 {
George Liub4b40912024-07-17 16:14:17 +0800270 lg2::info("Handler produced exception, NetFn: {NETFN}, "
271 "Cmd: {CMD}: {ERROR}",
272 "NETFN", lg2::hex, request->ctx->netFn, "CMD", lg2::hex,
273 request->ctx->cmd, "ERROR", e);
William A. Kennington III687e9b02021-01-08 10:37:09 -0800274 return errorResponse(request, e.code());
275 }
Vernon Mauerye7329c72018-10-08 12:05:16 -0700276 catch (const std::exception& e)
277 {
George Liub4b40912024-07-17 16:14:17 +0800278 lg2::error("Handler failed to catch exception, NetFn: {NETFN}, "
279 "Cmd: {CMD}: {ERROR}",
280 "NETFN", lg2::hex, request->ctx->netFn, "CMD", lg2::hex,
281 request->ctx->cmd, "ERROR", e);
Vernon Mauerye7329c72018-10-08 12:05:16 -0700282 return errorResponse(request, ccUnspecifiedError);
283 }
William A. Kennington III687e9b02021-01-08 10:37:09 -0800284 catch (const HandlerCompletion& c)
285 {
286 return errorResponse(request, c.code());
287 }
Vernon Mauerye7329c72018-10-08 12:05:16 -0700288 catch (...)
289 {
Vernon Mauery03d7a4b2021-01-19 11:22:17 -0800290 const char* what = currentExceptionType();
George Liub4b40912024-07-17 16:14:17 +0800291 lg2::error("Handler failed to catch exception, NetFn: {NETFN}, "
292 "Cmd: {CMD}: {ERROR}",
293 "NETFN", lg2::hex, request->ctx->netFn, "CMD", lg2::hex,
294 request->ctx->cmd, "ERROR", what);
Vernon Mauery03d7a4b2021-01-19 11:22:17 -0800295 return errorResponse(request, ccUnspecifiedError);
Vernon Mauerye7329c72018-10-08 12:05:16 -0700296 }
297
298 response->cc = std::get<0>(result);
299 auto payload = std::get<1>(result);
300 // check for optional payload
301 if (payload)
302 {
303 response->pack(*payload);
304 }
305 return response;
306 }
307};
308
309#ifdef ALLOW_DEPRECATED_API
Vernon Mauery48408b62019-08-22 14:41:50 -0700310static constexpr size_t maxLegacyBufferSize = 64 * 1024;
Vernon Mauerye7329c72018-10-08 12:05:16 -0700311/**
312 * @brief Legacy IPMI handler class
313 *
314 * Legacy IPMI handlers will resolve into this class, which will behave the same
315 * way as the legacy IPMI queue, passing in a big buffer for the request and a
316 * big buffer for the response.
317 *
318 * As soon as all the handlers have been rewritten, this class will be marked as
319 * deprecated and eventually removed.
320 */
321template <>
322class IpmiHandler<ipmid_callback_t> final : public HandlerBase
323{
324 public:
Vernon Mauerybe376302019-03-21 13:02:05 -0700325 explicit IpmiHandler(const ipmid_callback_t& handler, void* ctx = nullptr) :
326 handler_(handler), handlerCtx(ctx)
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500327 {}
Vernon Mauerye7329c72018-10-08 12:05:16 -0700328
329 private:
330 ipmid_callback_t handler_;
Vernon Mauerybe376302019-03-21 13:02:05 -0700331 void* handlerCtx;
Vernon Mauerye7329c72018-10-08 12:05:16 -0700332
333 /** @brief call the registered handler with the request
334 *
335 * This is called from the running queue context after it has already
336 * created a request object that contains all the information required to
337 * execute the ipmi command. This function will return the response object
338 * pointer that owns the response object that will ultimately get sent back
339 * to the requester.
340 *
341 * Because this is the legacy variety of IPMI handler, this function does
342 * not really have to do much other than pass the payload to the callback
343 * and return response to the caller.
344 *
345 * @param request a shared_ptr to a Request object
346 *
347 * @return a shared_ptr to a Response object
348 */
Patrick Williams69b4c282025-03-03 11:19:13 -0500349 message::Response::ptr executeCallback(
350 message::Request::ptr request) override
Vernon Mauerye7329c72018-10-08 12:05:16 -0700351 {
352 message::Response::ptr response = request->makeResponse();
Vernon Mauerye7329c72018-10-08 12:05:16 -0700353 // allocate a big response buffer here
Vernon Mauery48408b62019-08-22 14:41:50 -0700354 response->payload.resize(maxLegacyBufferSize);
Vernon Mauerye7329c72018-10-08 12:05:16 -0700355
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700356 size_t len = request->payload.size() - request->payload.rawIndex;
Vernon Mauerye7329c72018-10-08 12:05:16 -0700357 Cc ccRet{ccSuccess};
358 try
359 {
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700360 ccRet =
361 handler_(request->ctx->netFn, request->ctx->cmd,
362 request->payload.data() + request->payload.rawIndex,
363 response->payload.data(), &len, handlerCtx);
Vernon Mauerye7329c72018-10-08 12:05:16 -0700364 }
William A. Kennington III687e9b02021-01-08 10:37:09 -0800365 catch (const HandlerException& e)
366 {
George Liub4b40912024-07-17 16:14:17 +0800367 lg2::info("Legacy Handler produced exception, NetFn: {NETFN}, "
368 "Cmd: {CMD}: {ERROR}",
369 "NETFN", lg2::hex, request->ctx->netFn, "CMD", lg2::hex,
370 request->ctx->cmd, "ERROR", e);
William A. Kennington III687e9b02021-01-08 10:37:09 -0800371 return errorResponse(request, e.code());
372 }
Vernon Mauerye7329c72018-10-08 12:05:16 -0700373 catch (const std::exception& e)
374 {
George Liub4b40912024-07-17 16:14:17 +0800375 lg2::error("Legacy Handler failed to catch exception, "
376 "NetFn: {NETFN}, Cmd: {CMD}: {ERROR}",
377 "NETFN", lg2::hex, request->ctx->netFn, "CMD", lg2::hex,
378 request->ctx->cmd, "ERROR", e);
Vernon Mauerye7329c72018-10-08 12:05:16 -0700379 return errorResponse(request, ccUnspecifiedError);
380 }
William A. Kennington III687e9b02021-01-08 10:37:09 -0800381 catch (const HandlerCompletion& c)
382 {
383 return errorResponse(request, c.code());
384 }
Vernon Mauerye7329c72018-10-08 12:05:16 -0700385 catch (...)
386 {
Vernon Mauery03d7a4b2021-01-19 11:22:17 -0800387 const char* what = currentExceptionType();
George Liub4b40912024-07-17 16:14:17 +0800388 lg2::error("Handler failed to catch exception, NetFn: {NETFN}, "
389 "Cmd: {CMD}: {ERROR}",
390 "NETFN", lg2::hex, request->ctx->netFn, "CMD", lg2::hex,
391 request->ctx->cmd, "ERROR", what);
Vernon Mauery03d7a4b2021-01-19 11:22:17 -0800392 return errorResponse(request, ccUnspecifiedError);
Vernon Mauerye7329c72018-10-08 12:05:16 -0700393 }
394 response->cc = ccRet;
395 response->payload.resize(len);
396 return response;
397 }
398};
399
400/**
Vernon Maueryf984a012018-10-08 12:05:18 -0700401 * @brief Legacy IPMI OEM handler class
402 *
403 * Legacy IPMI OEM handlers will resolve into this class, which will behave the
404 * same way as the legacy IPMI queue, passing in a big buffer for the request
405 * and a big buffer for the response.
406 *
407 * As soon as all the handlers have been rewritten, this class will be marked as
408 * deprecated and eventually removed.
409 */
410template <>
411class IpmiHandler<oem::Handler> final : public HandlerBase
412{
413 public:
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500414 explicit IpmiHandler(const oem::Handler& handler) : handler_(handler) {}
Vernon Maueryf984a012018-10-08 12:05:18 -0700415
416 private:
417 oem::Handler handler_;
418
419 /** @brief call the registered handler with the request
420 *
421 * This is called from the running queue context after it has already
422 * created a request object that contains all the information required to
423 * execute the ipmi command. This function will return the response object
424 * pointer that owns the response object that will ultimately get sent back
425 * to the requester.
426 *
427 * Because this is the legacy variety of IPMI handler, this function does
428 * not really have to do much other than pass the payload to the callback
429 * and return response to the caller.
430 *
431 * @param request a shared_ptr to a Request object
432 *
433 * @return a shared_ptr to a Response object
434 */
Patrick Williams69b4c282025-03-03 11:19:13 -0500435 message::Response::ptr executeCallback(
436 message::Request::ptr request) override
Vernon Maueryf984a012018-10-08 12:05:18 -0700437 {
438 message::Response::ptr response = request->makeResponse();
Vernon Maueryf984a012018-10-08 12:05:18 -0700439 // allocate a big response buffer here
Vernon Mauery48408b62019-08-22 14:41:50 -0700440 response->payload.resize(maxLegacyBufferSize);
Vernon Maueryf984a012018-10-08 12:05:18 -0700441
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700442 size_t len = request->payload.size() - request->payload.rawIndex;
Vernon Maueryf984a012018-10-08 12:05:18 -0700443 Cc ccRet{ccSuccess};
444 try
445 {
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700446 ccRet =
447 handler_(request->ctx->cmd,
448 request->payload.data() + request->payload.rawIndex,
449 response->payload.data(), &len);
Vernon Maueryf984a012018-10-08 12:05:18 -0700450 }
William A. Kennington III687e9b02021-01-08 10:37:09 -0800451 catch (const HandlerException& e)
452 {
George Liub4b40912024-07-17 16:14:17 +0800453 lg2::info("Legacy OEM Handler produced exception, NetFn: {NETFN}, "
454 "Cmd: {CMD}: {ERROR}",
455 "NETFN", lg2::hex, request->ctx->netFn, "CMD", lg2::hex,
456 request->ctx->cmd, "ERROR", e);
William A. Kennington III687e9b02021-01-08 10:37:09 -0800457 return errorResponse(request, e.code());
458 }
Vernon Maueryf984a012018-10-08 12:05:18 -0700459 catch (const std::exception& e)
460 {
George Liub4b40912024-07-17 16:14:17 +0800461 lg2::error("Legacy OEM Handler failed to catch exception, "
462 "NetFn: {NETFN}, Cmd: {CMD}: {ERROR}",
463 "NETFN", lg2::hex, request->ctx->netFn, "CMD", lg2::hex,
464 request->ctx->cmd, "ERROR", e);
Vernon Maueryf984a012018-10-08 12:05:18 -0700465 return errorResponse(request, ccUnspecifiedError);
466 }
William A. Kennington III687e9b02021-01-08 10:37:09 -0800467 catch (const HandlerCompletion& c)
468 {
469 return errorResponse(request, c.code());
470 }
Vernon Maueryf984a012018-10-08 12:05:18 -0700471 catch (...)
472 {
Vernon Mauery03d7a4b2021-01-19 11:22:17 -0800473 const char* what = currentExceptionType();
George Liub4b40912024-07-17 16:14:17 +0800474 lg2::error("Legacy failed to catch exception, NetFn: {NETFN}, "
475 "Cmd: {CMD}: {ERROR}",
476 "NETFN", lg2::hex, request->ctx->netFn, "CMD", lg2::hex,
477 request->ctx->cmd, "ERROR", what);
Vernon Mauery03d7a4b2021-01-19 11:22:17 -0800478 return errorResponse(request, ccUnspecifiedError);
Vernon Maueryf984a012018-10-08 12:05:18 -0700479 }
480 response->cc = ccRet;
481 response->payload.resize(len);
482 return response;
483 }
484};
485
486/**
Vernon Mauerye7329c72018-10-08 12:05:16 -0700487 * @brief create a legacy IPMI handler class and return a shared_ptr
488 *
489 * The queue uses a map of pointers to do the lookup. This function returns the
490 * shared_ptr that owns the Handler object.
491 *
492 * This is called internally via the ipmi_register_callback function.
493 *
494 * @param handler the function pointer to the callback
495 *
496 * @return A shared_ptr to the created handler object
497 */
Vernon Mauerybe376302019-03-21 13:02:05 -0700498inline auto makeLegacyHandler(const ipmid_callback_t& handler,
499 void* ctx = nullptr)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700500{
Vernon Mauerybe376302019-03-21 13:02:05 -0700501 HandlerBase::ptr ptr(new IpmiHandler<ipmid_callback_t>(handler, ctx));
Vernon Mauerye7329c72018-10-08 12:05:16 -0700502 return ptr;
503}
504
Vernon Maueryf984a012018-10-08 12:05:18 -0700505/**
506 * @brief create a legacy IPMI OEM handler class and return a shared_ptr
507 *
508 * The queue uses a map of pointers to do the lookup. This function returns the
509 * shared_ptr that owns the Handler object.
510 *
511 * This is called internally via the Router::registerHandler method.
512 *
513 * @param handler the function pointer to the callback
514 *
515 * @return A shared_ptr to the created handler object
516 */
517inline auto makeLegacyHandler(oem::Handler&& handler)
518{
519 HandlerBase::ptr ptr(
520 new IpmiHandler<oem::Handler>(std::forward<oem::Handler>(handler)));
521 return ptr;
522}
Vernon Mauerye7329c72018-10-08 12:05:16 -0700523#endif // ALLOW_DEPRECATED_API
524
525/**
526 * @brief create an IPMI handler class and return a shared_ptr
527 *
528 * The queue uses a map of pointers to do the lookup. This function returns the
529 * shared_ptr that owns the Handler object.
530 *
531 * This is called internally via the ipmi::registerHandler function.
532 *
533 * @param handler the function pointer to the callback
534 *
535 * @return A shared_ptr to the created handler object
536 */
537template <typename Handler>
538inline auto makeHandler(Handler&& handler)
539{
540 HandlerBase::ptr ptr(
541 new IpmiHandler<Handler>(std::forward<Handler>(handler)));
542 return ptr;
543}
544
Vernon Mauerye08fbff2019-04-03 09:19:34 -0700545namespace impl
546{
547
548// IPMI command handler registration implementation
549bool registerHandler(int prio, NetFn netFn, Cmd cmd, Privilege priv,
550 ::ipmi::HandlerBase::ptr handler);
551bool registerGroupHandler(int prio, Group group, Cmd cmd, Privilege priv,
552 ::ipmi::HandlerBase::ptr handler);
553bool registerOemHandler(int prio, Iana iana, Cmd cmd, Privilege priv,
554 ::ipmi::HandlerBase::ptr handler);
555
556} // namespace impl
557
558/**
559 * @brief main IPMI handler registration function
560 *
561 * This function should be used to register all new-style IPMI handler
562 * functions. This function just passes the callback to makeHandler, which
563 * creates a new wrapper object that will automatically extract the appropriate
564 * parameters for the callback function as well as pack up the response.
565 *
566 * @param prio - priority at which to register; see api.hpp
567 * @param netFn - the IPMI net function number to register
568 * @param cmd - the IPMI command number to register
569 * @param priv - the IPMI user privilige required for this command
570 * @param handler - the callback function that will handle this request
571 *
572 * @return bool - success of registering the handler
573 */
574template <typename Handler>
575bool registerHandler(int prio, NetFn netFn, Cmd cmd, Privilege priv,
576 Handler&& handler)
577{
578 auto h = ipmi::makeHandler(std::forward<Handler>(handler));
579 return impl::registerHandler(prio, netFn, cmd, priv, h);
580}
581
582/**
583 * @brief register a IPMI OEM group handler
584 *
585 * From IPMI 2.0 spec Network Function Codes Table (Row 2Ch):
586 * The first data byte position in requests and responses under this network
587 * function identifies the defining body that specifies command functionality.
588 * Software assumes that the command and completion code field positions will
589 * hold command and completion code values.
590 *
591 * The following values are used to identify the defining body:
592 * 00h PICMG - PCI Industrial Computer Manufacturer’s Group. (www.picmg.com)
593 * 01h DMTF Pre-OS Working Group ASF Specification (www.dmtf.org)
594 * 02h Server System Infrastructure (SSI) Forum (www.ssiforum.org)
595 * 03h VITA Standards Organization (VSO) (www.vita.com)
596 * DCh DCMI Specifications (www.intel.com/go/dcmi)
597 * all other Reserved
598 *
599 * When this network function is used, the ID for the defining body occupies
600 * the first data byte in a request, and the second data byte (following the
601 * completion code) in a response.
602 *
603 * @tparam Handler - implicitly specified callback function type
604 * @param prio - priority at which to register; see api.hpp
605 * @param netFn - the IPMI net function number to register
606 * @param cmd - the IPMI command number to register
607 * @param priv - the IPMI user privilige required for this command
608 * @param handler - the callback function that will handle this request
609 *
610 * @return bool - success of registering the handler
611 *
612 */
613template <typename Handler>
614void registerGroupHandler(int prio, Group group, Cmd cmd, Privilege priv,
615 Handler&& handler)
616{
617 auto h = ipmi::makeHandler(handler);
618 impl::registerGroupHandler(prio, group, cmd, priv, h);
619}
620
621/**
622 * @brief register a IPMI OEM IANA handler
623 *
624 * From IPMI spec Network Function Codes Table (Row 2Eh):
625 * The first three data bytes of requests and responses under this network
626 * function explicitly identify the OEM or non-IPMI group that specifies the
627 * command functionality. While the OEM or non-IPMI group defines the
628 * functional semantics for the cmd and remaining data fields, the cmd field
629 * is required to hold the same value in requests and responses for a given
630 * operation in order to be supported under the IPMI message handling and
631 * transport mechanisms.
632 *
633 * When this network function is used, the IANA Enterprise Number for the
634 * defining body occupies the first three data bytes in a request, and the
635 * first three data bytes following the completion code position in a
636 * response.
637 *
638 * @tparam Handler - implicitly specified callback function type
639 * @param prio - priority at which to register; see api.hpp
640 * @param netFn - the IPMI net function number to register
641 * @param cmd - the IPMI command number to register
642 * @param priv - the IPMI user privilige required for this command
643 * @param handler - the callback function that will handle this request
644 *
645 * @return bool - success of registering the handler
646 *
647 */
648template <typename Handler>
649void registerOemHandler(int prio, Iana iana, Cmd cmd, Privilege priv,
650 Handler&& handler)
651{
652 auto h = ipmi::makeHandler(handler);
653 impl::registerOemHandler(prio, iana, cmd, priv, h);
654}
655
Vernon Mauerye7329c72018-10-08 12:05:16 -0700656} // namespace ipmi
Vernon Mauerye08fbff2019-04-03 09:19:34 -0700657
658#ifdef ALLOW_DEPRECATED_API
659/**
660 * @brief legacy IPMI handler registration function
661 *
662 * This function should be used to register all legacy IPMI handler
663 * functions. This function just behaves just as the legacy registration
664 * mechanism did, silently replacing any existing handler with a new one.
665 *
666 * @param netFn - the IPMI net function number to register
667 * @param cmd - the IPMI command number to register
668 * @param context - ignored
669 * @param handler - the callback function that will handle this request
670 * @param priv - the IPMI user privilige required for this command
671 */
672// [[deprecated("Use ipmi::registerHandler() instead")]]
673void ipmi_register_callback(ipmi_netfn_t netFn, ipmi_cmd_t cmd,
674 ipmi_context_t context, ipmid_callback_t handler,
675 ipmi_cmd_privilege_t priv);
676
677#endif /* ALLOW_DEPRECATED_API */