From 4a58985ce0cfb24bc0eb8678a4aa9a0ac42ba524 Mon Sep 17 00:00:00 2001 From: Peter Hanson Date: Wed, 7 Jun 2017 17:40:45 -0700 Subject: Add OemRouter facility. OemRouter adds a facility to register OEM Group Message handlers, then dispatch matching messages to the registered handler. Added as a core source so that any dynamic provider can register its messages without requiring any specific load order. Includes code fixes for x86 portability. Change-Id: I47b8fe7873e3c7fdf35a00d3c8a7e17d30c398c4 Signed-off-by: Peter Hanson Signed-off-by: Patrick Venture --- oemrouter.cpp | 149 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 oemrouter.cpp (limited to 'oemrouter.cpp') diff --git a/oemrouter.cpp b/oemrouter.cpp new file mode 100644 index 0000000..273a679 --- /dev/null +++ b/oemrouter.cpp @@ -0,0 +1,149 @@ +#include +#include +#include +#include + +#include "host-ipmid/oemrouter.hpp" + +namespace oem +{ + +using Key = std::pair; + +// Private implementation of OemRouter Interface. +class RouterImpl : public Router +{ + public: + RouterImpl() {} + + // Implement OemRouter Interface. + void activate() override; + void registerHandler(Number oen, ipmi_cmd_t cmd, + Handler handler) override; + + // Actual message routing function. + ipmi_ret_t routeMsg(ipmi_cmd_t cmd, const uint8_t* reqBuf, + uint8_t* replyBuf, size_t* dataLen); + + private: + std::map handlers; +}; + +// Static global instance for simplicity. +static RouterImpl* globalRouterImpl; + +// TODO Refactor ipmid to avoid need for singleton here. +Router* mutableRouter() +{ + if (!globalRouterImpl) + { + globalRouterImpl = new RouterImpl; + } + return globalRouterImpl; +} + +ipmi_ret_t RouterImpl::routeMsg(ipmi_cmd_t cmd, const uint8_t* reqBuf, + uint8_t* replyBuf, size_t* dataLen) +{ + // Not entirely clear we can route reply without complete OEM group. + // TODO: consider adding a way to suppress malformed replies. + if (*dataLen < groupMagicSize) + { + fprintf(stderr, "NetFn:[0x2E], OEM:[%zu bytes?], Cmd:[%#04X]\n", + *dataLen, cmd); + (*dataLen) = 0; + return IPMI_CC_REQ_DATA_LEN_INVALID; + } + + // Find registered handler or reject request. + auto number = toOemNumber(reqBuf); + auto cmdKey = std::make_pair(number, cmd); + + auto iter = handlers.find(cmdKey); + if (iter == handlers.end()) + { + auto wildKey = std::make_pair(number, IPMI_CMD_WILDCARD); + iter = handlers.find(wildKey); + if (iter == handlers.end()) + { + fprintf(stderr, "No Registered handler for NetFn:[0x2E], " + "OEM:[%#08X], Cmd:[%#04X]\n", number, cmd); + *dataLen = groupMagicSize; + return IPMI_CC_INVALID; + } +#ifdef __IPMI_DEBUG__ + fprintf(stderr, "Wildcard NetFn:[0x2E], OEM:[%#08X], Cmd:[%#04X]\n", + number, cmd); +#endif + } + else + { +#ifdef __IPMI_DEBUG__ + fprintf(stderr, "Match NetFn:[0x2E], OEM:[%#08X], Cmd:[%#04X]\n", + number, cmd); +#endif + } + + // Copy OEMGroup here, by analogy to IPMI CC code at netfn router; + // OemHandler should deal only with optional following data bytes. + std::memcpy(replyBuf, reqBuf, groupMagicSize); + + size_t oemDataLen = *dataLen - groupMagicSize; + Handler& handler = iter->second; + + auto rc = handler(cmd, reqBuf + groupMagicSize, + replyBuf + groupMagicSize, &oemDataLen); + + // Add OEMGroup bytes to nominal reply. + *dataLen = oemDataLen + groupMagicSize; + return rc; +} + +// Function suitable for use as ipmi_netfn_router() call-back. +// Translates call-back pointer args to more specific types. +ipmi_ret_t ipmi_oem_wildcard_handler(ipmi_netfn_t /* netfn */, + ipmi_cmd_t cmd, ipmi_request_t request, + ipmi_response_t response, + ipmi_data_len_t dataLen, + ipmi_context_t context) +{ + // View requests & responses as byte sequences. + const uint8_t* reqBuf = static_cast(request); + uint8_t* replyBuf = static_cast(response); + + // View context as router object, defaulting nullptr to global object. + auto router = static_cast( + context ? context : mutableRouter()); + + // Send message parameters to dispatcher. + return router->routeMsg(cmd, reqBuf, replyBuf, dataLen); +} + +// Enable message routing to begin. +void RouterImpl::activate() +{ + // Register netfn 0x2e OEM Group, any (wildcard) command. + printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n", + NETFUN_OEM_GROUP, IPMI_CMD_WILDCARD); + ipmi_register_callback(NETFUN_OEM_GROUP, IPMI_CMD_WILDCARD, this, + ipmi_oem_wildcard_handler, PRIVILEGE_OEM); +} + +void RouterImpl::registerHandler(Number oen, ipmi_cmd_t cmd, + Handler handler) +{ + auto cmdKey = std::make_pair(oen, cmd); + auto iter = handlers.find(cmdKey); + if (iter == handlers.end()) + { + // Add handler if key not already taken. + handlers.emplace(cmdKey, handler); + } + else + { + fprintf(stderr, "ERROR : Duplicate registration for NetFn:[0x2E], " + "OEM:[%#08X], Cmd:[%#04X]\n", oen, cmd); + } +} + +} // namespace oem -- cgit v1.2.1