blob: 3b40762a448422dad333932fe7898adbdaf17150 [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
17#include <algorithm>
18#include <boost/asio/spawn.hpp>
19#include <boost/callable_traits.hpp>
20#include <cstdint>
21#include <exception>
Vernon Mauerye08fbff2019-04-03 09:19:34 -070022#include <ipmid/api-types.hpp>
Vernon Mauerye7329c72018-10-08 12:05:16 -070023#include <ipmid/message.hpp>
24#include <memory>
25#include <optional>
26#include <phosphor-logging/log.hpp>
William A. Kennington III687e9b02021-01-08 10:37:09 -080027#include <stdexcept>
Vernon Mauerye7329c72018-10-08 12:05:16 -070028#include <tuple>
29#include <user_channel/channel_layer.hpp>
30#include <utility>
31
32#ifdef ALLOW_DEPRECATED_API
33#include <ipmid/api.h>
34
35#include <ipmid/oemrouter.hpp>
36#endif /* ALLOW_DEPRECATED_API */
37
38namespace ipmi
39{
40
41template <typename... Args>
42static inline message::Response::ptr
43 errorResponse(message::Request::ptr request, ipmi::Cc cc, Args&&... args)
44{
45 message::Response::ptr response = request->makeResponse();
Vernon Mauerybfe55a12019-03-08 13:48:40 -080046 response->cc = cc;
47 response->pack(args...);
Vernon Mauerye7329c72018-10-08 12:05:16 -070048 return response;
49}
50static inline message::Response::ptr
51 errorResponse(message::Request::ptr request, ipmi::Cc cc)
52{
53 message::Response::ptr response = request->makeResponse();
Vernon Mauerybfe55a12019-03-08 13:48:40 -080054 response->cc = cc;
Vernon Mauerye7329c72018-10-08 12:05:16 -070055 return response;
56}
57
William A. Kennington III687e9b02021-01-08 10:37:09 -080058/** @brief Exception extension that allows setting an IPMI return code */
59class HandlerCompletion
60{
61 public:
62 HandlerCompletion(Cc cc) noexcept : cc(cc)
63 {
64 }
65
66 Cc code() const noexcept
67 {
68 return cc;
69 }
70
71 private:
72 Cc cc;
73};
74
75/** @brief Exception extension that allows setting an IPMI return code and
76 * printing out a logged error */
77class HandlerException : public HandlerCompletion, public std::runtime_error
78{
79 public:
80 HandlerException(Cc cc, const char* what) :
81 HandlerCompletion(cc), std::runtime_error(what)
82 {
83 }
84 HandlerException(Cc cc, const std::string& what) :
85 HandlerException(cc, what.c_str())
86 {
87 }
88};
89
Vernon Mauerye7329c72018-10-08 12:05:16 -070090/**
91 * @brief Handler base class for dealing with IPMI request/response
92 *
93 * The subclasses are all templated so they can provide access to any type
94 * of command callback functions.
95 */
96class HandlerBase
97{
98 public:
99 using ptr = std::shared_ptr<HandlerBase>;
100
101 /** @brief wrap the call to the registered handler with the request
102 *
103 * This is called from the running queue context after it has already
104 * created a request object that contains all the information required to
105 * execute the ipmi command. This function will return the response object
106 * pointer that owns the response object that will ultimately get sent back
107 * to the requester.
108 *
109 * This is a non-virtual function wrapper to the virtualized executeCallback
110 * function that actually does the work. This is required because of how
111 * templates and virtualization work together.
112 *
113 * @param request a shared_ptr to a Request object
114 *
115 * @return a shared_ptr to a Response object
116 */
117 message::Response::ptr call(message::Request::ptr request)
118 {
119 return executeCallback(request);
120 }
121
122 private:
123 /** @brief call the registered handler with the request
124 *
125 * This is called from the running queue context after it has already
126 * created a request object that contains all the information required to
127 * execute the ipmi command. This function will return the response object
128 * pointer that owns the response object that will ultimately get sent back
129 * to the requester.
130 *
131 * @param request a shared_ptr to a Request object
132 *
133 * @return a shared_ptr to a Response object
134 */
135 virtual message::Response::ptr
136 executeCallback(message::Request::ptr request) = 0;
137};
138
139/**
140 * @brief Main IPMI handler class
141 *
142 * New IPMI handlers will resolve into this class, which will read the signature
143 * of the registering function, attempt to extract the appropriate arguments
144 * from a request, pass the arguments to the function, and then pack the
145 * response of the function back into an IPMI response.
146 */
147template <typename Handler>
148class IpmiHandler final : public HandlerBase
149{
150 public:
151 explicit IpmiHandler(Handler&& handler) :
152 handler_(std::forward<Handler>(handler))
153 {
154 }
155
156 private:
157 Handler handler_;
158
159 /** @brief call the registered handler with the request
160 *
161 * This is called from the running queue context after it has already
162 * created a request object that contains all the information required to
163 * execute the ipmi command. This function will return the response object
164 * pointer that owns the response object that will ultimately get sent back
165 * to the requester.
166 *
167 * Because this is the new variety of IPMI handler, this is the function
168 * that attempts to extract the requested parameters in order to pass them
169 * onto the callback function and then packages up the response into a plain
170 * old vector to pass back to the caller.
171 *
172 * @param request a shared_ptr to a Request object
173 *
174 * @return a shared_ptr to a Response object
175 */
176 message::Response::ptr
177 executeCallback(message::Request::ptr request) override
178 {
179 message::Response::ptr response = request->makeResponse();
180
181 using CallbackSig = boost::callable_traits::args_t<Handler>;
182 using InputArgsType = typename utility::DecayTuple<CallbackSig>::type;
183 using UnpackArgsType = typename utility::StripFirstArgs<
184 utility::NonIpmiArgsCount<InputArgsType>::size(),
185 InputArgsType>::type;
186 using ResultType = boost::callable_traits::return_type_t<Handler>;
187
188 UnpackArgsType unpackArgs;
William A. Kennington III51694c22019-04-24 01:44:44 -0700189 request->payload.trailingOk = false;
Vernon Mauerye7329c72018-10-08 12:05:16 -0700190 ipmi::Cc unpackError = request->unpack(unpackArgs);
191 if (unpackError != ipmi::ccSuccess)
192 {
193 response->cc = unpackError;
194 return response;
195 }
196 /* callbacks can contain an optional first argument of one of:
197 * 1) boost::asio::yield_context
198 * 2) ipmi::Context::ptr
199 * 3) ipmi::message::Request::ptr
200 *
201 * If any of those is part of the callback signature as the first
202 * argument, it will automatically get packed into the parameter pack
203 * here.
204 *
205 * One more special optional argument is an ipmi::message::Payload.
206 * This argument can be in any position, though logically it makes the
207 * most sense if it is the last. If this class is included in the
208 * handler signature, it will allow for the handler to unpack optional
209 * parameters. For example, the Set LAN Configuration Parameters
210 * command takes variable length (and type) values for each of the LAN
211 * parameters. This means that the only fixed data is the channel and
212 * parameter selector. All the remaining data can be extracted using
213 * the Payload class and the unpack API available to the Payload class.
214 */
Vernon Mauerye7329c72018-10-08 12:05:16 -0700215 ResultType result;
216 try
217 {
William A. Kennington IIIf2fd17a2019-04-24 01:53:52 -0700218 std::optional<InputArgsType> inputArgs;
219 if constexpr (std::tuple_size<InputArgsType>::value > 0)
220 {
221 if constexpr (std::is_same<
222 std::tuple_element_t<0, InputArgsType>,
223 boost::asio::yield_context>::value)
224 {
225 inputArgs.emplace(std::tuple_cat(
James Feistcb09aa02019-09-06 13:41:59 -0700226 std::forward_as_tuple(request->ctx->yield),
William A. Kennington IIIf2fd17a2019-04-24 01:53:52 -0700227 std::move(unpackArgs)));
228 }
229 else if constexpr (std::is_same<
230 std::tuple_element_t<0, InputArgsType>,
231 ipmi::Context::ptr>::value)
232 {
233 inputArgs.emplace(
234 std::tuple_cat(std::forward_as_tuple(request->ctx),
235 std::move(unpackArgs)));
236 }
237 else if constexpr (std::is_same<
238 std::tuple_element_t<0, InputArgsType>,
239 ipmi::message::Request::ptr>::value)
240 {
241 inputArgs.emplace(std::tuple_cat(
242 std::forward_as_tuple(request), std::move(unpackArgs)));
243 }
244 else
245 {
246 // no special parameters were requested (but others were)
247 inputArgs.emplace(std::move(unpackArgs));
248 }
249 }
250 else
251 {
252 // no parameters were requested
253 inputArgs = std::move(unpackArgs);
254 }
255
Vernon Mauerye7329c72018-10-08 12:05:16 -0700256 // execute the registered callback function and get the
257 // ipmi::RspType<>
258 result = std::apply(handler_, *inputArgs);
259 }
William A. Kennington III687e9b02021-01-08 10:37:09 -0800260 catch (const HandlerException& e)
261 {
262 phosphor::logging::log<phosphor::logging::level::INFO>(
263 "Handler produced exception",
264 phosphor::logging::entry("CC=%x", e.code()),
265 phosphor::logging::entry("EXCEPTION=%s", e.what()),
266 phosphor::logging::entry("NETFN=%x", request->ctx->netFn),
267 phosphor::logging::entry("CMD=%x", request->ctx->cmd));
268 return errorResponse(request, e.code());
269 }
Vernon Mauerye7329c72018-10-08 12:05:16 -0700270 catch (const std::exception& e)
271 {
272 phosphor::logging::log<phosphor::logging::level::ERR>(
273 "Handler failed to catch exception",
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, ccUnspecifiedError);
278 }
William A. Kennington III687e9b02021-01-08 10:37:09 -0800279 catch (const HandlerCompletion& c)
280 {
281 return errorResponse(request, c.code());
282 }
Vernon Mauerye7329c72018-10-08 12:05:16 -0700283 catch (...)
284 {
285 std::exception_ptr eptr;
286 try
287 {
288 eptr = std::current_exception();
289 if (eptr)
290 {
291 std::rethrow_exception(eptr);
292 }
293 }
294 catch (const std::exception& e)
295 {
296 phosphor::logging::log<phosphor::logging::level::ERR>(
297 "Handler failed to catch exception",
298 phosphor::logging::entry("EXCEPTION=%s", e.what()),
299 phosphor::logging::entry("NETFN=%x", request->ctx->netFn),
300 phosphor::logging::entry("CMD=%x", request->ctx->cmd));
301 return errorResponse(request, ccUnspecifiedError);
302 }
303 }
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 {
398 std::exception_ptr eptr;
399 try
400 {
401 eptr = std::current_exception();
402 if (eptr)
403 {
404 std::rethrow_exception(eptr);
405 }
406 }
407 catch (const std::exception& e)
408 {
409 phosphor::logging::log<phosphor::logging::level::ERR>(
410 "Handler failed to catch exception",
411 phosphor::logging::entry("EXCEPTION=%s", e.what()),
412 phosphor::logging::entry("NETFN=%x", request->ctx->netFn),
413 phosphor::logging::entry("CMD=%x", request->ctx->cmd));
414 return errorResponse(request, ccUnspecifiedError);
415 }
416 }
417 response->cc = ccRet;
418 response->payload.resize(len);
419 return response;
420 }
421};
422
423/**
Vernon Maueryf984a012018-10-08 12:05:18 -0700424 * @brief Legacy IPMI OEM handler class
425 *
426 * Legacy IPMI OEM handlers will resolve into this class, which will behave the
427 * same way as the legacy IPMI queue, passing in a big buffer for the request
428 * and a big buffer for the response.
429 *
430 * As soon as all the handlers have been rewritten, this class will be marked as
431 * deprecated and eventually removed.
432 */
433template <>
434class IpmiHandler<oem::Handler> final : public HandlerBase
435{
436 public:
437 explicit IpmiHandler(const oem::Handler& handler) : handler_(handler)
438 {
439 }
440
441 private:
442 oem::Handler handler_;
443
444 /** @brief call the registered handler with the request
445 *
446 * This is called from the running queue context after it has already
447 * created a request object that contains all the information required to
448 * execute the ipmi command. This function will return the response object
449 * pointer that owns the response object that will ultimately get sent back
450 * to the requester.
451 *
452 * Because this is the legacy variety of IPMI handler, this function does
453 * not really have to do much other than pass the payload to the callback
454 * and return response to the caller.
455 *
456 * @param request a shared_ptr to a Request object
457 *
458 * @return a shared_ptr to a Response object
459 */
460 message::Response::ptr
461 executeCallback(message::Request::ptr request) override
462 {
463 message::Response::ptr response = request->makeResponse();
Vernon Maueryf984a012018-10-08 12:05:18 -0700464 // allocate a big response buffer here
Vernon Mauery48408b62019-08-22 14:41:50 -0700465 response->payload.resize(maxLegacyBufferSize);
Vernon Maueryf984a012018-10-08 12:05:18 -0700466
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700467 size_t len = request->payload.size() - request->payload.rawIndex;
Vernon Maueryf984a012018-10-08 12:05:18 -0700468 Cc ccRet{ccSuccess};
469 try
470 {
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700471 ccRet =
472 handler_(request->ctx->cmd,
473 request->payload.data() + request->payload.rawIndex,
474 response->payload.data(), &len);
Vernon Maueryf984a012018-10-08 12:05:18 -0700475 }
William A. Kennington III687e9b02021-01-08 10:37:09 -0800476 catch (const HandlerException& e)
477 {
478 phosphor::logging::log<phosphor::logging::level::INFO>(
479 "Legacy OEM Handler produced exception",
480 phosphor::logging::entry("CC=%x", e.code()),
481 phosphor::logging::entry("EXCEPTION=%s", e.what()),
482 phosphor::logging::entry("NETFN=%x", request->ctx->netFn),
483 phosphor::logging::entry("CMD=%x", request->ctx->cmd));
484 return errorResponse(request, e.code());
485 }
Vernon Maueryf984a012018-10-08 12:05:18 -0700486 catch (const std::exception& e)
487 {
488 phosphor::logging::log<phosphor::logging::level::ERR>(
489 "Legacy OEM Handler failed to catch exception",
490 phosphor::logging::entry("EXCEPTION=%s", e.what()),
491 phosphor::logging::entry("NETFN=%x", request->ctx->netFn),
492 phosphor::logging::entry("CMD=%x", request->ctx->cmd));
493 return errorResponse(request, ccUnspecifiedError);
494 }
William A. Kennington III687e9b02021-01-08 10:37:09 -0800495 catch (const HandlerCompletion& c)
496 {
497 return errorResponse(request, c.code());
498 }
Vernon Maueryf984a012018-10-08 12:05:18 -0700499 catch (...)
500 {
501 std::exception_ptr eptr;
502 try
503 {
504 eptr = std::current_exception();
505 if (eptr)
506 {
507 std::rethrow_exception(eptr);
508 }
509 }
510 catch (const std::exception& e)
511 {
512 phosphor::logging::log<phosphor::logging::level::ERR>(
513 "Handler failed to catch exception",
514 phosphor::logging::entry("EXCEPTION=%s", e.what()),
515 phosphor::logging::entry("NETFN=%x", request->ctx->netFn),
516 phosphor::logging::entry("CMD=%x", request->ctx->cmd));
517 return errorResponse(request, ccUnspecifiedError);
518 }
519 }
520 response->cc = ccRet;
521 response->payload.resize(len);
522 return response;
523 }
524};
525
526/**
Vernon Mauerye7329c72018-10-08 12:05:16 -0700527 * @brief create a legacy IPMI handler class and return a shared_ptr
528 *
529 * The queue uses a map of pointers to do the lookup. This function returns the
530 * shared_ptr that owns the Handler object.
531 *
532 * This is called internally via the ipmi_register_callback function.
533 *
534 * @param handler the function pointer to the callback
535 *
536 * @return A shared_ptr to the created handler object
537 */
Vernon Mauerybe376302019-03-21 13:02:05 -0700538inline auto makeLegacyHandler(const ipmid_callback_t& handler,
539 void* ctx = nullptr)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700540{
Vernon Mauerybe376302019-03-21 13:02:05 -0700541 HandlerBase::ptr ptr(new IpmiHandler<ipmid_callback_t>(handler, ctx));
Vernon Mauerye7329c72018-10-08 12:05:16 -0700542 return ptr;
543}
544
Vernon Maueryf984a012018-10-08 12:05:18 -0700545/**
546 * @brief create a legacy IPMI OEM handler class and return a shared_ptr
547 *
548 * The queue uses a map of pointers to do the lookup. This function returns the
549 * shared_ptr that owns the Handler object.
550 *
551 * This is called internally via the Router::registerHandler method.
552 *
553 * @param handler the function pointer to the callback
554 *
555 * @return A shared_ptr to the created handler object
556 */
557inline auto makeLegacyHandler(oem::Handler&& handler)
558{
559 HandlerBase::ptr ptr(
560 new IpmiHandler<oem::Handler>(std::forward<oem::Handler>(handler)));
561 return ptr;
562}
Vernon Mauerye7329c72018-10-08 12:05:16 -0700563#endif // ALLOW_DEPRECATED_API
564
565/**
566 * @brief create an IPMI handler class and return a shared_ptr
567 *
568 * The queue uses a map of pointers to do the lookup. This function returns the
569 * shared_ptr that owns the Handler object.
570 *
571 * This is called internally via the ipmi::registerHandler function.
572 *
573 * @param handler the function pointer to the callback
574 *
575 * @return A shared_ptr to the created handler object
576 */
577template <typename Handler>
578inline auto makeHandler(Handler&& handler)
579{
580 HandlerBase::ptr ptr(
581 new IpmiHandler<Handler>(std::forward<Handler>(handler)));
582 return ptr;
583}
584
Vernon Mauerye08fbff2019-04-03 09:19:34 -0700585namespace impl
586{
587
588// IPMI command handler registration implementation
589bool registerHandler(int prio, NetFn netFn, Cmd cmd, Privilege priv,
590 ::ipmi::HandlerBase::ptr handler);
591bool registerGroupHandler(int prio, Group group, Cmd cmd, Privilege priv,
592 ::ipmi::HandlerBase::ptr handler);
593bool registerOemHandler(int prio, Iana iana, Cmd cmd, Privilege priv,
594 ::ipmi::HandlerBase::ptr handler);
595
596} // namespace impl
597
598/**
599 * @brief main IPMI handler registration function
600 *
601 * This function should be used to register all new-style IPMI handler
602 * functions. This function just passes the callback to makeHandler, which
603 * creates a new wrapper object that will automatically extract the appropriate
604 * parameters for the callback function as well as pack up the response.
605 *
606 * @param prio - priority at which to register; see api.hpp
607 * @param netFn - the IPMI net function number to register
608 * @param cmd - the IPMI command number to register
609 * @param priv - the IPMI user privilige required for this command
610 * @param handler - the callback function that will handle this request
611 *
612 * @return bool - success of registering the handler
613 */
614template <typename Handler>
615bool registerHandler(int prio, NetFn netFn, Cmd cmd, Privilege priv,
616 Handler&& handler)
617{
618 auto h = ipmi::makeHandler(std::forward<Handler>(handler));
619 return impl::registerHandler(prio, netFn, cmd, priv, h);
620}
621
622/**
623 * @brief register a IPMI OEM group handler
624 *
625 * From IPMI 2.0 spec Network Function Codes Table (Row 2Ch):
626 * The first data byte position in requests and responses under this network
627 * function identifies the defining body that specifies command functionality.
628 * Software assumes that the command and completion code field positions will
629 * hold command and completion code values.
630 *
631 * The following values are used to identify the defining body:
632 * 00h PICMG - PCI Industrial Computer Manufacturer’s Group. (www.picmg.com)
633 * 01h DMTF Pre-OS Working Group ASF Specification (www.dmtf.org)
634 * 02h Server System Infrastructure (SSI) Forum (www.ssiforum.org)
635 * 03h VITA Standards Organization (VSO) (www.vita.com)
636 * DCh DCMI Specifications (www.intel.com/go/dcmi)
637 * all other Reserved
638 *
639 * When this network function is used, the ID for the defining body occupies
640 * the first data byte in a request, and the second data byte (following the
641 * completion code) in a response.
642 *
643 * @tparam Handler - implicitly specified callback function type
644 * @param prio - priority at which to register; see api.hpp
645 * @param netFn - the IPMI net function number to register
646 * @param cmd - the IPMI command number to register
647 * @param priv - the IPMI user privilige required for this command
648 * @param handler - the callback function that will handle this request
649 *
650 * @return bool - success of registering the handler
651 *
652 */
653template <typename Handler>
654void registerGroupHandler(int prio, Group group, Cmd cmd, Privilege priv,
655 Handler&& handler)
656{
657 auto h = ipmi::makeHandler(handler);
658 impl::registerGroupHandler(prio, group, cmd, priv, h);
659}
660
661/**
662 * @brief register a IPMI OEM IANA handler
663 *
664 * From IPMI spec Network Function Codes Table (Row 2Eh):
665 * The first three data bytes of requests and responses under this network
666 * function explicitly identify the OEM or non-IPMI group that specifies the
667 * command functionality. While the OEM or non-IPMI group defines the
668 * functional semantics for the cmd and remaining data fields, the cmd field
669 * is required to hold the same value in requests and responses for a given
670 * operation in order to be supported under the IPMI message handling and
671 * transport mechanisms.
672 *
673 * When this network function is used, the IANA Enterprise Number for the
674 * defining body occupies the first three data bytes in a request, and the
675 * first three data bytes following the completion code position in a
676 * response.
677 *
678 * @tparam Handler - implicitly specified callback function type
679 * @param prio - priority at which to register; see api.hpp
680 * @param netFn - the IPMI net function number to register
681 * @param cmd - the IPMI command number to register
682 * @param priv - the IPMI user privilige required for this command
683 * @param handler - the callback function that will handle this request
684 *
685 * @return bool - success of registering the handler
686 *
687 */
688template <typename Handler>
689void registerOemHandler(int prio, Iana iana, Cmd cmd, Privilege priv,
690 Handler&& handler)
691{
692 auto h = ipmi::makeHandler(handler);
693 impl::registerOemHandler(prio, iana, cmd, priv, h);
694}
695
Vernon Mauerye7329c72018-10-08 12:05:16 -0700696} // namespace ipmi
Vernon Mauerye08fbff2019-04-03 09:19:34 -0700697
698#ifdef ALLOW_DEPRECATED_API
699/**
700 * @brief legacy IPMI handler registration function
701 *
702 * This function should be used to register all legacy IPMI handler
703 * functions. This function just behaves just as the legacy registration
704 * mechanism did, silently replacing any existing handler with a new one.
705 *
706 * @param netFn - the IPMI net function number to register
707 * @param cmd - the IPMI command number to register
708 * @param context - ignored
709 * @param handler - the callback function that will handle this request
710 * @param priv - the IPMI user privilige required for this command
711 */
712// [[deprecated("Use ipmi::registerHandler() instead")]]
713void ipmi_register_callback(ipmi_netfn_t netFn, ipmi_cmd_t cmd,
714 ipmi_context_t context, ipmid_callback_t handler,
715 ipmi_cmd_privilege_t priv);
716
717#endif /* ALLOW_DEPRECATED_API */