blob: 64944db85f3bdad425f51b4e648f0a34d28ace6c [file] [log] [blame]
Patrick Venture0b02be92018-08-31 11:55:55 -07001#include "host-ipmid/oemrouter.hpp"
2
Peter Hanson4a589852017-06-07 17:40:45 -07003#include <cstdio>
4#include <cstring>
5#include <map>
6#include <utility>
7
Peter Hanson4a589852017-06-07 17:40:45 -07008namespace oem
9{
10
11using Key = std::pair<Number, ipmi_cmd_t>;
12
13// Private implementation of OemRouter Interface.
14class RouterImpl : public Router
15{
Patrick Venture0b02be92018-08-31 11:55:55 -070016 public:
17 RouterImpl()
18 {
19 }
Peter Hanson4a589852017-06-07 17:40:45 -070020
Patrick Venture0b02be92018-08-31 11:55:55 -070021 // Implement OemRouter Interface.
22 void activate() override;
23 void registerHandler(Number oen, ipmi_cmd_t cmd, Handler handler) override;
Peter Hanson4a589852017-06-07 17:40:45 -070024
Patrick Venture0b02be92018-08-31 11:55:55 -070025 // Actual message routing function.
26 ipmi_ret_t routeMsg(ipmi_cmd_t cmd, const uint8_t* reqBuf,
27 uint8_t* replyBuf, size_t* dataLen);
Peter Hanson4a589852017-06-07 17:40:45 -070028
Patrick Venture0b02be92018-08-31 11:55:55 -070029 private:
30 std::map<Key, Handler> handlers;
Peter Hanson4a589852017-06-07 17:40:45 -070031};
32
33// Static global instance for simplicity.
34static RouterImpl* globalRouterImpl;
35
36// TODO Refactor ipmid to avoid need for singleton here.
37Router* mutableRouter()
38{
39 if (!globalRouterImpl)
40 {
41 globalRouterImpl = new RouterImpl;
42 }
43 return globalRouterImpl;
44}
45
46ipmi_ret_t RouterImpl::routeMsg(ipmi_cmd_t cmd, const uint8_t* reqBuf,
47 uint8_t* replyBuf, size_t* dataLen)
48{
49 // Not entirely clear we can route reply without complete OEM group.
50 // TODO: consider adding a way to suppress malformed replies.
51 if (*dataLen < groupMagicSize)
52 {
53 fprintf(stderr, "NetFn:[0x2E], OEM:[%zu bytes?], Cmd:[%#04X]\n",
54 *dataLen, cmd);
55 (*dataLen) = 0;
56 return IPMI_CC_REQ_DATA_LEN_INVALID;
57 }
58
59 // Find registered handler or reject request.
60 auto number = toOemNumber(reqBuf);
61 auto cmdKey = std::make_pair(number, cmd);
62
63 auto iter = handlers.find(cmdKey);
64 if (iter == handlers.end())
65 {
66 auto wildKey = std::make_pair(number, IPMI_CMD_WILDCARD);
67 iter = handlers.find(wildKey);
68 if (iter == handlers.end())
69 {
Patrick Venture0b02be92018-08-31 11:55:55 -070070 fprintf(stderr,
71 "No Registered handler for NetFn:[0x2E], "
72 "OEM:[%#08X], Cmd:[%#04X]\n",
73 number, cmd);
Peter Hanson4a589852017-06-07 17:40:45 -070074 *dataLen = groupMagicSize;
75 return IPMI_CC_INVALID;
76 }
77#ifdef __IPMI_DEBUG__
78 fprintf(stderr, "Wildcard NetFn:[0x2E], OEM:[%#08X], Cmd:[%#04X]\n",
79 number, cmd);
80#endif
81 }
82 else
83 {
84#ifdef __IPMI_DEBUG__
85 fprintf(stderr, "Match NetFn:[0x2E], OEM:[%#08X], Cmd:[%#04X]\n",
86 number, cmd);
87#endif
88 }
89
90 // Copy OEMGroup here, by analogy to IPMI CC code at netfn router;
91 // OemHandler should deal only with optional following data bytes.
92 std::memcpy(replyBuf, reqBuf, groupMagicSize);
93
94 size_t oemDataLen = *dataLen - groupMagicSize;
95 Handler& handler = iter->second;
96
Patrick Venture0b02be92018-08-31 11:55:55 -070097 auto rc = handler(cmd, reqBuf + groupMagicSize, replyBuf + groupMagicSize,
98 &oemDataLen);
Peter Hanson4a589852017-06-07 17:40:45 -070099
100 // Add OEMGroup bytes to nominal reply.
101 *dataLen = oemDataLen + groupMagicSize;
102 return rc;
103}
104
105// Function suitable for use as ipmi_netfn_router() call-back.
106// Translates call-back pointer args to more specific types.
Patrick Venture0b02be92018-08-31 11:55:55 -0700107ipmi_ret_t ipmi_oem_wildcard_handler(ipmi_netfn_t /* netfn */, ipmi_cmd_t cmd,
108 ipmi_request_t request,
Peter Hanson4a589852017-06-07 17:40:45 -0700109 ipmi_response_t response,
110 ipmi_data_len_t dataLen,
111 ipmi_context_t context)
112{
113 // View requests & responses as byte sequences.
114 const uint8_t* reqBuf = static_cast<uint8_t*>(request);
115 uint8_t* replyBuf = static_cast<uint8_t*>(response);
116
117 // View context as router object, defaulting nullptr to global object.
Patrick Venture0b02be92018-08-31 11:55:55 -0700118 auto router = static_cast<RouterImpl*>(context ? context : mutableRouter());
Peter Hanson4a589852017-06-07 17:40:45 -0700119
120 // Send message parameters to dispatcher.
121 return router->routeMsg(cmd, reqBuf, replyBuf, dataLen);
122}
123
124// Enable message routing to begin.
125void RouterImpl::activate()
126{
127 // Register netfn 0x2e OEM Group, any (wildcard) command.
Patrick Venture0b02be92018-08-31 11:55:55 -0700128 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n", NETFUN_OEM_GROUP,
129 IPMI_CMD_WILDCARD);
Peter Hanson4a589852017-06-07 17:40:45 -0700130 ipmi_register_callback(NETFUN_OEM_GROUP, IPMI_CMD_WILDCARD, this,
131 ipmi_oem_wildcard_handler, PRIVILEGE_OEM);
132}
133
Patrick Venture0b02be92018-08-31 11:55:55 -0700134void RouterImpl::registerHandler(Number oen, ipmi_cmd_t cmd, Handler handler)
Peter Hanson4a589852017-06-07 17:40:45 -0700135{
136 auto cmdKey = std::make_pair(oen, cmd);
137 auto iter = handlers.find(cmdKey);
138 if (iter == handlers.end())
139 {
140 // Add handler if key not already taken.
141 handlers.emplace(cmdKey, handler);
142 }
143 else
144 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700145 fprintf(stderr,
146 "ERROR : Duplicate registration for NetFn:[0x2E], "
147 "OEM:[%#08X], Cmd:[%#04X]\n",
148 oen, cmd);
Peter Hanson4a589852017-06-07 17:40:45 -0700149 }
150}
151
Patrick Venture0b02be92018-08-31 11:55:55 -0700152} // namespace oem