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