1 /**
2  * Copyright © 2018 Intel Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #define SD_JOURNAL_SUPPRESS_LOCATION
17 
18 #include <systemd/sd-journal.h>
19 
20 #include <ipmid/api.hpp>
21 #include <ipmid/message.hpp>
22 
23 #include <stdexcept>
24 
25 #include <gtest/gtest.h>
26 
TEST(Payload,InputSize)27 TEST(Payload, InputSize)
28 {
29     ipmi::SecureBuffer i = {0xbf, 0x04, 0x86, 0x00, 0x02};
30     size_t input_size = i.size();
31     ipmi::message::Payload p(std::forward<ipmi::SecureBuffer>(i));
32     ASSERT_EQ(input_size, p.size());
33 }
34 
TEST(Payload,OutputSize)35 TEST(Payload, OutputSize)
36 {
37     ipmi::message::Payload p;
38     ASSERT_EQ(0, p.size());
39     ipmi::SecureBuffer i = {0xbf, 0x04, 0x86, 0x00, 0x02};
40     p.pack(i);
41     ASSERT_EQ(i.size(), p.size());
42     p.pack(i);
43     p.pack(i);
44     ASSERT_EQ(3 * i.size(), p.size());
45 }
46 
TEST(Payload,Resize)47 TEST(Payload, Resize)
48 {
49     ipmi::SecureBuffer i = {0xbf, 0x04, 0x86, 0x00, 0x02};
50     ipmi::message::Payload p;
51     p.pack(i);
52     p.resize(16);
53     ASSERT_EQ(p.size(), 16);
54 }
55 
TEST(Payload,Data)56 TEST(Payload, Data)
57 {
58     ipmi::SecureBuffer i = {0xbf, 0x04, 0x86, 0x00, 0x02};
59     ipmi::message::Payload p;
60     p.pack(i);
61     ASSERT_NE(nullptr, p.data());
62 }
63 
TEST(PayloadResponse,Append)64 TEST(PayloadResponse, Append)
65 {
66     std::string s("0123456789abcdef");
67     ipmi::message::Payload p;
68     p.append(s.data(), s.data() + s.size());
69     ASSERT_EQ(s.size(), p.size());
70 }
71 
TEST(PayloadResponse,AppendDrain)72 TEST(PayloadResponse, AppendDrain)
73 {
74     std::string s("0123456789abcdef");
75     ipmi::message::Payload p;
76     bool b = true;
77     // first pack a lone bit
78     p.pack(b);
79     p.append(s.data(), s.data() + s.size());
80     // append will 'drain' first, padding the lone bit into a full byte
81     ASSERT_EQ(s.size() + 1, p.size());
82 }
83 
TEST(PayloadResponse,AppendBits)84 TEST(PayloadResponse, AppendBits)
85 {
86     ipmi::message::Payload p;
87     p.appendBits(3, 0b101);
88     ASSERT_EQ(p.bitStream, 0b101);
89     p.appendBits(4, 0b1100);
90     ASSERT_EQ(p.bitStream, 0b1100101);
91     p.appendBits(1, 0b1);
92     ASSERT_EQ(p.bitStream, 0);
93     ASSERT_EQ(p.bitCount, 0);
94     // appended 8 bits, should be one byte
95     ASSERT_EQ(p.size(), 1);
96     ipmi::SecureBuffer k1 = {0b11100101};
97     ASSERT_EQ(p.raw, k1);
98     p.appendBits(7, 0b1110111);
99     // appended 7 more bits, should still be one byte
100     ASSERT_EQ(p.size(), 1);
101     p.drain();
102     // drain forces padding; should be two bytes now
103     ASSERT_EQ(p.size(), 2);
104     ipmi::SecureBuffer k2 = {0b11100101, 0b01110111};
105     ASSERT_EQ(p.raw, k2);
106 }
107 
TEST(PayloadResponse,Drain16Bits)108 TEST(PayloadResponse, Drain16Bits)
109 {
110     ipmi::message::Payload p;
111     p.bitStream = 0b1011010011001111;
112     p.bitCount = 16;
113     p.drain();
114     ASSERT_EQ(p.size(), 2);
115     ASSERT_EQ(p.bitCount, 0);
116     ASSERT_EQ(p.bitStream, 0);
117     ipmi::SecureBuffer k1 = {0b11001111, 0b10110100};
118     ASSERT_EQ(p.raw, k1);
119 }
120 
TEST(PayloadResponse,Drain15Bits)121 TEST(PayloadResponse, Drain15Bits)
122 {
123     ipmi::message::Payload p;
124     p.bitStream = 0b101101001100111;
125     p.bitCount = 15;
126     p.drain();
127     ASSERT_EQ(p.size(), 2);
128     ASSERT_EQ(p.bitCount, 0);
129     ASSERT_EQ(p.bitStream, 0);
130     ipmi::SecureBuffer k1 = {0b1100111, 0b1011010};
131     ASSERT_EQ(p.raw, k1);
132 }
133 
TEST(PayloadResponse,Drain15BitsWholeBytesOnly)134 TEST(PayloadResponse, Drain15BitsWholeBytesOnly)
135 {
136     ipmi::message::Payload p;
137     p.bitStream = 0b101101001100111;
138     p.bitCount = 15;
139     p.drain(true);
140     // only the first whole byte should have been 'drained' into p.raw
141     ASSERT_EQ(p.size(), 1);
142     ASSERT_EQ(p.bitCount, 7);
143     ASSERT_EQ(p.bitStream, 0b1011010);
144     ipmi::SecureBuffer k1 = {0b1100111};
145     ASSERT_EQ(p.raw, k1);
146 }
147 
TEST(PayloadRequest,Pop)148 TEST(PayloadRequest, Pop)
149 {
150     ipmi::SecureBuffer i = {0xbf, 0x04, 0x86, 0x00, 0x02};
151     ipmi::message::Payload p(std::forward<ipmi::SecureBuffer>(i));
152     const auto& [vb, ve] = p.pop<uint8_t>(4);
153     std::vector<uint8_t> v(vb, ve);
154     std::vector<uint8_t> k = {0xbf, 0x04, 0x86, 0x00};
155     ASSERT_EQ(v, k);
156 }
157 
TEST(PayloadRequest,FillBits)158 TEST(PayloadRequest, FillBits)
159 {
160     ipmi::SecureBuffer i = {0xbf, 0x04, 0x86, 0x00, 0x02};
161     ipmi::message::Payload p(std::forward<ipmi::SecureBuffer>(i));
162     p.fillBits(5);
163     ASSERT_FALSE(p.unpackError);
164     ASSERT_EQ(p.bitStream, 0xbf);
165     ASSERT_EQ(p.bitCount, 8);
166     // should still have 5 bits available, no change
167     p.fillBits(5);
168     ASSERT_FALSE(p.unpackError);
169     ASSERT_EQ(p.bitStream, 0xbf);
170     ASSERT_EQ(p.bitCount, 8);
171     // discard 5 bits (low order)
172     p.popBits(5);
173     // should add another byte into the stream (high order)
174     p.fillBits(5);
175     ASSERT_FALSE(p.unpackError);
176     ASSERT_EQ(p.bitStream, 0x25);
177     ASSERT_EQ(p.bitCount, 11);
178 }
179 
TEST(PayloadRequest,FillBitsTooManyBits)180 TEST(PayloadRequest, FillBitsTooManyBits)
181 {
182     ipmi::SecureBuffer i = {1, 2, 3, 4, 5, 6, 7, 8, 9};
183     ipmi::message::Payload p(std::forward<ipmi::SecureBuffer>(i));
184     p.fillBits(72);
185     ASSERT_TRUE(p.unpackError);
186 }
187 
TEST(PayloadRequest,FillBitsNotEnoughBytes)188 TEST(PayloadRequest, FillBitsNotEnoughBytes)
189 {
190     ipmi::SecureBuffer i = {1, 2, 3, 4};
191     ipmi::message::Payload p(std::forward<ipmi::SecureBuffer>(i));
192     p.fillBits(48);
193     ASSERT_TRUE(p.unpackError);
194 }
195 
TEST(PayloadRequest,PopBits)196 TEST(PayloadRequest, PopBits)
197 {
198     ipmi::SecureBuffer i = {0xbf, 0x04, 0x86, 0x00, 0x02};
199     ipmi::message::Payload p(std::forward<ipmi::SecureBuffer>(i));
200     p.fillBits(4);
201     uint8_t v = p.popBits(4);
202     ASSERT_FALSE(p.unpackError);
203     ASSERT_EQ(p.bitStream, 0x0b);
204     ASSERT_EQ(p.bitCount, 4);
205     ASSERT_EQ(v, 0x0f);
206 }
207 
TEST(PayloadRequest,PopBitsNoFillBits)208 TEST(PayloadRequest, PopBitsNoFillBits)
209 {
210     ipmi::SecureBuffer i = {0xbf, 0x04, 0x86, 0x00, 0x02};
211     ipmi::message::Payload p(std::forward<ipmi::SecureBuffer>(i));
212     p.popBits(4);
213     ASSERT_TRUE(p.unpackError);
214 }
215 
TEST(PayloadRequest,DiscardBits)216 TEST(PayloadRequest, DiscardBits)
217 {
218     ipmi::SecureBuffer i = {0xbf, 0x04, 0x86, 0x00, 0x02};
219     ipmi::message::Payload p(std::forward<ipmi::SecureBuffer>(i));
220     p.fillBits(5);
221     ASSERT_FALSE(p.unpackError);
222     ASSERT_EQ(p.bitStream, 0xbf);
223     ASSERT_EQ(p.bitCount, 8);
224     p.discardBits();
225     ASSERT_FALSE(p.unpackError);
226     ASSERT_EQ(p.bitStream, 0);
227     ASSERT_EQ(p.bitCount, 0);
228 }
229 
TEST(PayloadRequest,FullyUnpacked)230 TEST(PayloadRequest, FullyUnpacked)
231 {
232     ipmi::SecureBuffer i = {0xbf, 0x04, 0x86, 0x00, 0x02};
233     ipmi::message::Payload p(std::forward<ipmi::SecureBuffer>(i));
234     uint32_t v1;
235     p.unpack(v1);
236     // still one remaining byte
237     ASSERT_FALSE(p.fullyUnpacked());
238     p.fillBits(3);
239     p.popBits(3);
240     // still five remaining bits
241     ASSERT_FALSE(p.fullyUnpacked());
242     p.fillBits(5);
243     p.popBits(5);
244     // fully unpacked, should be no errors
245     ASSERT_TRUE(p.fullyUnpacked());
246     p.fillBits(4);
247     // fullyUnpacked fails because an attempt to unpack too many bytes
248     ASSERT_FALSE(p.fullyUnpacked());
249 }
250 
TEST(PayloadRequest,ResetInternal)251 TEST(PayloadRequest, ResetInternal)
252 {
253     ipmi::SecureBuffer i = {0xbf, 0x04, 0x86, 0x00, 0x02};
254     ipmi::message::Payload p(std::forward<ipmi::SecureBuffer>(i));
255     p.fillBits(4);
256     p.unpackError = true;
257     p.reset();
258     ASSERT_EQ(p.rawIndex, 0);
259     ASSERT_EQ(p.bitStream, 0);
260     ASSERT_EQ(p.bitCount, 0);
261     ASSERT_FALSE(p.unpackError);
262 }
263 
TEST(PayloadRequest,ResetUsage)264 TEST(PayloadRequest, ResetUsage)
265 {
266     // Payload.reset is used to rewind the unpacking to the initial
267     // state. This is needed so that OEM commands can unpack the group
268     // number or the IANA to determine which handler needs to be called
269     ipmi::SecureBuffer i = {0x04, 0x86};
270     ipmi::message::Payload p(std::forward<ipmi::SecureBuffer>(i));
271     uint8_t v1;
272     // check that the number of bytes matches
273     ASSERT_EQ(p.unpack(v1), 0);
274     // check that the payload was not fully unpacked
275     ASSERT_FALSE(p.fullyUnpacked());
276     uint8_t k1 = 0x04;
277     // check that the bytes were correctly unpacked (LSB first)
278     ASSERT_EQ(v1, k1);
279     // do a reset on the payload
280     p.reset();
281     // unpack a uint16
282     uint16_t v2;
283     // check that the number of bytes matches
284     ASSERT_EQ(p.unpack(v2), 0);
285     // check that the payload was fully unpacked
286     ASSERT_TRUE(p.fullyUnpacked());
287     uint16_t k2 = 0x8604;
288     // check that the bytes were correctly unpacked (LSB first)
289     ASSERT_EQ(v2, k2);
290 }
291 
TEST(PayloadRequest,PartialPayload)292 TEST(PayloadRequest, PartialPayload)
293 {
294     ipmi::SecureBuffer i = {0xbf, 0x04, 0x86, 0x00, 0x02};
295     ipmi::message::Payload p(std::forward<ipmi::SecureBuffer>(i));
296     uint8_t v1;
297     ipmi::message::Payload localPayload;
298     // check that the number of bytes matches
299     ASSERT_EQ(p.unpack(v1, localPayload), 0);
300     // check that the payload was partially unpacked and not in error
301     ASSERT_FALSE(p.fullyUnpacked());
302     ASSERT_FALSE(p.unpackError);
303     // check that the 'extracted' payload is not fully unpacked
304     ASSERT_FALSE(localPayload.fullyUnpacked());
305     uint8_t k1 = 0xbf;
306     // check that the bytes were correctly unpacked (LSB first)
307     ASSERT_EQ(v1, k1);
308     uint32_t v2;
309     // unpack using the 'extracted' payload
310     ASSERT_EQ(localPayload.unpack(v2), 0);
311     ASSERT_TRUE(localPayload.fullyUnpacked());
312     uint32_t k2 = 0x02008604;
313     ASSERT_EQ(v2, k2);
314 }
315 
316 std::vector<std::string> logs;
317 
318 extern "C"
319 {
sd_journal_sendv(const struct iovec * iov,int)320 int sd_journal_sendv(const struct iovec* iov, int /* n */)
321 {
322     logs.push_back(std::string((char*)iov[0].iov_base, iov[0].iov_len));
323     return 0;
324 }
325 }
326 
327 class PayloadLogging : public testing::Test
328 {
329   public:
SetUp()330     void SetUp()
331     {
332         logs.clear();
333     }
334 };
335 
TEST_F(PayloadLogging,TrailingOk)336 TEST_F(PayloadLogging, TrailingOk)
337 {
338     {
339         ipmi::message::Payload p({1, 2});
340     }
341     EXPECT_EQ(logs.size(), 0);
342 }
343 
TEST_F(PayloadLogging,EnforcingUnchecked)344 TEST_F(PayloadLogging, EnforcingUnchecked)
345 {
346     {
347         ipmi::message::Payload p({1, 2});
348         p.trailingOk = false;
349     }
350     EXPECT_EQ(logs.size(), 1);
351 }
352 
TEST_F(PayloadLogging,EnforcingUncheckedUnpacked)353 TEST_F(PayloadLogging, EnforcingUncheckedUnpacked)
354 {
355     {
356         ipmi::message::Payload p({1, 2});
357         p.trailingOk = false;
358         uint8_t out;
359         p.unpack(out, out);
360     }
361     EXPECT_EQ(logs.size(), 1);
362 }
363 
TEST_F(PayloadLogging,EnforcingUncheckedError)364 TEST_F(PayloadLogging, EnforcingUncheckedError)
365 {
366     {
367         ipmi::message::Payload p({1, 2});
368         p.trailingOk = false;
369         uint32_t out;
370         p.unpack(out);
371     }
372     EXPECT_EQ(logs.size(), 0);
373 }
374 
TEST_F(PayloadLogging,EnforcingChecked)375 TEST_F(PayloadLogging, EnforcingChecked)
376 {
377     {
378         ipmi::message::Payload p({1, 2});
379         p.trailingOk = false;
380         EXPECT_FALSE(p.fullyUnpacked());
381     }
382     EXPECT_EQ(logs.size(), 0);
383 }
384 
TEST_F(PayloadLogging,EnforcingCheckedUnpacked)385 TEST_F(PayloadLogging, EnforcingCheckedUnpacked)
386 {
387     {
388         ipmi::message::Payload p({1, 2});
389         p.trailingOk = false;
390         uint8_t out;
391         p.unpack(out, out);
392         EXPECT_TRUE(p.fullyUnpacked());
393     }
394     EXPECT_EQ(logs.size(), 0);
395 }
396 
TEST_F(PayloadLogging,EnforcingUnpackPayload)397 TEST_F(PayloadLogging, EnforcingUnpackPayload)
398 {
399     {
400         ipmi::message::Payload p;
401         {
402             ipmi::message::Payload q({1, 2});
403             q.trailingOk = false;
404             q.unpack(p);
405         }
406         EXPECT_EQ(logs.size(), 0);
407     }
408     EXPECT_EQ(logs.size(), 1);
409 }
410 
TEST_F(PayloadLogging,EnforcingMove)411 TEST_F(PayloadLogging, EnforcingMove)
412 {
413     {
414         ipmi::message::Payload p;
415         {
416             ipmi::message::Payload q({1, 2});
417             q.trailingOk = false;
418             p = std::move(q);
419         }
420         EXPECT_EQ(logs.size(), 0);
421     }
422     EXPECT_EQ(logs.size(), 1);
423 }
424 
TEST_F(PayloadLogging,EnforcingException)425 TEST_F(PayloadLogging, EnforcingException)
426 {
427     try
428     {
429         ipmi::message::Payload p({1, 2});
430         p.trailingOk = false;
431         throw std::runtime_error("test");
432     }
433     catch (...)
434     {}
435     EXPECT_EQ(logs.size(), 0);
436 }
437