blob: 62fcbe95fe64be590336c16de3a471480db01241 [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>
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -050023#include <phosphor-logging/log.hpp>
24#include <user_channel/channel_layer.hpp>
25
26#include <algorithm>
27#include <cstdint>
28#include <exception>
Vernon Mauerye7329c72018-10-08 12:05:16 -070029#include <memory>
30#include <optional>
William A. Kennington III687e9b02021-01-08 10:37:09 -080031#include <stdexcept>
Vernon Mauerye7329c72018-10-08 12:05:16 -070032#include <tuple>
Vernon Mauerye7329c72018-10-08 12:05:16 -070033#include <utility>
34
35#ifdef ALLOW_DEPRECATED_API
36#include <ipmid/api.h>
37
38#include <ipmid/oemrouter.hpp>
39#endif /* ALLOW_DEPRECATED_API */
40
41namespace ipmi
42{
43
44template <typename... Args>
45static inline message::Response::ptr
46 errorResponse(message::Request::ptr request, ipmi::Cc cc, Args&&... args)
47{
48 message::Response::ptr response = request->makeResponse();
Vernon Mauerybfe55a12019-03-08 13:48:40 -080049 response->cc = cc;
50 response->pack(args...);
Vernon Mauerye7329c72018-10-08 12:05:16 -070051 return response;
52}
53static inline message::Response::ptr
54 errorResponse(message::Request::ptr request, ipmi::Cc cc)
55{
56 message::Response::ptr response = request->makeResponse();
Vernon Mauerybfe55a12019-03-08 13:48:40 -080057 response->cc = cc;
Vernon Mauerye7329c72018-10-08 12:05:16 -070058 return response;
59}
60
William A. Kennington III687e9b02021-01-08 10:37:09 -080061/** @brief Exception extension that allows setting an IPMI return code */
62class HandlerCompletion
63{
64 public:
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -050065 HandlerCompletion(Cc cc) noexcept : cc(cc) {}
William A. Kennington III687e9b02021-01-08 10:37:09 -080066
67 Cc code() const noexcept
68 {
69 return cc;
70 }
71
72 private:
73 Cc cc;
74};
75
76/** @brief Exception extension that allows setting an IPMI return code and
77 * printing out a logged error */
78class HandlerException : public HandlerCompletion, public std::runtime_error
79{
80 public:
81 HandlerException(Cc cc, const char* what) :
82 HandlerCompletion(cc), std::runtime_error(what)
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -050083 {}
William A. Kennington III687e9b02021-01-08 10:37:09 -080084 HandlerException(Cc cc, const std::string& what) :
85 HandlerException(cc, what.c_str())
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -050086 {}
William A. Kennington III687e9b02021-01-08 10:37:09 -080087};
88
Vernon Mauery03d7a4b2021-01-19 11:22:17 -080089static inline const char* currentExceptionType()
90{
91 int status;
92 return abi::__cxa_demangle(abi::__cxa_current_exception_type()->name(), 0,
93 0, &status);
94}
95
Vernon Mauerye7329c72018-10-08 12:05:16 -070096/**
97 * @brief Handler base class for dealing with IPMI request/response
98 *
99 * The subclasses are all templated so they can provide access to any type
100 * of command callback functions.
101 */
102class HandlerBase
103{
104 public:
105 using ptr = std::shared_ptr<HandlerBase>;
106
Patrick Williams7d7a6852022-07-25 09:53:19 -0500107 virtual ~HandlerBase() = default;
108
Vernon Mauerye7329c72018-10-08 12:05:16 -0700109 /** @brief wrap the call to the registered handler with the request
110 *
111 * This is called from the running queue context after it has already
112 * created a request object that contains all the information required to
113 * execute the ipmi command. This function will return the response object
114 * pointer that owns the response object that will ultimately get sent back
115 * to the requester.
116 *
117 * This is a non-virtual function wrapper to the virtualized executeCallback
118 * function that actually does the work. This is required because of how
119 * templates and virtualization work together.
120 *
121 * @param request a shared_ptr to a Request object
122 *
123 * @return a shared_ptr to a Response object
124 */
125 message::Response::ptr call(message::Request::ptr request)
126 {
127 return executeCallback(request);
128 }
129
130 private:
131 /** @brief call the registered handler with the request
132 *
133 * This is called from the running queue context after it has already
134 * created a request object that contains all the information required to
135 * execute the ipmi command. This function will return the response object
136 * pointer that owns the response object that will ultimately get sent back
137 * to the requester.
138 *
139 * @param request a shared_ptr to a Request object
140 *
141 * @return a shared_ptr to a Response object
142 */
143 virtual message::Response::ptr
144 executeCallback(message::Request::ptr request) = 0;
145};
146
147/**
148 * @brief Main IPMI handler class
149 *
150 * New IPMI handlers will resolve into this class, which will read the signature
151 * of the registering function, attempt to extract the appropriate arguments
152 * from a request, pass the arguments to the function, and then pack the
153 * response of the function back into an IPMI response.
154 */
155template <typename Handler>
156class IpmiHandler final : public HandlerBase
157{
158 public:
159 explicit IpmiHandler(Handler&& handler) :
160 handler_(std::forward<Handler>(handler))
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500161 {}
Vernon Mauerye7329c72018-10-08 12:05:16 -0700162
163 private:
164 Handler handler_;
165
166 /** @brief call the registered handler with the request
167 *
168 * This is called from the running queue context after it has already
169 * created a request object that contains all the information required to
170 * execute the ipmi command. This function will return the response object
171 * pointer that owns the response object that will ultimately get sent back
172 * to the requester.
173 *
174 * Because this is the new variety of IPMI handler, this is the function
175 * that attempts to extract the requested parameters in order to pass them
176 * onto the callback function and then packages up the response into a plain
177 * old vector to pass back to the caller.
178 *
179 * @param request a shared_ptr to a Request object
180 *
181 * @return a shared_ptr to a Response object
182 */
183 message::Response::ptr
184 executeCallback(message::Request::ptr request) override
185 {
186 message::Response::ptr response = request->makeResponse();
187
188 using CallbackSig = boost::callable_traits::args_t<Handler>;
189 using InputArgsType = typename utility::DecayTuple<CallbackSig>::type;
190 using UnpackArgsType = typename utility::StripFirstArgs<
191 utility::NonIpmiArgsCount<InputArgsType>::size(),
192 InputArgsType>::type;
193 using ResultType = boost::callable_traits::return_type_t<Handler>;
194
Vernon Maueryed6f4602023-08-25 16:44:06 -0700195 UnpackArgsType unpackArgs{};
William A. Kennington III51694c22019-04-24 01:44:44 -0700196 request->payload.trailingOk = false;
Vernon Mauerye7329c72018-10-08 12:05:16 -0700197 ipmi::Cc unpackError = request->unpack(unpackArgs);
198 if (unpackError != ipmi::ccSuccess)
199 {
200 response->cc = unpackError;
201 return response;
202 }
203 /* callbacks can contain an optional first argument of one of:
204 * 1) boost::asio::yield_context
205 * 2) ipmi::Context::ptr
206 * 3) ipmi::message::Request::ptr
207 *
208 * If any of those is part of the callback signature as the first
209 * argument, it will automatically get packed into the parameter pack
210 * here.
211 *
212 * One more special optional argument is an ipmi::message::Payload.
213 * This argument can be in any position, though logically it makes the
214 * most sense if it is the last. If this class is included in the
215 * handler signature, it will allow for the handler to unpack optional
216 * parameters. For example, the Set LAN Configuration Parameters
217 * command takes variable length (and type) values for each of the LAN
218 * parameters. This means that the only fixed data is the channel and
219 * parameter selector. All the remaining data can be extracted using
220 * the Payload class and the unpack API available to the Payload class.
221 */
Vernon Mauerye7329c72018-10-08 12:05:16 -0700222 ResultType result;
223 try
224 {
William A. Kennington IIIf2fd17a2019-04-24 01:53:52 -0700225 std::optional<InputArgsType> inputArgs;
226 if constexpr (std::tuple_size<InputArgsType>::value > 0)
227 {
228 if constexpr (std::is_same<
229 std::tuple_element_t<0, InputArgsType>,
230 boost::asio::yield_context>::value)
231 {
232 inputArgs.emplace(std::tuple_cat(
James Feistcb09aa02019-09-06 13:41:59 -0700233 std::forward_as_tuple(request->ctx->yield),
William A. Kennington IIIf2fd17a2019-04-24 01:53:52 -0700234 std::move(unpackArgs)));
235 }
236 else if constexpr (std::is_same<
237 std::tuple_element_t<0, InputArgsType>,
238 ipmi::Context::ptr>::value)
239 {
240 inputArgs.emplace(
241 std::tuple_cat(std::forward_as_tuple(request->ctx),
242 std::move(unpackArgs)));
243 }
244 else if constexpr (std::is_same<
245 std::tuple_element_t<0, InputArgsType>,
246 ipmi::message::Request::ptr>::value)
247 {
248 inputArgs.emplace(std::tuple_cat(
249 std::forward_as_tuple(request), std::move(unpackArgs)));
250 }
251 else
252 {
253 // no special parameters were requested (but others were)
254 inputArgs.emplace(std::move(unpackArgs));
255 }
256 }
257 else
258 {
259 // no parameters were requested
260 inputArgs = std::move(unpackArgs);
261 }
262
Vernon Mauerye7329c72018-10-08 12:05:16 -0700263 // execute the registered callback function and get the
264 // ipmi::RspType<>
265 result = std::apply(handler_, *inputArgs);
266 }
William A. Kennington III687e9b02021-01-08 10:37:09 -0800267 catch (const HandlerException& e)
268 {
269 phosphor::logging::log<phosphor::logging::level::INFO>(
270 "Handler produced exception",
271 phosphor::logging::entry("CC=%x", e.code()),
272 phosphor::logging::entry("EXCEPTION=%s", e.what()),
273 phosphor::logging::entry("NETFN=%x", request->ctx->netFn),
274 phosphor::logging::entry("CMD=%x", request->ctx->cmd));
275 return errorResponse(request, e.code());
276 }
Vernon Mauerye7329c72018-10-08 12:05:16 -0700277 catch (const std::exception& e)
278 {
279 phosphor::logging::log<phosphor::logging::level::ERR>(
280 "Handler failed to catch exception",
281 phosphor::logging::entry("EXCEPTION=%s", e.what()),
282 phosphor::logging::entry("NETFN=%x", request->ctx->netFn),
283 phosphor::logging::entry("CMD=%x", request->ctx->cmd));
284 return errorResponse(request, ccUnspecifiedError);
285 }
William A. Kennington III687e9b02021-01-08 10:37:09 -0800286 catch (const HandlerCompletion& c)
287 {
288 return errorResponse(request, c.code());
289 }
Vernon Mauerye7329c72018-10-08 12:05:16 -0700290 catch (...)
291 {
Vernon Mauery03d7a4b2021-01-19 11:22:17 -0800292 const char* what = currentExceptionType();
293 phosphor::logging::log<phosphor::logging::level::ERR>(
294 "Handler failed to catch exception",
295 phosphor::logging::entry("EXCEPTION=%s", what),
296 phosphor::logging::entry("NETFN=%x", request->ctx->netFn),
297 phosphor::logging::entry("CMD=%x", request->ctx->cmd));
298 return errorResponse(request, ccUnspecifiedError);
Vernon Mauerye7329c72018-10-08 12:05:16 -0700299 }
300
301 response->cc = std::get<0>(result);
302 auto payload = std::get<1>(result);
303 // check for optional payload
304 if (payload)
305 {
306 response->pack(*payload);
307 }
308 return response;
309 }
310};
311
312#ifdef ALLOW_DEPRECATED_API
Vernon Mauery48408b62019-08-22 14:41:50 -0700313static constexpr size_t maxLegacyBufferSize = 64 * 1024;
Vernon Mauerye7329c72018-10-08 12:05:16 -0700314/**
315 * @brief Legacy IPMI handler class
316 *
317 * Legacy IPMI handlers will resolve into this class, which will behave the same
318 * way as the legacy IPMI queue, passing in a big buffer for the request and a
319 * big buffer for the response.
320 *
321 * As soon as all the handlers have been rewritten, this class will be marked as
322 * deprecated and eventually removed.
323 */
324template <>
325class IpmiHandler<ipmid_callback_t> final : public HandlerBase
326{
327 public:
Vernon Mauerybe376302019-03-21 13:02:05 -0700328 explicit IpmiHandler(const ipmid_callback_t& handler, void* ctx = nullptr) :
329 handler_(handler), handlerCtx(ctx)
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500330 {}
Vernon Mauerye7329c72018-10-08 12:05:16 -0700331
332 private:
333 ipmid_callback_t handler_;
Vernon Mauerybe376302019-03-21 13:02:05 -0700334 void* handlerCtx;
Vernon Mauerye7329c72018-10-08 12:05:16 -0700335
336 /** @brief call the registered handler with the request
337 *
338 * This is called from the running queue context after it has already
339 * created a request object that contains all the information required to
340 * execute the ipmi command. This function will return the response object
341 * pointer that owns the response object that will ultimately get sent back
342 * to the requester.
343 *
344 * Because this is the legacy variety of IPMI handler, this function does
345 * not really have to do much other than pass the payload to the callback
346 * and return response to the caller.
347 *
348 * @param request a shared_ptr to a Request object
349 *
350 * @return a shared_ptr to a Response object
351 */
352 message::Response::ptr
353 executeCallback(message::Request::ptr request) override
354 {
355 message::Response::ptr response = request->makeResponse();
Vernon Mauerye7329c72018-10-08 12:05:16 -0700356 // allocate a big response buffer here
Vernon Mauery48408b62019-08-22 14:41:50 -0700357 response->payload.resize(maxLegacyBufferSize);
Vernon Mauerye7329c72018-10-08 12:05:16 -0700358
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700359 size_t len = request->payload.size() - request->payload.rawIndex;
Vernon Mauerye7329c72018-10-08 12:05:16 -0700360 Cc ccRet{ccSuccess};
361 try
362 {
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700363 ccRet =
364 handler_(request->ctx->netFn, request->ctx->cmd,
365 request->payload.data() + request->payload.rawIndex,
366 response->payload.data(), &len, handlerCtx);
Vernon Mauerye7329c72018-10-08 12:05:16 -0700367 }
William A. Kennington III687e9b02021-01-08 10:37:09 -0800368 catch (const HandlerException& e)
369 {
370 phosphor::logging::log<phosphor::logging::level::INFO>(
371 "Legacy Handler produced exception",
372 phosphor::logging::entry("CC=%x", e.code()),
373 phosphor::logging::entry("EXCEPTION=%s", e.what()),
374 phosphor::logging::entry("NETFN=%x", request->ctx->netFn),
375 phosphor::logging::entry("CMD=%x", request->ctx->cmd));
376 return errorResponse(request, e.code());
377 }
Vernon Mauerye7329c72018-10-08 12:05:16 -0700378 catch (const std::exception& e)
379 {
380 phosphor::logging::log<phosphor::logging::level::ERR>(
381 "Legacy Handler failed to catch exception",
382 phosphor::logging::entry("EXCEPTION=%s", e.what()),
383 phosphor::logging::entry("NETFN=%x", request->ctx->netFn),
384 phosphor::logging::entry("CMD=%x", request->ctx->cmd));
385 return errorResponse(request, ccUnspecifiedError);
386 }
William A. Kennington III687e9b02021-01-08 10:37:09 -0800387 catch (const HandlerCompletion& c)
388 {
389 return errorResponse(request, c.code());
390 }
Vernon Mauerye7329c72018-10-08 12:05:16 -0700391 catch (...)
392 {
Vernon Mauery03d7a4b2021-01-19 11:22:17 -0800393 const char* what = currentExceptionType();
394 phosphor::logging::log<phosphor::logging::level::ERR>(
395 "Handler failed to catch exception",
396 phosphor::logging::entry("EXCEPTION=%s", what),
397 phosphor::logging::entry("NETFN=%x", request->ctx->netFn),
398 phosphor::logging::entry("CMD=%x", request->ctx->cmd));
399 return errorResponse(request, ccUnspecifiedError);
Vernon Mauerye7329c72018-10-08 12:05:16 -0700400 }
401 response->cc = ccRet;
402 response->payload.resize(len);
403 return response;
404 }
405};
406
407/**
Vernon Maueryf984a012018-10-08 12:05:18 -0700408 * @brief Legacy IPMI OEM handler class
409 *
410 * Legacy IPMI OEM handlers will resolve into this class, which will behave the
411 * same way as the legacy IPMI queue, passing in a big buffer for the request
412 * and a big buffer for the response.
413 *
414 * As soon as all the handlers have been rewritten, this class will be marked as
415 * deprecated and eventually removed.
416 */
417template <>
418class IpmiHandler<oem::Handler> final : public HandlerBase
419{
420 public:
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500421 explicit IpmiHandler(const oem::Handler& handler) : handler_(handler) {}
Vernon Maueryf984a012018-10-08 12:05:18 -0700422
423 private:
424 oem::Handler handler_;
425
426 /** @brief call the registered handler with the request
427 *
428 * This is called from the running queue context after it has already
429 * created a request object that contains all the information required to
430 * execute the ipmi command. This function will return the response object
431 * pointer that owns the response object that will ultimately get sent back
432 * to the requester.
433 *
434 * Because this is the legacy variety of IPMI handler, this function does
435 * not really have to do much other than pass the payload to the callback
436 * and return response to the caller.
437 *
438 * @param request a shared_ptr to a Request object
439 *
440 * @return a shared_ptr to a Response object
441 */
442 message::Response::ptr
443 executeCallback(message::Request::ptr request) override
444 {
445 message::Response::ptr response = request->makeResponse();
Vernon Maueryf984a012018-10-08 12:05:18 -0700446 // allocate a big response buffer here
Vernon Mauery48408b62019-08-22 14:41:50 -0700447 response->payload.resize(maxLegacyBufferSize);
Vernon Maueryf984a012018-10-08 12:05:18 -0700448
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700449 size_t len = request->payload.size() - request->payload.rawIndex;
Vernon Maueryf984a012018-10-08 12:05:18 -0700450 Cc ccRet{ccSuccess};
451 try
452 {
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700453 ccRet =
454 handler_(request->ctx->cmd,
455 request->payload.data() + request->payload.rawIndex,
456 response->payload.data(), &len);
Vernon Maueryf984a012018-10-08 12:05:18 -0700457 }
William A. Kennington III687e9b02021-01-08 10:37:09 -0800458 catch (const HandlerException& e)
459 {
460 phosphor::logging::log<phosphor::logging::level::INFO>(
461 "Legacy OEM Handler produced exception",
462 phosphor::logging::entry("CC=%x", e.code()),
463 phosphor::logging::entry("EXCEPTION=%s", e.what()),
464 phosphor::logging::entry("NETFN=%x", request->ctx->netFn),
465 phosphor::logging::entry("CMD=%x", request->ctx->cmd));
466 return errorResponse(request, e.code());
467 }
Vernon Maueryf984a012018-10-08 12:05:18 -0700468 catch (const std::exception& e)
469 {
470 phosphor::logging::log<phosphor::logging::level::ERR>(
471 "Legacy OEM Handler failed to catch exception",
472 phosphor::logging::entry("EXCEPTION=%s", e.what()),
473 phosphor::logging::entry("NETFN=%x", request->ctx->netFn),
474 phosphor::logging::entry("CMD=%x", request->ctx->cmd));
475 return errorResponse(request, ccUnspecifiedError);
476 }
William A. Kennington III687e9b02021-01-08 10:37:09 -0800477 catch (const HandlerCompletion& c)
478 {
479 return errorResponse(request, c.code());
480 }
Vernon Maueryf984a012018-10-08 12:05:18 -0700481 catch (...)
482 {
Vernon Mauery03d7a4b2021-01-19 11:22:17 -0800483 const char* what = currentExceptionType();
484 phosphor::logging::log<phosphor::logging::level::ERR>(
485 "Handler failed to catch exception",
486 phosphor::logging::entry("EXCEPTION=%s", what),
487 phosphor::logging::entry("NETFN=%x", request->ctx->netFn),
488 phosphor::logging::entry("CMD=%x", request->ctx->cmd));
489 return errorResponse(request, ccUnspecifiedError);
Vernon Maueryf984a012018-10-08 12:05:18 -0700490 }
491 response->cc = ccRet;
492 response->payload.resize(len);
493 return response;
494 }
495};
496
497/**
Vernon Mauerye7329c72018-10-08 12:05:16 -0700498 * @brief create a legacy IPMI handler class and return a shared_ptr
499 *
500 * The queue uses a map of pointers to do the lookup. This function returns the
501 * shared_ptr that owns the Handler object.
502 *
503 * This is called internally via the ipmi_register_callback function.
504 *
505 * @param handler the function pointer to the callback
506 *
507 * @return A shared_ptr to the created handler object
508 */
Vernon Mauerybe376302019-03-21 13:02:05 -0700509inline auto makeLegacyHandler(const ipmid_callback_t& handler,
510 void* ctx = nullptr)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700511{
Vernon Mauerybe376302019-03-21 13:02:05 -0700512 HandlerBase::ptr ptr(new IpmiHandler<ipmid_callback_t>(handler, ctx));
Vernon Mauerye7329c72018-10-08 12:05:16 -0700513 return ptr;
514}
515
Vernon Maueryf984a012018-10-08 12:05:18 -0700516/**
517 * @brief create a legacy IPMI OEM handler class and return a shared_ptr
518 *
519 * The queue uses a map of pointers to do the lookup. This function returns the
520 * shared_ptr that owns the Handler object.
521 *
522 * This is called internally via the Router::registerHandler method.
523 *
524 * @param handler the function pointer to the callback
525 *
526 * @return A shared_ptr to the created handler object
527 */
528inline auto makeLegacyHandler(oem::Handler&& handler)
529{
530 HandlerBase::ptr ptr(
531 new IpmiHandler<oem::Handler>(std::forward<oem::Handler>(handler)));
532 return ptr;
533}
Vernon Mauerye7329c72018-10-08 12:05:16 -0700534#endif // ALLOW_DEPRECATED_API
535
536/**
537 * @brief create an IPMI handler class and return a shared_ptr
538 *
539 * The queue uses a map of pointers to do the lookup. This function returns the
540 * shared_ptr that owns the Handler object.
541 *
542 * This is called internally via the ipmi::registerHandler function.
543 *
544 * @param handler the function pointer to the callback
545 *
546 * @return A shared_ptr to the created handler object
547 */
548template <typename Handler>
549inline auto makeHandler(Handler&& handler)
550{
551 HandlerBase::ptr ptr(
552 new IpmiHandler<Handler>(std::forward<Handler>(handler)));
553 return ptr;
554}
555
Vernon Mauerye08fbff2019-04-03 09:19:34 -0700556namespace impl
557{
558
559// IPMI command handler registration implementation
560bool registerHandler(int prio, NetFn netFn, Cmd cmd, Privilege priv,
561 ::ipmi::HandlerBase::ptr handler);
562bool registerGroupHandler(int prio, Group group, Cmd cmd, Privilege priv,
563 ::ipmi::HandlerBase::ptr handler);
564bool registerOemHandler(int prio, Iana iana, Cmd cmd, Privilege priv,
565 ::ipmi::HandlerBase::ptr handler);
566
567} // namespace impl
568
569/**
570 * @brief main IPMI handler registration function
571 *
572 * This function should be used to register all new-style IPMI handler
573 * functions. This function just passes the callback to makeHandler, which
574 * creates a new wrapper object that will automatically extract the appropriate
575 * parameters for the callback function as well as pack up the response.
576 *
577 * @param prio - priority at which to register; see api.hpp
578 * @param netFn - the IPMI net function number to register
579 * @param cmd - the IPMI command number to register
580 * @param priv - the IPMI user privilige required for this command
581 * @param handler - the callback function that will handle this request
582 *
583 * @return bool - success of registering the handler
584 */
585template <typename Handler>
586bool registerHandler(int prio, NetFn netFn, Cmd cmd, Privilege priv,
587 Handler&& handler)
588{
589 auto h = ipmi::makeHandler(std::forward<Handler>(handler));
590 return impl::registerHandler(prio, netFn, cmd, priv, h);
591}
592
593/**
594 * @brief register a IPMI OEM group handler
595 *
596 * From IPMI 2.0 spec Network Function Codes Table (Row 2Ch):
597 * The first data byte position in requests and responses under this network
598 * function identifies the defining body that specifies command functionality.
599 * Software assumes that the command and completion code field positions will
600 * hold command and completion code values.
601 *
602 * The following values are used to identify the defining body:
603 * 00h PICMG - PCI Industrial Computer Manufacturer’s Group. (www.picmg.com)
604 * 01h DMTF Pre-OS Working Group ASF Specification (www.dmtf.org)
605 * 02h Server System Infrastructure (SSI) Forum (www.ssiforum.org)
606 * 03h VITA Standards Organization (VSO) (www.vita.com)
607 * DCh DCMI Specifications (www.intel.com/go/dcmi)
608 * all other Reserved
609 *
610 * When this network function is used, the ID for the defining body occupies
611 * the first data byte in a request, and the second data byte (following the
612 * completion code) in a response.
613 *
614 * @tparam Handler - implicitly specified callback function type
615 * @param prio - priority at which to register; see api.hpp
616 * @param netFn - the IPMI net function number to register
617 * @param cmd - the IPMI command number to register
618 * @param priv - the IPMI user privilige required for this command
619 * @param handler - the callback function that will handle this request
620 *
621 * @return bool - success of registering the handler
622 *
623 */
624template <typename Handler>
625void registerGroupHandler(int prio, Group group, Cmd cmd, Privilege priv,
626 Handler&& handler)
627{
628 auto h = ipmi::makeHandler(handler);
629 impl::registerGroupHandler(prio, group, cmd, priv, h);
630}
631
632/**
633 * @brief register a IPMI OEM IANA handler
634 *
635 * From IPMI spec Network Function Codes Table (Row 2Eh):
636 * The first three data bytes of requests and responses under this network
637 * function explicitly identify the OEM or non-IPMI group that specifies the
638 * command functionality. While the OEM or non-IPMI group defines the
639 * functional semantics for the cmd and remaining data fields, the cmd field
640 * is required to hold the same value in requests and responses for a given
641 * operation in order to be supported under the IPMI message handling and
642 * transport mechanisms.
643 *
644 * When this network function is used, the IANA Enterprise Number for the
645 * defining body occupies the first three data bytes in a request, and the
646 * first three data bytes following the completion code position in a
647 * response.
648 *
649 * @tparam Handler - implicitly specified callback function type
650 * @param prio - priority at which to register; see api.hpp
651 * @param netFn - the IPMI net function number to register
652 * @param cmd - the IPMI command number to register
653 * @param priv - the IPMI user privilige required for this command
654 * @param handler - the callback function that will handle this request
655 *
656 * @return bool - success of registering the handler
657 *
658 */
659template <typename Handler>
660void registerOemHandler(int prio, Iana iana, Cmd cmd, Privilege priv,
661 Handler&& handler)
662{
663 auto h = ipmi::makeHandler(handler);
664 impl::registerOemHandler(prio, iana, cmd, priv, h);
665}
666
Vernon Mauerye7329c72018-10-08 12:05:16 -0700667} // namespace ipmi
Vernon Mauerye08fbff2019-04-03 09:19:34 -0700668
669#ifdef ALLOW_DEPRECATED_API
670/**
671 * @brief legacy IPMI handler registration function
672 *
673 * This function should be used to register all legacy IPMI handler
674 * functions. This function just behaves just as the legacy registration
675 * mechanism did, silently replacing any existing handler with a new one.
676 *
677 * @param netFn - the IPMI net function number to register
678 * @param cmd - the IPMI command number to register
679 * @param context - ignored
680 * @param handler - the callback function that will handle this request
681 * @param priv - the IPMI user privilige required for this command
682 */
683// [[deprecated("Use ipmi::registerHandler() instead")]]
684void ipmi_register_callback(ipmi_netfn_t netFn, ipmi_cmd_t cmd,
685 ipmi_context_t context, ipmid_callback_t handler,
686 ipmi_cmd_privilege_t priv);
687
688#endif /* ALLOW_DEPRECATED_API */