blob: 27ce370a353e02d5b3c640f496a9fa29a2762d83 [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
110 /** @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 */
144 virtual message::Response::ptr
145 executeCallback(message::Request::ptr request) = 0;
146};
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))
162 {
163 }
164
165 private:
166 Handler handler_;
167
168 /** @brief call the registered handler with the request
169 *
170 * This is called from the running queue context after it has already
171 * created a request object that contains all the information required to
172 * execute the ipmi command. This function will return the response object
173 * pointer that owns the response object that will ultimately get sent back
174 * to the requester.
175 *
176 * Because this is the new variety of IPMI handler, this is the function
177 * that attempts to extract the requested parameters in order to pass them
178 * onto the callback function and then packages up the response into a plain
179 * old vector to pass back to the caller.
180 *
181 * @param request a shared_ptr to a Request object
182 *
183 * @return a shared_ptr to a Response object
184 */
185 message::Response::ptr
186 executeCallback(message::Request::ptr request) override
187 {
188 message::Response::ptr response = request->makeResponse();
189
190 using CallbackSig = boost::callable_traits::args_t<Handler>;
191 using InputArgsType = typename utility::DecayTuple<CallbackSig>::type;
192 using UnpackArgsType = typename utility::StripFirstArgs<
193 utility::NonIpmiArgsCount<InputArgsType>::size(),
194 InputArgsType>::type;
195 using ResultType = boost::callable_traits::return_type_t<Handler>;
196
197 UnpackArgsType unpackArgs;
William A. Kennington III51694c22019-04-24 01:44:44 -0700198 request->payload.trailingOk = false;
Vernon Mauerye7329c72018-10-08 12:05:16 -0700199 ipmi::Cc unpackError = request->unpack(unpackArgs);
200 if (unpackError != ipmi::ccSuccess)
201 {
202 response->cc = unpackError;
203 return response;
204 }
205 /* callbacks can contain an optional first argument of one of:
206 * 1) boost::asio::yield_context
207 * 2) ipmi::Context::ptr
208 * 3) ipmi::message::Request::ptr
209 *
210 * If any of those is part of the callback signature as the first
211 * argument, it will automatically get packed into the parameter pack
212 * here.
213 *
214 * One more special optional argument is an ipmi::message::Payload.
215 * This argument can be in any position, though logically it makes the
216 * most sense if it is the last. If this class is included in the
217 * handler signature, it will allow for the handler to unpack optional
218 * parameters. For example, the Set LAN Configuration Parameters
219 * command takes variable length (and type) values for each of the LAN
220 * parameters. This means that the only fixed data is the channel and
221 * parameter selector. All the remaining data can be extracted using
222 * the Payload class and the unpack API available to the Payload class.
223 */
Vernon Mauerye7329c72018-10-08 12:05:16 -0700224 ResultType result;
225 try
226 {
William A. Kennington IIIf2fd17a2019-04-24 01:53:52 -0700227 std::optional<InputArgsType> inputArgs;
228 if constexpr (std::tuple_size<InputArgsType>::value > 0)
229 {
230 if constexpr (std::is_same<
231 std::tuple_element_t<0, InputArgsType>,
232 boost::asio::yield_context>::value)
233 {
234 inputArgs.emplace(std::tuple_cat(
James Feistcb09aa02019-09-06 13:41:59 -0700235 std::forward_as_tuple(request->ctx->yield),
William A. Kennington IIIf2fd17a2019-04-24 01:53:52 -0700236 std::move(unpackArgs)));
237 }
238 else if constexpr (std::is_same<
239 std::tuple_element_t<0, InputArgsType>,
240 ipmi::Context::ptr>::value)
241 {
242 inputArgs.emplace(
243 std::tuple_cat(std::forward_as_tuple(request->ctx),
244 std::move(unpackArgs)));
245 }
246 else if constexpr (std::is_same<
247 std::tuple_element_t<0, InputArgsType>,
248 ipmi::message::Request::ptr>::value)
249 {
250 inputArgs.emplace(std::tuple_cat(
251 std::forward_as_tuple(request), std::move(unpackArgs)));
252 }
253 else
254 {
255 // no special parameters were requested (but others were)
256 inputArgs.emplace(std::move(unpackArgs));
257 }
258 }
259 else
260 {
261 // no parameters were requested
262 inputArgs = std::move(unpackArgs);
263 }
264
Vernon Mauerye7329c72018-10-08 12:05:16 -0700265 // execute the registered callback function and get the
266 // ipmi::RspType<>
267 result = std::apply(handler_, *inputArgs);
268 }
William A. Kennington III687e9b02021-01-08 10:37:09 -0800269 catch (const HandlerException& e)
270 {
271 phosphor::logging::log<phosphor::logging::level::INFO>(
272 "Handler produced exception",
273 phosphor::logging::entry("CC=%x", e.code()),
274 phosphor::logging::entry("EXCEPTION=%s", e.what()),
275 phosphor::logging::entry("NETFN=%x", request->ctx->netFn),
276 phosphor::logging::entry("CMD=%x", request->ctx->cmd));
277 return errorResponse(request, e.code());
278 }
Vernon Mauerye7329c72018-10-08 12:05:16 -0700279 catch (const std::exception& e)
280 {
281 phosphor::logging::log<phosphor::logging::level::ERR>(
282 "Handler failed to catch exception",
283 phosphor::logging::entry("EXCEPTION=%s", e.what()),
284 phosphor::logging::entry("NETFN=%x", request->ctx->netFn),
285 phosphor::logging::entry("CMD=%x", request->ctx->cmd));
286 return errorResponse(request, ccUnspecifiedError);
287 }
William A. Kennington III687e9b02021-01-08 10:37:09 -0800288 catch (const HandlerCompletion& c)
289 {
290 return errorResponse(request, c.code());
291 }
Vernon Mauerye7329c72018-10-08 12:05:16 -0700292 catch (...)
293 {
Vernon Mauery03d7a4b2021-01-19 11:22:17 -0800294 const char* what = currentExceptionType();
295 phosphor::logging::log<phosphor::logging::level::ERR>(
296 "Handler failed to catch exception",
297 phosphor::logging::entry("EXCEPTION=%s", what),
298 phosphor::logging::entry("NETFN=%x", request->ctx->netFn),
299 phosphor::logging::entry("CMD=%x", request->ctx->cmd));
300 return errorResponse(request, ccUnspecifiedError);
Vernon Mauerye7329c72018-10-08 12:05:16 -0700301 }
302
303 response->cc = std::get<0>(result);
304 auto payload = std::get<1>(result);
305 // check for optional payload
306 if (payload)
307 {
308 response->pack(*payload);
309 }
310 return response;
311 }
312};
313
314#ifdef ALLOW_DEPRECATED_API
Vernon Mauery48408b62019-08-22 14:41:50 -0700315static constexpr size_t maxLegacyBufferSize = 64 * 1024;
Vernon Mauerye7329c72018-10-08 12:05:16 -0700316/**
317 * @brief Legacy IPMI handler class
318 *
319 * Legacy IPMI handlers will resolve into this class, which will behave the same
320 * way as the legacy IPMI queue, passing in a big buffer for the request and a
321 * big buffer for the response.
322 *
323 * As soon as all the handlers have been rewritten, this class will be marked as
324 * deprecated and eventually removed.
325 */
326template <>
327class IpmiHandler<ipmid_callback_t> final : public HandlerBase
328{
329 public:
Vernon Mauerybe376302019-03-21 13:02:05 -0700330 explicit IpmiHandler(const ipmid_callback_t& handler, void* ctx = nullptr) :
331 handler_(handler), handlerCtx(ctx)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700332 {
333 }
334
335 private:
336 ipmid_callback_t handler_;
Vernon Mauerybe376302019-03-21 13:02:05 -0700337 void* handlerCtx;
Vernon Mauerye7329c72018-10-08 12:05:16 -0700338
339 /** @brief call the registered handler with the request
340 *
341 * This is called from the running queue context after it has already
342 * created a request object that contains all the information required to
343 * execute the ipmi command. This function will return the response object
344 * pointer that owns the response object that will ultimately get sent back
345 * to the requester.
346 *
347 * Because this is the legacy variety of IPMI handler, this function does
348 * not really have to do much other than pass the payload to the callback
349 * and return response to the caller.
350 *
351 * @param request a shared_ptr to a Request object
352 *
353 * @return a shared_ptr to a Response object
354 */
355 message::Response::ptr
356 executeCallback(message::Request::ptr request) override
357 {
358 message::Response::ptr response = request->makeResponse();
Vernon Mauerye7329c72018-10-08 12:05:16 -0700359 // allocate a big response buffer here
Vernon Mauery48408b62019-08-22 14:41:50 -0700360 response->payload.resize(maxLegacyBufferSize);
Vernon Mauerye7329c72018-10-08 12:05:16 -0700361
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700362 size_t len = request->payload.size() - request->payload.rawIndex;
Vernon Mauerye7329c72018-10-08 12:05:16 -0700363 Cc ccRet{ccSuccess};
364 try
365 {
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700366 ccRet =
367 handler_(request->ctx->netFn, request->ctx->cmd,
368 request->payload.data() + request->payload.rawIndex,
369 response->payload.data(), &len, handlerCtx);
Vernon Mauerye7329c72018-10-08 12:05:16 -0700370 }
William A. Kennington III687e9b02021-01-08 10:37:09 -0800371 catch (const HandlerException& e)
372 {
373 phosphor::logging::log<phosphor::logging::level::INFO>(
374 "Legacy Handler produced exception",
375 phosphor::logging::entry("CC=%x", e.code()),
376 phosphor::logging::entry("EXCEPTION=%s", e.what()),
377 phosphor::logging::entry("NETFN=%x", request->ctx->netFn),
378 phosphor::logging::entry("CMD=%x", request->ctx->cmd));
379 return errorResponse(request, e.code());
380 }
Vernon Mauerye7329c72018-10-08 12:05:16 -0700381 catch (const std::exception& e)
382 {
383 phosphor::logging::log<phosphor::logging::level::ERR>(
384 "Legacy Handler failed to catch exception",
385 phosphor::logging::entry("EXCEPTION=%s", e.what()),
386 phosphor::logging::entry("NETFN=%x", request->ctx->netFn),
387 phosphor::logging::entry("CMD=%x", request->ctx->cmd));
388 return errorResponse(request, ccUnspecifiedError);
389 }
William A. Kennington III687e9b02021-01-08 10:37:09 -0800390 catch (const HandlerCompletion& c)
391 {
392 return errorResponse(request, c.code());
393 }
Vernon Mauerye7329c72018-10-08 12:05:16 -0700394 catch (...)
395 {
Vernon Mauery03d7a4b2021-01-19 11:22:17 -0800396 const char* what = currentExceptionType();
397 phosphor::logging::log<phosphor::logging::level::ERR>(
398 "Handler failed to catch exception",
399 phosphor::logging::entry("EXCEPTION=%s", what),
400 phosphor::logging::entry("NETFN=%x", request->ctx->netFn),
401 phosphor::logging::entry("CMD=%x", request->ctx->cmd));
402 return errorResponse(request, ccUnspecifiedError);
Vernon Mauerye7329c72018-10-08 12:05:16 -0700403 }
404 response->cc = ccRet;
405 response->payload.resize(len);
406 return response;
407 }
408};
409
410/**
Vernon Maueryf984a012018-10-08 12:05:18 -0700411 * @brief Legacy IPMI OEM handler class
412 *
413 * Legacy IPMI OEM handlers will resolve into this class, which will behave the
414 * same way as the legacy IPMI queue, passing in a big buffer for the request
415 * and a big buffer for the response.
416 *
417 * As soon as all the handlers have been rewritten, this class will be marked as
418 * deprecated and eventually removed.
419 */
420template <>
421class IpmiHandler<oem::Handler> final : public HandlerBase
422{
423 public:
424 explicit IpmiHandler(const oem::Handler& handler) : handler_(handler)
425 {
426 }
427
428 private:
429 oem::Handler handler_;
430
431 /** @brief call the registered handler with the request
432 *
433 * This is called from the running queue context after it has already
434 * created a request object that contains all the information required to
435 * execute the ipmi command. This function will return the response object
436 * pointer that owns the response object that will ultimately get sent back
437 * to the requester.
438 *
439 * Because this is the legacy variety of IPMI handler, this function does
440 * not really have to do much other than pass the payload to the callback
441 * and return response to the caller.
442 *
443 * @param request a shared_ptr to a Request object
444 *
445 * @return a shared_ptr to a Response object
446 */
447 message::Response::ptr
448 executeCallback(message::Request::ptr request) override
449 {
450 message::Response::ptr response = request->makeResponse();
Vernon Maueryf984a012018-10-08 12:05:18 -0700451 // allocate a big response buffer here
Vernon Mauery48408b62019-08-22 14:41:50 -0700452 response->payload.resize(maxLegacyBufferSize);
Vernon Maueryf984a012018-10-08 12:05:18 -0700453
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700454 size_t len = request->payload.size() - request->payload.rawIndex;
Vernon Maueryf984a012018-10-08 12:05:18 -0700455 Cc ccRet{ccSuccess};
456 try
457 {
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700458 ccRet =
459 handler_(request->ctx->cmd,
460 request->payload.data() + request->payload.rawIndex,
461 response->payload.data(), &len);
Vernon Maueryf984a012018-10-08 12:05:18 -0700462 }
William A. Kennington III687e9b02021-01-08 10:37:09 -0800463 catch (const HandlerException& e)
464 {
465 phosphor::logging::log<phosphor::logging::level::INFO>(
466 "Legacy OEM Handler produced exception",
467 phosphor::logging::entry("CC=%x", e.code()),
468 phosphor::logging::entry("EXCEPTION=%s", e.what()),
469 phosphor::logging::entry("NETFN=%x", request->ctx->netFn),
470 phosphor::logging::entry("CMD=%x", request->ctx->cmd));
471 return errorResponse(request, e.code());
472 }
Vernon Maueryf984a012018-10-08 12:05:18 -0700473 catch (const std::exception& e)
474 {
475 phosphor::logging::log<phosphor::logging::level::ERR>(
476 "Legacy OEM Handler failed to catch exception",
477 phosphor::logging::entry("EXCEPTION=%s", e.what()),
478 phosphor::logging::entry("NETFN=%x", request->ctx->netFn),
479 phosphor::logging::entry("CMD=%x", request->ctx->cmd));
480 return errorResponse(request, ccUnspecifiedError);
481 }
William A. Kennington III687e9b02021-01-08 10:37:09 -0800482 catch (const HandlerCompletion& c)
483 {
484 return errorResponse(request, c.code());
485 }
Vernon Maueryf984a012018-10-08 12:05:18 -0700486 catch (...)
487 {
Vernon Mauery03d7a4b2021-01-19 11:22:17 -0800488 const char* what = currentExceptionType();
489 phosphor::logging::log<phosphor::logging::level::ERR>(
490 "Handler failed to catch exception",
491 phosphor::logging::entry("EXCEPTION=%s", what),
492 phosphor::logging::entry("NETFN=%x", request->ctx->netFn),
493 phosphor::logging::entry("CMD=%x", request->ctx->cmd));
494 return errorResponse(request, ccUnspecifiedError);
Vernon Maueryf984a012018-10-08 12:05:18 -0700495 }
496 response->cc = ccRet;
497 response->payload.resize(len);
498 return response;
499 }
500};
501
502/**
Vernon Mauerye7329c72018-10-08 12:05:16 -0700503 * @brief create a legacy IPMI handler class and return a shared_ptr
504 *
505 * The queue uses a map of pointers to do the lookup. This function returns the
506 * shared_ptr that owns the Handler object.
507 *
508 * This is called internally via the ipmi_register_callback function.
509 *
510 * @param handler the function pointer to the callback
511 *
512 * @return A shared_ptr to the created handler object
513 */
Vernon Mauerybe376302019-03-21 13:02:05 -0700514inline auto makeLegacyHandler(const ipmid_callback_t& handler,
515 void* ctx = nullptr)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700516{
Vernon Mauerybe376302019-03-21 13:02:05 -0700517 HandlerBase::ptr ptr(new IpmiHandler<ipmid_callback_t>(handler, ctx));
Vernon Mauerye7329c72018-10-08 12:05:16 -0700518 return ptr;
519}
520
Vernon Maueryf984a012018-10-08 12:05:18 -0700521/**
522 * @brief create a legacy IPMI OEM handler class and return a shared_ptr
523 *
524 * The queue uses a map of pointers to do the lookup. This function returns the
525 * shared_ptr that owns the Handler object.
526 *
527 * This is called internally via the Router::registerHandler method.
528 *
529 * @param handler the function pointer to the callback
530 *
531 * @return A shared_ptr to the created handler object
532 */
533inline auto makeLegacyHandler(oem::Handler&& handler)
534{
535 HandlerBase::ptr ptr(
536 new IpmiHandler<oem::Handler>(std::forward<oem::Handler>(handler)));
537 return ptr;
538}
Vernon Mauerye7329c72018-10-08 12:05:16 -0700539#endif // ALLOW_DEPRECATED_API
540
541/**
542 * @brief create an IPMI handler class and return a shared_ptr
543 *
544 * The queue uses a map of pointers to do the lookup. This function returns the
545 * shared_ptr that owns the Handler object.
546 *
547 * This is called internally via the ipmi::registerHandler function.
548 *
549 * @param handler the function pointer to the callback
550 *
551 * @return A shared_ptr to the created handler object
552 */
553template <typename Handler>
554inline auto makeHandler(Handler&& handler)
555{
556 HandlerBase::ptr ptr(
557 new IpmiHandler<Handler>(std::forward<Handler>(handler)));
558 return ptr;
559}
560
Vernon Mauerye08fbff2019-04-03 09:19:34 -0700561namespace impl
562{
563
564// IPMI command handler registration implementation
565bool registerHandler(int prio, NetFn netFn, Cmd cmd, Privilege priv,
566 ::ipmi::HandlerBase::ptr handler);
567bool registerGroupHandler(int prio, Group group, Cmd cmd, Privilege priv,
568 ::ipmi::HandlerBase::ptr handler);
569bool registerOemHandler(int prio, Iana iana, Cmd cmd, Privilege priv,
570 ::ipmi::HandlerBase::ptr handler);
571
572} // namespace impl
573
574/**
575 * @brief main IPMI handler registration function
576 *
577 * This function should be used to register all new-style IPMI handler
578 * functions. This function just passes the callback to makeHandler, which
579 * creates a new wrapper object that will automatically extract the appropriate
580 * parameters for the callback function as well as pack up the response.
581 *
582 * @param prio - priority at which to register; see api.hpp
583 * @param netFn - the IPMI net function number to register
584 * @param cmd - the IPMI command number to register
585 * @param priv - the IPMI user privilige required for this command
586 * @param handler - the callback function that will handle this request
587 *
588 * @return bool - success of registering the handler
589 */
590template <typename Handler>
591bool registerHandler(int prio, NetFn netFn, Cmd cmd, Privilege priv,
592 Handler&& handler)
593{
594 auto h = ipmi::makeHandler(std::forward<Handler>(handler));
595 return impl::registerHandler(prio, netFn, cmd, priv, h);
596}
597
598/**
599 * @brief register a IPMI OEM group handler
600 *
601 * From IPMI 2.0 spec Network Function Codes Table (Row 2Ch):
602 * The first data byte position in requests and responses under this network
603 * function identifies the defining body that specifies command functionality.
604 * Software assumes that the command and completion code field positions will
605 * hold command and completion code values.
606 *
607 * The following values are used to identify the defining body:
608 * 00h PICMG - PCI Industrial Computer Manufacturer’s Group. (www.picmg.com)
609 * 01h DMTF Pre-OS Working Group ASF Specification (www.dmtf.org)
610 * 02h Server System Infrastructure (SSI) Forum (www.ssiforum.org)
611 * 03h VITA Standards Organization (VSO) (www.vita.com)
612 * DCh DCMI Specifications (www.intel.com/go/dcmi)
613 * all other Reserved
614 *
615 * When this network function is used, the ID for the defining body occupies
616 * the first data byte in a request, and the second data byte (following the
617 * completion code) in a response.
618 *
619 * @tparam Handler - implicitly specified callback function type
620 * @param prio - priority at which to register; see api.hpp
621 * @param netFn - the IPMI net function number to register
622 * @param cmd - the IPMI command number to register
623 * @param priv - the IPMI user privilige required for this command
624 * @param handler - the callback function that will handle this request
625 *
626 * @return bool - success of registering the handler
627 *
628 */
629template <typename Handler>
630void registerGroupHandler(int prio, Group group, Cmd cmd, Privilege priv,
631 Handler&& handler)
632{
633 auto h = ipmi::makeHandler(handler);
634 impl::registerGroupHandler(prio, group, cmd, priv, h);
635}
636
637/**
638 * @brief register a IPMI OEM IANA handler
639 *
640 * From IPMI spec Network Function Codes Table (Row 2Eh):
641 * The first three data bytes of requests and responses under this network
642 * function explicitly identify the OEM or non-IPMI group that specifies the
643 * command functionality. While the OEM or non-IPMI group defines the
644 * functional semantics for the cmd and remaining data fields, the cmd field
645 * is required to hold the same value in requests and responses for a given
646 * operation in order to be supported under the IPMI message handling and
647 * transport mechanisms.
648 *
649 * When this network function is used, the IANA Enterprise Number for the
650 * defining body occupies the first three data bytes in a request, and the
651 * first three data bytes following the completion code position in a
652 * response.
653 *
654 * @tparam Handler - implicitly specified callback function type
655 * @param prio - priority at which to register; see api.hpp
656 * @param netFn - the IPMI net function number to register
657 * @param cmd - the IPMI command number to register
658 * @param priv - the IPMI user privilige required for this command
659 * @param handler - the callback function that will handle this request
660 *
661 * @return bool - success of registering the handler
662 *
663 */
664template <typename Handler>
665void registerOemHandler(int prio, Iana iana, Cmd cmd, Privilege priv,
666 Handler&& handler)
667{
668 auto h = ipmi::makeHandler(handler);
669 impl::registerOemHandler(prio, iana, cmd, priv, h);
670}
671
Vernon Mauerye7329c72018-10-08 12:05:16 -0700672} // namespace ipmi
Vernon Mauerye08fbff2019-04-03 09:19:34 -0700673
674#ifdef ALLOW_DEPRECATED_API
675/**
676 * @brief legacy IPMI handler registration function
677 *
678 * This function should be used to register all legacy IPMI handler
679 * functions. This function just behaves just as the legacy registration
680 * mechanism did, silently replacing any existing handler with a new one.
681 *
682 * @param netFn - the IPMI net function number to register
683 * @param cmd - the IPMI command number to register
684 * @param context - ignored
685 * @param handler - the callback function that will handle this request
686 * @param priv - the IPMI user privilige required for this command
687 */
688// [[deprecated("Use ipmi::registerHandler() instead")]]
689void ipmi_register_callback(ipmi_netfn_t netFn, ipmi_cmd_t cmd,
690 ipmi_context_t context, ipmid_callback_t handler,
691 ipmi_cmd_privilege_t priv);
692
693#endif /* ALLOW_DEPRECATED_API */