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