blob: 229b0cf7f3b19146590714c10222aee554140968 [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 <algorithm>
20#include <boost/asio/spawn.hpp>
21#include <boost/callable_traits.hpp>
22#include <cstdint>
23#include <exception>
Vernon Mauerye08fbff2019-04-03 09:19:34 -070024#include <ipmid/api-types.hpp>
Vernon Mauerye7329c72018-10-08 12:05:16 -070025#include <ipmid/message.hpp>
26#include <memory>
27#include <optional>
28#include <phosphor-logging/log.hpp>
William A. Kennington III687e9b02021-01-08 10:37:09 -080029#include <stdexcept>
Vernon Mauerye7329c72018-10-08 12:05:16 -070030#include <tuple>
31#include <user_channel/channel_layer.hpp>
32#include <utility>
33
34#ifdef ALLOW_DEPRECATED_API
35#include <ipmid/api.h>
36
37#include <ipmid/oemrouter.hpp>
38#endif /* ALLOW_DEPRECATED_API */
39
40namespace ipmi
41{
42
43template <typename... Args>
44static inline message::Response::ptr
45 errorResponse(message::Request::ptr request, ipmi::Cc cc, Args&&... args)
46{
47 message::Response::ptr response = request->makeResponse();
Vernon Mauerybfe55a12019-03-08 13:48:40 -080048 response->cc = cc;
49 response->pack(args...);
Vernon Mauerye7329c72018-10-08 12:05:16 -070050 return response;
51}
52static inline message::Response::ptr
53 errorResponse(message::Request::ptr request, ipmi::Cc cc)
54{
55 message::Response::ptr response = request->makeResponse();
Vernon Mauerybfe55a12019-03-08 13:48:40 -080056 response->cc = cc;
Vernon Mauerye7329c72018-10-08 12:05:16 -070057 return response;
58}
59
William A. Kennington III687e9b02021-01-08 10:37:09 -080060/** @brief Exception extension that allows setting an IPMI return code */
61class HandlerCompletion
62{
63 public:
64 HandlerCompletion(Cc cc) noexcept : cc(cc)
65 {
66 }
67
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)
84 {
85 }
86 HandlerException(Cc cc, const std::string& what) :
87 HandlerException(cc, what.c_str())
88 {
89 }
90};
91
Vernon Mauery03d7a4b2021-01-19 11:22:17 -080092static inline const char* currentExceptionType()
93{
94 int status;
95 return abi::__cxa_demangle(abi::__cxa_current_exception_type()->name(), 0,
96 0, &status);
97}
98
Vernon Mauerye7329c72018-10-08 12:05:16 -070099/**
100 * @brief Handler base class for dealing with IPMI request/response
101 *
102 * The subclasses are all templated so they can provide access to any type
103 * of command callback functions.
104 */
105class HandlerBase
106{
107 public:
108 using ptr = std::shared_ptr<HandlerBase>;
109
Patrick Williams7d7a6852022-07-25 09:53:19 -0500110 virtual ~HandlerBase() = default;
111
Vernon Mauerye7329c72018-10-08 12:05:16 -0700112 /** @brief wrap the call to the registered handler with the request
113 *
114 * This is called from the running queue context after it has already
115 * created a request object that contains all the information required to
116 * execute the ipmi command. This function will return the response object
117 * pointer that owns the response object that will ultimately get sent back
118 * to the requester.
119 *
120 * This is a non-virtual function wrapper to the virtualized executeCallback
121 * function that actually does the work. This is required because of how
122 * templates and virtualization work together.
123 *
124 * @param request a shared_ptr to a Request object
125 *
126 * @return a shared_ptr to a Response object
127 */
128 message::Response::ptr call(message::Request::ptr request)
129 {
130 return executeCallback(request);
131 }
132
133 private:
134 /** @brief call the registered handler with the request
135 *
136 * This is called from the running queue context after it has already
137 * created a request object that contains all the information required to
138 * execute the ipmi command. This function will return the response object
139 * pointer that owns the response object that will ultimately get sent back
140 * to the requester.
141 *
142 * @param request a shared_ptr to a Request object
143 *
144 * @return a shared_ptr to a Response object
145 */
146 virtual message::Response::ptr
147 executeCallback(message::Request::ptr request) = 0;
148};
149
150/**
151 * @brief Main IPMI handler class
152 *
153 * New IPMI handlers will resolve into this class, which will read the signature
154 * of the registering function, attempt to extract the appropriate arguments
155 * from a request, pass the arguments to the function, and then pack the
156 * response of the function back into an IPMI response.
157 */
158template <typename Handler>
159class IpmiHandler final : public HandlerBase
160{
161 public:
162 explicit IpmiHandler(Handler&& handler) :
163 handler_(std::forward<Handler>(handler))
164 {
165 }
166
167 private:
168 Handler handler_;
169
170 /** @brief call the registered handler with the request
171 *
172 * This is called from the running queue context after it has already
173 * created a request object that contains all the information required to
174 * execute the ipmi command. This function will return the response object
175 * pointer that owns the response object that will ultimately get sent back
176 * to the requester.
177 *
178 * Because this is the new variety of IPMI handler, this is the function
179 * that attempts to extract the requested parameters in order to pass them
180 * onto the callback function and then packages up the response into a plain
181 * old vector to pass back to the caller.
182 *
183 * @param request a shared_ptr to a Request object
184 *
185 * @return a shared_ptr to a Response object
186 */
187 message::Response::ptr
188 executeCallback(message::Request::ptr request) override
189 {
190 message::Response::ptr response = request->makeResponse();
191
192 using CallbackSig = boost::callable_traits::args_t<Handler>;
193 using InputArgsType = typename utility::DecayTuple<CallbackSig>::type;
194 using UnpackArgsType = typename utility::StripFirstArgs<
195 utility::NonIpmiArgsCount<InputArgsType>::size(),
196 InputArgsType>::type;
197 using ResultType = boost::callable_traits::return_type_t<Handler>;
198
199 UnpackArgsType unpackArgs;
William A. Kennington III51694c22019-04-24 01:44:44 -0700200 request->payload.trailingOk = false;
Vernon Mauerye7329c72018-10-08 12:05:16 -0700201 ipmi::Cc unpackError = request->unpack(unpackArgs);
202 if (unpackError != ipmi::ccSuccess)
203 {
204 response->cc = unpackError;
205 return response;
206 }
207 /* callbacks can contain an optional first argument of one of:
208 * 1) boost::asio::yield_context
209 * 2) ipmi::Context::ptr
210 * 3) ipmi::message::Request::ptr
211 *
212 * If any of those is part of the callback signature as the first
213 * argument, it will automatically get packed into the parameter pack
214 * here.
215 *
216 * One more special optional argument is an ipmi::message::Payload.
217 * This argument can be in any position, though logically it makes the
218 * most sense if it is the last. If this class is included in the
219 * handler signature, it will allow for the handler to unpack optional
220 * parameters. For example, the Set LAN Configuration Parameters
221 * command takes variable length (and type) values for each of the LAN
222 * parameters. This means that the only fixed data is the channel and
223 * parameter selector. All the remaining data can be extracted using
224 * the Payload class and the unpack API available to the Payload class.
225 */
Vernon Mauerye7329c72018-10-08 12:05:16 -0700226 ResultType result;
227 try
228 {
William A. Kennington IIIf2fd17a2019-04-24 01:53:52 -0700229 std::optional<InputArgsType> inputArgs;
230 if constexpr (std::tuple_size<InputArgsType>::value > 0)
231 {
232 if constexpr (std::is_same<
233 std::tuple_element_t<0, InputArgsType>,
234 boost::asio::yield_context>::value)
235 {
236 inputArgs.emplace(std::tuple_cat(
James Feistcb09aa02019-09-06 13:41:59 -0700237 std::forward_as_tuple(request->ctx->yield),
William A. Kennington IIIf2fd17a2019-04-24 01:53:52 -0700238 std::move(unpackArgs)));
239 }
240 else if constexpr (std::is_same<
241 std::tuple_element_t<0, InputArgsType>,
242 ipmi::Context::ptr>::value)
243 {
244 inputArgs.emplace(
245 std::tuple_cat(std::forward_as_tuple(request->ctx),
246 std::move(unpackArgs)));
247 }
248 else if constexpr (std::is_same<
249 std::tuple_element_t<0, InputArgsType>,
250 ipmi::message::Request::ptr>::value)
251 {
252 inputArgs.emplace(std::tuple_cat(
253 std::forward_as_tuple(request), std::move(unpackArgs)));
254 }
255 else
256 {
257 // no special parameters were requested (but others were)
258 inputArgs.emplace(std::move(unpackArgs));
259 }
260 }
261 else
262 {
263 // no parameters were requested
264 inputArgs = std::move(unpackArgs);
265 }
266
Vernon Mauerye7329c72018-10-08 12:05:16 -0700267 // execute the registered callback function and get the
268 // ipmi::RspType<>
269 result = std::apply(handler_, *inputArgs);
270 }
William A. Kennington III687e9b02021-01-08 10:37:09 -0800271 catch (const HandlerException& e)
272 {
273 phosphor::logging::log<phosphor::logging::level::INFO>(
274 "Handler produced exception",
275 phosphor::logging::entry("CC=%x", e.code()),
276 phosphor::logging::entry("EXCEPTION=%s", e.what()),
277 phosphor::logging::entry("NETFN=%x", request->ctx->netFn),
278 phosphor::logging::entry("CMD=%x", request->ctx->cmd));
279 return errorResponse(request, e.code());
280 }
Vernon Mauerye7329c72018-10-08 12:05:16 -0700281 catch (const std::exception& e)
282 {
283 phosphor::logging::log<phosphor::logging::level::ERR>(
284 "Handler failed to catch exception",
285 phosphor::logging::entry("EXCEPTION=%s", e.what()),
286 phosphor::logging::entry("NETFN=%x", request->ctx->netFn),
287 phosphor::logging::entry("CMD=%x", request->ctx->cmd));
288 return errorResponse(request, ccUnspecifiedError);
289 }
William A. Kennington III687e9b02021-01-08 10:37:09 -0800290 catch (const HandlerCompletion& c)
291 {
292 return errorResponse(request, c.code());
293 }
Vernon Mauerye7329c72018-10-08 12:05:16 -0700294 catch (...)
295 {
Vernon Mauery03d7a4b2021-01-19 11:22:17 -0800296 const char* what = currentExceptionType();
297 phosphor::logging::log<phosphor::logging::level::ERR>(
298 "Handler failed to catch exception",
299 phosphor::logging::entry("EXCEPTION=%s", what),
300 phosphor::logging::entry("NETFN=%x", request->ctx->netFn),
301 phosphor::logging::entry("CMD=%x", request->ctx->cmd));
302 return errorResponse(request, ccUnspecifiedError);
Vernon Mauerye7329c72018-10-08 12:05:16 -0700303 }
304
305 response->cc = std::get<0>(result);
306 auto payload = std::get<1>(result);
307 // check for optional payload
308 if (payload)
309 {
310 response->pack(*payload);
311 }
312 return response;
313 }
314};
315
316#ifdef ALLOW_DEPRECATED_API
Vernon Mauery48408b62019-08-22 14:41:50 -0700317static constexpr size_t maxLegacyBufferSize = 64 * 1024;
Vernon Mauerye7329c72018-10-08 12:05:16 -0700318/**
319 * @brief Legacy IPMI handler class
320 *
321 * Legacy IPMI handlers will resolve into this class, which will behave the same
322 * way as the legacy IPMI queue, passing in a big buffer for the request and a
323 * big buffer for the response.
324 *
325 * As soon as all the handlers have been rewritten, this class will be marked as
326 * deprecated and eventually removed.
327 */
328template <>
329class IpmiHandler<ipmid_callback_t> final : public HandlerBase
330{
331 public:
Vernon Mauerybe376302019-03-21 13:02:05 -0700332 explicit IpmiHandler(const ipmid_callback_t& handler, void* ctx = nullptr) :
333 handler_(handler), handlerCtx(ctx)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700334 {
335 }
336
337 private:
338 ipmid_callback_t handler_;
Vernon Mauerybe376302019-03-21 13:02:05 -0700339 void* handlerCtx;
Vernon Mauerye7329c72018-10-08 12:05:16 -0700340
341 /** @brief call the registered handler with the request
342 *
343 * This is called from the running queue context after it has already
344 * created a request object that contains all the information required to
345 * execute the ipmi command. This function will return the response object
346 * pointer that owns the response object that will ultimately get sent back
347 * to the requester.
348 *
349 * Because this is the legacy variety of IPMI handler, this function does
350 * not really have to do much other than pass the payload to the callback
351 * and return response to the caller.
352 *
353 * @param request a shared_ptr to a Request object
354 *
355 * @return a shared_ptr to a Response object
356 */
357 message::Response::ptr
358 executeCallback(message::Request::ptr request) override
359 {
360 message::Response::ptr response = request->makeResponse();
Vernon Mauerye7329c72018-10-08 12:05:16 -0700361 // allocate a big response buffer here
Vernon Mauery48408b62019-08-22 14:41:50 -0700362 response->payload.resize(maxLegacyBufferSize);
Vernon Mauerye7329c72018-10-08 12:05:16 -0700363
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700364 size_t len = request->payload.size() - request->payload.rawIndex;
Vernon Mauerye7329c72018-10-08 12:05:16 -0700365 Cc ccRet{ccSuccess};
366 try
367 {
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700368 ccRet =
369 handler_(request->ctx->netFn, request->ctx->cmd,
370 request->payload.data() + request->payload.rawIndex,
371 response->payload.data(), &len, handlerCtx);
Vernon Mauerye7329c72018-10-08 12:05:16 -0700372 }
William A. Kennington III687e9b02021-01-08 10:37:09 -0800373 catch (const HandlerException& e)
374 {
375 phosphor::logging::log<phosphor::logging::level::INFO>(
376 "Legacy Handler produced exception",
377 phosphor::logging::entry("CC=%x", e.code()),
378 phosphor::logging::entry("EXCEPTION=%s", e.what()),
379 phosphor::logging::entry("NETFN=%x", request->ctx->netFn),
380 phosphor::logging::entry("CMD=%x", request->ctx->cmd));
381 return errorResponse(request, e.code());
382 }
Vernon Mauerye7329c72018-10-08 12:05:16 -0700383 catch (const std::exception& e)
384 {
385 phosphor::logging::log<phosphor::logging::level::ERR>(
386 "Legacy Handler failed to catch exception",
387 phosphor::logging::entry("EXCEPTION=%s", e.what()),
388 phosphor::logging::entry("NETFN=%x", request->ctx->netFn),
389 phosphor::logging::entry("CMD=%x", request->ctx->cmd));
390 return errorResponse(request, ccUnspecifiedError);
391 }
William A. Kennington III687e9b02021-01-08 10:37:09 -0800392 catch (const HandlerCompletion& c)
393 {
394 return errorResponse(request, c.code());
395 }
Vernon Mauerye7329c72018-10-08 12:05:16 -0700396 catch (...)
397 {
Vernon Mauery03d7a4b2021-01-19 11:22:17 -0800398 const char* what = currentExceptionType();
399 phosphor::logging::log<phosphor::logging::level::ERR>(
400 "Handler failed to catch exception",
401 phosphor::logging::entry("EXCEPTION=%s", what),
402 phosphor::logging::entry("NETFN=%x", request->ctx->netFn),
403 phosphor::logging::entry("CMD=%x", request->ctx->cmd));
404 return errorResponse(request, ccUnspecifiedError);
Vernon Mauerye7329c72018-10-08 12:05:16 -0700405 }
406 response->cc = ccRet;
407 response->payload.resize(len);
408 return response;
409 }
410};
411
412/**
Vernon Maueryf984a012018-10-08 12:05:18 -0700413 * @brief Legacy IPMI OEM handler class
414 *
415 * Legacy IPMI OEM handlers will resolve into this class, which will behave the
416 * same way as the legacy IPMI queue, passing in a big buffer for the request
417 * and a big buffer for the response.
418 *
419 * As soon as all the handlers have been rewritten, this class will be marked as
420 * deprecated and eventually removed.
421 */
422template <>
423class IpmiHandler<oem::Handler> final : public HandlerBase
424{
425 public:
426 explicit IpmiHandler(const oem::Handler& handler) : handler_(handler)
427 {
428 }
429
430 private:
431 oem::Handler handler_;
432
433 /** @brief call the registered handler with the request
434 *
435 * This is called from the running queue context after it has already
436 * created a request object that contains all the information required to
437 * execute the ipmi command. This function will return the response object
438 * pointer that owns the response object that will ultimately get sent back
439 * to the requester.
440 *
441 * Because this is the legacy variety of IPMI handler, this function does
442 * not really have to do much other than pass the payload to the callback
443 * and return response to the caller.
444 *
445 * @param request a shared_ptr to a Request object
446 *
447 * @return a shared_ptr to a Response object
448 */
449 message::Response::ptr
450 executeCallback(message::Request::ptr request) override
451 {
452 message::Response::ptr response = request->makeResponse();
Vernon Maueryf984a012018-10-08 12:05:18 -0700453 // allocate a big response buffer here
Vernon Mauery48408b62019-08-22 14:41:50 -0700454 response->payload.resize(maxLegacyBufferSize);
Vernon Maueryf984a012018-10-08 12:05:18 -0700455
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700456 size_t len = request->payload.size() - request->payload.rawIndex;
Vernon Maueryf984a012018-10-08 12:05:18 -0700457 Cc ccRet{ccSuccess};
458 try
459 {
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700460 ccRet =
461 handler_(request->ctx->cmd,
462 request->payload.data() + request->payload.rawIndex,
463 response->payload.data(), &len);
Vernon Maueryf984a012018-10-08 12:05:18 -0700464 }
William A. Kennington III687e9b02021-01-08 10:37:09 -0800465 catch (const HandlerException& e)
466 {
467 phosphor::logging::log<phosphor::logging::level::INFO>(
468 "Legacy OEM Handler produced exception",
469 phosphor::logging::entry("CC=%x", e.code()),
470 phosphor::logging::entry("EXCEPTION=%s", e.what()),
471 phosphor::logging::entry("NETFN=%x", request->ctx->netFn),
472 phosphor::logging::entry("CMD=%x", request->ctx->cmd));
473 return errorResponse(request, e.code());
474 }
Vernon Maueryf984a012018-10-08 12:05:18 -0700475 catch (const std::exception& e)
476 {
477 phosphor::logging::log<phosphor::logging::level::ERR>(
478 "Legacy OEM Handler failed to catch exception",
479 phosphor::logging::entry("EXCEPTION=%s", e.what()),
480 phosphor::logging::entry("NETFN=%x", request->ctx->netFn),
481 phosphor::logging::entry("CMD=%x", request->ctx->cmd));
482 return errorResponse(request, ccUnspecifiedError);
483 }
William A. Kennington III687e9b02021-01-08 10:37:09 -0800484 catch (const HandlerCompletion& c)
485 {
486 return errorResponse(request, c.code());
487 }
Vernon Maueryf984a012018-10-08 12:05:18 -0700488 catch (...)
489 {
Vernon Mauery03d7a4b2021-01-19 11:22:17 -0800490 const char* what = currentExceptionType();
491 phosphor::logging::log<phosphor::logging::level::ERR>(
492 "Handler failed to catch exception",
493 phosphor::logging::entry("EXCEPTION=%s", what),
494 phosphor::logging::entry("NETFN=%x", request->ctx->netFn),
495 phosphor::logging::entry("CMD=%x", request->ctx->cmd));
496 return errorResponse(request, ccUnspecifiedError);
Vernon Maueryf984a012018-10-08 12:05:18 -0700497 }
498 response->cc = ccRet;
499 response->payload.resize(len);
500 return response;
501 }
502};
503
504/**
Vernon Mauerye7329c72018-10-08 12:05:16 -0700505 * @brief create a legacy IPMI handler class and return a shared_ptr
506 *
507 * The queue uses a map of pointers to do the lookup. This function returns the
508 * shared_ptr that owns the Handler object.
509 *
510 * This is called internally via the ipmi_register_callback function.
511 *
512 * @param handler the function pointer to the callback
513 *
514 * @return A shared_ptr to the created handler object
515 */
Vernon Mauerybe376302019-03-21 13:02:05 -0700516inline auto makeLegacyHandler(const ipmid_callback_t& handler,
517 void* ctx = nullptr)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700518{
Vernon Mauerybe376302019-03-21 13:02:05 -0700519 HandlerBase::ptr ptr(new IpmiHandler<ipmid_callback_t>(handler, ctx));
Vernon Mauerye7329c72018-10-08 12:05:16 -0700520 return ptr;
521}
522
Vernon Maueryf984a012018-10-08 12:05:18 -0700523/**
524 * @brief create a legacy IPMI OEM handler class and return a shared_ptr
525 *
526 * The queue uses a map of pointers to do the lookup. This function returns the
527 * shared_ptr that owns the Handler object.
528 *
529 * This is called internally via the Router::registerHandler method.
530 *
531 * @param handler the function pointer to the callback
532 *
533 * @return A shared_ptr to the created handler object
534 */
535inline auto makeLegacyHandler(oem::Handler&& handler)
536{
537 HandlerBase::ptr ptr(
538 new IpmiHandler<oem::Handler>(std::forward<oem::Handler>(handler)));
539 return ptr;
540}
Vernon Mauerye7329c72018-10-08 12:05:16 -0700541#endif // ALLOW_DEPRECATED_API
542
543/**
544 * @brief create an IPMI handler class and return a shared_ptr
545 *
546 * The queue uses a map of pointers to do the lookup. This function returns the
547 * shared_ptr that owns the Handler object.
548 *
549 * This is called internally via the ipmi::registerHandler function.
550 *
551 * @param handler the function pointer to the callback
552 *
553 * @return A shared_ptr to the created handler object
554 */
555template <typename Handler>
556inline auto makeHandler(Handler&& handler)
557{
558 HandlerBase::ptr ptr(
559 new IpmiHandler<Handler>(std::forward<Handler>(handler)));
560 return ptr;
561}
562
Vernon Mauerye08fbff2019-04-03 09:19:34 -0700563namespace impl
564{
565
566// IPMI command handler registration implementation
567bool registerHandler(int prio, NetFn netFn, Cmd cmd, Privilege priv,
568 ::ipmi::HandlerBase::ptr handler);
569bool registerGroupHandler(int prio, Group group, Cmd cmd, Privilege priv,
570 ::ipmi::HandlerBase::ptr handler);
571bool registerOemHandler(int prio, Iana iana, Cmd cmd, Privilege priv,
572 ::ipmi::HandlerBase::ptr handler);
573
574} // namespace impl
575
576/**
577 * @brief main IPMI handler registration function
578 *
579 * This function should be used to register all new-style IPMI handler
580 * functions. This function just passes the callback to makeHandler, which
581 * creates a new wrapper object that will automatically extract the appropriate
582 * parameters for the callback function as well as pack up the response.
583 *
584 * @param prio - priority at which to register; see api.hpp
585 * @param netFn - the IPMI net function number to register
586 * @param cmd - the IPMI command number to register
587 * @param priv - the IPMI user privilige required for this command
588 * @param handler - the callback function that will handle this request
589 *
590 * @return bool - success of registering the handler
591 */
592template <typename Handler>
593bool registerHandler(int prio, NetFn netFn, Cmd cmd, Privilege priv,
594 Handler&& handler)
595{
596 auto h = ipmi::makeHandler(std::forward<Handler>(handler));
597 return impl::registerHandler(prio, netFn, cmd, priv, h);
598}
599
600/**
601 * @brief register a IPMI OEM group handler
602 *
603 * From IPMI 2.0 spec Network Function Codes Table (Row 2Ch):
604 * The first data byte position in requests and responses under this network
605 * function identifies the defining body that specifies command functionality.
606 * Software assumes that the command and completion code field positions will
607 * hold command and completion code values.
608 *
609 * The following values are used to identify the defining body:
610 * 00h PICMG - PCI Industrial Computer Manufacturer’s Group. (www.picmg.com)
611 * 01h DMTF Pre-OS Working Group ASF Specification (www.dmtf.org)
612 * 02h Server System Infrastructure (SSI) Forum (www.ssiforum.org)
613 * 03h VITA Standards Organization (VSO) (www.vita.com)
614 * DCh DCMI Specifications (www.intel.com/go/dcmi)
615 * all other Reserved
616 *
617 * When this network function is used, the ID for the defining body occupies
618 * the first data byte in a request, and the second data byte (following the
619 * completion code) in a response.
620 *
621 * @tparam Handler - implicitly specified callback function type
622 * @param prio - priority at which to register; see api.hpp
623 * @param netFn - the IPMI net function number to register
624 * @param cmd - the IPMI command number to register
625 * @param priv - the IPMI user privilige required for this command
626 * @param handler - the callback function that will handle this request
627 *
628 * @return bool - success of registering the handler
629 *
630 */
631template <typename Handler>
632void registerGroupHandler(int prio, Group group, Cmd cmd, Privilege priv,
633 Handler&& handler)
634{
635 auto h = ipmi::makeHandler(handler);
636 impl::registerGroupHandler(prio, group, cmd, priv, h);
637}
638
639/**
640 * @brief register a IPMI OEM IANA handler
641 *
642 * From IPMI spec Network Function Codes Table (Row 2Eh):
643 * The first three data bytes of requests and responses under this network
644 * function explicitly identify the OEM or non-IPMI group that specifies the
645 * command functionality. While the OEM or non-IPMI group defines the
646 * functional semantics for the cmd and remaining data fields, the cmd field
647 * is required to hold the same value in requests and responses for a given
648 * operation in order to be supported under the IPMI message handling and
649 * transport mechanisms.
650 *
651 * When this network function is used, the IANA Enterprise Number for the
652 * defining body occupies the first three data bytes in a request, and the
653 * first three data bytes following the completion code position in a
654 * response.
655 *
656 * @tparam Handler - implicitly specified callback function type
657 * @param prio - priority at which to register; see api.hpp
658 * @param netFn - the IPMI net function number to register
659 * @param cmd - the IPMI command number to register
660 * @param priv - the IPMI user privilige required for this command
661 * @param handler - the callback function that will handle this request
662 *
663 * @return bool - success of registering the handler
664 *
665 */
666template <typename Handler>
667void registerOemHandler(int prio, Iana iana, Cmd cmd, Privilege priv,
668 Handler&& handler)
669{
670 auto h = ipmi::makeHandler(handler);
671 impl::registerOemHandler(prio, iana, cmd, priv, h);
672}
673
Vernon Mauerye7329c72018-10-08 12:05:16 -0700674} // namespace ipmi
Vernon Mauerye08fbff2019-04-03 09:19:34 -0700675
676#ifdef ALLOW_DEPRECATED_API
677/**
678 * @brief legacy IPMI handler registration function
679 *
680 * This function should be used to register all legacy IPMI handler
681 * functions. This function just behaves just as the legacy registration
682 * mechanism did, silently replacing any existing handler with a new one.
683 *
684 * @param netFn - the IPMI net function number to register
685 * @param cmd - the IPMI command number to register
686 * @param context - ignored
687 * @param handler - the callback function that will handle this request
688 * @param priv - the IPMI user privilige required for this command
689 */
690// [[deprecated("Use ipmi::registerHandler() instead")]]
691void ipmi_register_callback(ipmi_netfn_t netFn, ipmi_cmd_t cmd,
692 ipmi_context_t context, ipmid_callback_t handler,
693 ipmi_cmd_privilege_t priv);
694
695#endif /* ALLOW_DEPRECATED_API */