diff options
Diffstat (limited to 'include/ipmid')
-rw-r--r-- | include/ipmid/handler.hpp | 106 | ||||
-rw-r--r-- | include/ipmid/registration.hpp | 79 |
2 files changed, 185 insertions, 0 deletions
diff --git a/include/ipmid/handler.hpp b/include/ipmid/handler.hpp index 203dcad..0c65436 100644 --- a/include/ipmid/handler.hpp +++ b/include/ipmid/handler.hpp @@ -354,6 +354,94 @@ class IpmiHandler<ipmid_callback_t> final : public HandlerBase }; /** + * @brief Legacy IPMI OEM handler class + * + * Legacy IPMI OEM handlers will resolve into this class, which will behave the + * same way as the legacy IPMI queue, passing in a big buffer for the request + * and a big buffer for the response. + * + * As soon as all the handlers have been rewritten, this class will be marked as + * deprecated and eventually removed. + */ +template <> +class IpmiHandler<oem::Handler> final : public HandlerBase +{ + public: + explicit IpmiHandler(const oem::Handler& handler) : handler_(handler) + { + } + + private: + oem::Handler handler_; + + /** @brief call the registered handler with the request + * + * This is called from the running queue context after it has already + * created a request object that contains all the information required to + * execute the ipmi command. This function will return the response object + * pointer that owns the response object that will ultimately get sent back + * to the requester. + * + * Because this is the legacy variety of IPMI handler, this function does + * not really have to do much other than pass the payload to the callback + * and return response to the caller. + * + * @param request a shared_ptr to a Request object + * + * @return a shared_ptr to a Response object + */ + message::Response::ptr + executeCallback(message::Request::ptr request) override + { + message::Response::ptr response = request->makeResponse(); + size_t len = request->payload.size(); + // allocate a big response buffer here + response->payload.resize( + getChannelMaxTransferSize(request->ctx->channel)); + + Cc ccRet{ccSuccess}; + try + { + ccRet = handler_(request->ctx->cmd, request->payload.data(), + response->payload.data(), &len); + } + catch (const std::exception& e) + { + phosphor::logging::log<phosphor::logging::level::ERR>( + "Legacy OEM Handler failed to catch exception", + phosphor::logging::entry("EXCEPTION=%s", e.what()), + phosphor::logging::entry("NETFN=%x", request->ctx->netFn), + phosphor::logging::entry("CMD=%x", request->ctx->cmd)); + return errorResponse(request, ccUnspecifiedError); + } + catch (...) + { + std::exception_ptr eptr; + try + { + eptr = std::current_exception(); + if (eptr) + { + std::rethrow_exception(eptr); + } + } + catch (const std::exception& e) + { + phosphor::logging::log<phosphor::logging::level::ERR>( + "Handler failed to catch exception", + phosphor::logging::entry("EXCEPTION=%s", e.what()), + phosphor::logging::entry("NETFN=%x", request->ctx->netFn), + phosphor::logging::entry("CMD=%x", request->ctx->cmd)); + return errorResponse(request, ccUnspecifiedError); + } + } + response->cc = ccRet; + response->payload.resize(len); + return response; + } +}; + +/** * @brief create a legacy IPMI handler class and return a shared_ptr * * The queue uses a map of pointers to do the lookup. This function returns the @@ -371,6 +459,24 @@ inline auto makeLegacyHandler(const ipmid_callback_t& handler) return ptr; } +/** + * @brief create a legacy IPMI OEM handler class and return a shared_ptr + * + * The queue uses a map of pointers to do the lookup. This function returns the + * shared_ptr that owns the Handler object. + * + * This is called internally via the Router::registerHandler method. + * + * @param handler the function pointer to the callback + * + * @return A shared_ptr to the created handler object + */ +inline auto makeLegacyHandler(oem::Handler&& handler) +{ + HandlerBase::ptr ptr( + new IpmiHandler<oem::Handler>(std::forward<oem::Handler>(handler))); + return ptr; +} #endif // ALLOW_DEPRECATED_API /** diff --git a/include/ipmid/registration.hpp b/include/ipmid/registration.hpp index 151aca1..af89bc8 100644 --- a/include/ipmid/registration.hpp +++ b/include/ipmid/registration.hpp @@ -27,6 +27,11 @@ namespace impl // IPMI command handler registration implementation bool registerHandler(int prio, NetFn netFn, Cmd cmd, Privilege priv, ::ipmi::HandlerBase::ptr handler); +bool registerGroupHandler(int prio, Group group, Cmd cmd, Privilege priv, + ::ipmi::HandlerBase::ptr handler); +bool registerOemHandler(int prio, Iana iana, Cmd cmd, Privilege priv, + ::ipmi::HandlerBase::ptr handler); + } // namespace impl /** @@ -53,6 +58,80 @@ bool registerHandler(int prio, NetFn netFn, Cmd cmd, Privilege priv, return impl::registerHandler(prio, netFn, cmd, priv, h); } +/** + * @brief register a IPMI OEM group handler + * + * From IPMI 2.0 spec Network Function Codes Table (Row 2Ch): + * The first data byte position in requests and responses under this network + * function identifies the defining body that specifies command functionality. + * Software assumes that the command and completion code field positions will + * hold command and completion code values. + * + * The following values are used to identify the defining body: + * 00h PICMG - PCI Industrial Computer Manufacturer’s Group. (www.picmg.com) + * 01h DMTF Pre-OS Working Group ASF Specification (www.dmtf.org) + * 02h Server System Infrastructure (SSI) Forum (www.ssiforum.org) + * 03h VITA Standards Organization (VSO) (www.vita.com) + * DCh DCMI Specifications (www.intel.com/go/dcmi) + * all other Reserved + * + * When this network function is used, the ID for the defining body occupies + * the first data byte in a request, and the second data byte (following the + * completion code) in a response. + * + * @tparam Handler - implicitly specified callback function type + * @param prio - priority at which to register; see api.hpp + * @param netFn - the IPMI net function number to register + * @param cmd - the IPMI command number to register + * @param priv - the IPMI user privilige required for this command + * @param handler - the callback function that will handle this request + * + * @return bool - success of registering the handler + * + */ +template <typename Handler> +void registerGroupHandler(int prio, Group group, Cmd cmd, Privilege priv, + Handler&& handler) +{ + auto h = ipmi::makeHandler(handler); + impl::registerGroupHandler(prio, group, cmd, priv, h); +} + +/** + * @brief register a IPMI OEM IANA handler + * + * From IPMI spec Network Function Codes Table (Row 2Eh): + * The first three data bytes of requests and responses under this network + * function explicitly identify the OEM or non-IPMI group that specifies the + * command functionality. While the OEM or non-IPMI group defines the + * functional semantics for the cmd and remaining data fields, the cmd field + * is required to hold the same value in requests and responses for a given + * operation in order to be supported under the IPMI message handling and + * transport mechanisms. + * + * When this network function is used, the IANA Enterprise Number for the + * defining body occupies the first three data bytes in a request, and the + * first three data bytes following the completion code position in a + * response. + * + * @tparam Handler - implicitly specified callback function type + * @param prio - priority at which to register; see api.hpp + * @param netFn - the IPMI net function number to register + * @param cmd - the IPMI command number to register + * @param priv - the IPMI user privilige required for this command + * @param handler - the callback function that will handle this request + * + * @return bool - success of registering the handler + * + */ +template <typename Handler> +void registerOemHandler(int prio, Iana iana, Cmd cmd, Privilege priv, + Handler&& handler) +{ + auto h = ipmi::makeHandler(handler); + impl::registerOemHandler(prio, iana, cmd, priv, h); +} + } // namespace ipmi #ifdef ALLOW_DEPRECATED_API |