1 #include <ipmid/api.h>
2 
3 #include <cstring>
4 #include <ipmid/oemrouter.hpp>
5 
6 #include "sample.h"
7 
8 #include <gtest/gtest.h>
9 
10 // Watch for correct singleton behavior.
11 static oem::Router* singletonUnderTest;
12 
13 static ipmid_callback_t wildHandler;
14 
15 static ipmi_netfn_t lastNetFunction;
16 
17 // Fake ipmi_register_callback() for this test.
18 void ipmi_register_callback(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
19                             ipmi_context_t context, ipmid_callback_t cb,
20                             ipmi_cmd_privilege_t priv)
21 {
22     EXPECT_EQ(NETFUN_OEM_GROUP, netfn);
23     EXPECT_EQ(IPMI_CMD_WILDCARD, cmd);
24     EXPECT_EQ(reinterpret_cast<void*>(singletonUnderTest), context);
25     EXPECT_EQ(PRIVILEGE_OEM, priv);
26     lastNetFunction = netfn;
27     wildHandler = cb;
28 }
29 
30 namespace oem
31 {
32 
33 namespace
34 {
35 void MakeRouter()
36 {
37     if (!singletonUnderTest)
38     {
39         singletonUnderTest = mutableRouter();
40     }
41     ASSERT_EQ(singletonUnderTest, mutableRouter());
42 }
43 
44 void ActivateRouter()
45 {
46     MakeRouter();
47     singletonUnderTest->activate();
48     ASSERT_EQ(NETFUN_OEM_GROUP, lastNetFunction);
49 }
50 
51 void RegisterWithRouter(Number oen, ipmi_cmd_t cmd, Handler cb)
52 {
53     ActivateRouter();
54     singletonUnderTest->registerHandler(oen, cmd, cb);
55 }
56 
57 uint8_t msgPlain[] = {0x56, 0x34, 0x12};
58 uint8_t replyPlain[] = {0x56, 0x34, 0x12, 0x31, 0x41};
59 uint8_t msgPlus2[] = {0x67, 0x45, 0x23, 0x10, 0x20};
60 uint8_t msgBadOen[] = {0x57, 0x34, 0x12};
61 
62 void RegisterTwoWays(ipmi_cmd_t* nextCmd)
63 {
64     Handler f = [](ipmi_cmd_t cmd, const uint8_t* reqBuf, uint8_t* replyBuf,
65                    size_t* dataLen) {
66         // Check inputs
67         EXPECT_EQ(0x78, cmd);
68         EXPECT_EQ(0, *dataLen); // Excludes OEN
69 
70         // Generate reply.
71         *dataLen = 2;
72         std::memcpy(replyBuf, replyPlain + 3, *dataLen);
73         return 0;
74     };
75     RegisterWithRouter(0x123456, 0x78, f);
76 
77     *nextCmd = IPMI_CMD_WILDCARD;
78     Handler g = [nextCmd](ipmi_cmd_t cmd, const uint8_t* reqBuf,
79                           uint8_t* replyBuf, size_t* dataLen) {
80         // Check inputs
81         EXPECT_EQ(*nextCmd, cmd);
82         EXPECT_EQ(2, *dataLen); // Excludes OEN
83         if (2 != *dataLen)
84         {
85             return 0xE0;
86         }
87         EXPECT_EQ(msgPlus2[3], reqBuf[0]);
88         EXPECT_EQ(msgPlus2[4], reqBuf[1]);
89 
90         // Generate reply.
91         *dataLen = 0;
92         return 0;
93     };
94     RegisterWithRouter(0x234567, IPMI_CMD_WILDCARD, g);
95 }
96 } // namespace
97 
98 TEST(OemRouterTest, MakeRouterProducesConsistentSingleton)
99 {
100     MakeRouter();
101 }
102 
103 TEST(OemRouterTest, ActivateRouterSetsLastNetToOEMGROUP)
104 {
105     lastNetFunction = 0;
106     ActivateRouter();
107 }
108 
109 TEST(OemRouterTest, VerifiesSpecificCommandMatches)
110 {
111     ipmi_cmd_t cmd;
112     uint8_t reply[256];
113     size_t dataLen;
114 
115     RegisterTwoWays(&cmd);
116 
117     dataLen = 3;
118     EXPECT_EQ(0, wildHandler(NETFUN_OEM_GROUP, 0x78, msgPlain, reply, &dataLen,
119                              nullptr));
120     EXPECT_EQ(5, dataLen);
121     EXPECT_EQ(replyPlain[0], reply[0]);
122     EXPECT_EQ(replyPlain[1], reply[1]);
123     EXPECT_EQ(replyPlain[2], reply[2]);
124     EXPECT_EQ(replyPlain[3], reply[3]);
125     EXPECT_EQ(replyPlain[4], reply[4]);
126 }
127 
128 TEST(OemRouterTest, WildCardMatchesTwoRandomCodes)
129 {
130     ipmi_cmd_t cmd;
131     uint8_t reply[256];
132     size_t dataLen;
133 
134     RegisterTwoWays(&cmd);
135 
136     // Check two random command codes.
137     dataLen = 5;
138     cmd = 0x89;
139     EXPECT_EQ(0, wildHandler(NETFUN_OEM_GROUP, cmd, msgPlus2, reply, &dataLen,
140                              nullptr));
141     EXPECT_EQ(3, dataLen);
142 
143     dataLen = 5;
144     cmd = 0x67;
145     EXPECT_EQ(0, wildHandler(NETFUN_OEM_GROUP, cmd, msgPlus2, reply, &dataLen,
146                              nullptr));
147     EXPECT_EQ(3, dataLen);
148 }
149 
150 TEST(OemRouterTest, CommandsAreRejectedIfInvalid)
151 {
152     ipmi_cmd_t cmd;
153     uint8_t reply[256];
154     size_t dataLen;
155 
156     RegisterTwoWays(&cmd);
157 
158     // Message too short to include whole OEN?
159     dataLen = 2;
160     EXPECT_EQ(IPMI_CC_REQ_DATA_LEN_INVALID,
161               wildHandler(NETFUN_OEM_GROUP, 0x78, msgPlain, reply, &dataLen,
162                           nullptr));
163 
164     // Wrong specific command?
165     dataLen = 3;
166     EXPECT_EQ(IPMI_CC_INVALID, wildHandler(NETFUN_OEM_GROUP, 0x89, msgPlain,
167                                            reply, &dataLen, nullptr));
168 
169     // Wrong OEN?
170     dataLen = 3;
171     EXPECT_EQ(IPMI_CC_INVALID, wildHandler(NETFUN_OEM_GROUP, 0x78, msgBadOen,
172                                            reply, &dataLen, nullptr));
173 }
174 
175 } // namespace oem
176