summaryrefslogtreecommitdiffstats
path: root/oemrouter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'oemrouter.cpp')
-rw-r--r--oemrouter.cpp149
1 files changed, 149 insertions, 0 deletions
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 <cstdio>
+#include <cstring>
+#include <map>
+#include <utility>
+
+#include "host-ipmid/oemrouter.hpp"
+
+namespace oem
+{
+
+using Key = std::pair<Number, ipmi_cmd_t>;
+
+// 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<Key, Handler> 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<uint8_t*>(request);
+ uint8_t* replyBuf = static_cast<uint8_t*>(response);
+
+ // View context as router object, defaulting nullptr to global object.
+ auto router = static_cast<RouterImpl*>(
+ 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
OpenPOWER on IntegriCloud