xref: /openbmc/phosphor-host-ipmid/test/message/pack.cpp (revision 1318a5ed36cfd41335e687b54db1c17c0dde8f45)
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  #include <ipmid/api.hpp>
17  #include <ipmid/message.hpp>
18  
19  #include <gtest/gtest.h>
20  
21  // TODO: Add testing of Payload response API
22  
TEST(PackBasics,Uint8)23  TEST(PackBasics, Uint8)
24  {
25      ipmi::message::Payload p;
26      uint8_t v = 4;
27      p.pack(v);
28      // check that the number of bytes matches
29      ASSERT_EQ(p.size(), sizeof(v));
30      // check that the bytes were correctly packed (LSB first)
31      ipmi::SecureBuffer k = {0x04};
32      ASSERT_EQ(p.raw, k);
33  }
34  
TEST(PackBasics,Uint16)35  TEST(PackBasics, Uint16)
36  {
37      ipmi::message::Payload p;
38      uint16_t v = 0x8604;
39      p.pack(v);
40      // check that the number of bytes matches
41      ASSERT_EQ(p.size(), sizeof(v));
42      // check that the bytes were correctly packed (LSB first)
43      ipmi::SecureBuffer k = {0x04, 0x86};
44      ASSERT_EQ(p.raw, k);
45  }
46  
TEST(PackBasics,Uint32)47  TEST(PackBasics, Uint32)
48  {
49      ipmi::message::Payload p;
50      uint32_t v = 0x02008604;
51      p.pack(v);
52      // check that the number of bytes matches
53      ASSERT_EQ(p.size(), sizeof(v));
54      // check that the bytes were correctly packed (LSB first)
55      ipmi::SecureBuffer k = {0x04, 0x86, 0x00, 0x02};
56      ASSERT_EQ(p.raw, k);
57  }
58  
TEST(PackBasics,Uint64)59  TEST(PackBasics, Uint64)
60  {
61      ipmi::message::Payload p;
62      uint64_t v = 0x1122334402008604ull;
63      p.pack(v);
64      // check that the number of bytes matches
65      ASSERT_EQ(p.size(), sizeof(v));
66      // check that the bytes were correctly packed (LSB first)
67      ipmi::SecureBuffer k = {0x04, 0x86, 0x00, 0x02, 0x44, 0x33, 0x22, 0x11};
68      ASSERT_EQ(p.raw, k);
69  }
70  
TEST(PackBasics,Uint24)71  TEST(PackBasics, Uint24)
72  {
73      ipmi::message::Payload p;
74      uint24_t v = 0x112358;
75      p.pack(v);
76      // check that the number of bytes matches
77      ASSERT_EQ(p.size(), types::nrFixedBits<decltype(v)> / CHAR_BIT);
78      // check that the bytes were correctly packed (LSB first)
79      ipmi::SecureBuffer k = {0x58, 0x23, 0x11};
80      ASSERT_EQ(p.raw, k);
81  }
82  
TEST(PackBasics,Uint3Uint5)83  TEST(PackBasics, Uint3Uint5)
84  {
85      // individual bytes are packed low-order-bits first
86      // v1 will occupy [2:0], v2 will occupy [7:3]
87      ipmi::message::Payload p;
88      uint3_t v1 = 0x1;
89      uint5_t v2 = 0x19;
90      p.pack(v1, v2);
91      // check that the number of bytes matches
92      ASSERT_EQ(p.size(), (types::nrFixedBits<decltype(v1)> +
93                           types::nrFixedBits<decltype(v2)>) /
94                              CHAR_BIT);
95      // check that the bytes were correctly packed (LSB first)
96      ipmi::SecureBuffer k = {0xc9};
97      ASSERT_EQ(p.raw, k);
98  }
99  
TEST(PackBasics,Boolx8)100  TEST(PackBasics, Boolx8)
101  {
102      // individual bytes are packed low-order-bits first
103      // [v8, v7, v6, v5, v4, v3, v2, v1]
104      ipmi::message::Payload p;
105      bool v8 = true, v7 = true, v6 = false, v5 = false;
106      bool v4 = true, v3 = false, v2 = false, v1 = true;
107      p.pack(v1, v2, v3, v4, v5, v6, v7, v8);
108      // check that the number of bytes matches
109      ASSERT_EQ(p.size(), sizeof(uint8_t));
110      // check that the bytes were correctly packed (LSB first)
111      ipmi::SecureBuffer k = {0xc9};
112      ASSERT_EQ(p.raw, k);
113  }
114  
TEST(PackBasics,Bitset8)115  TEST(PackBasics, Bitset8)
116  {
117      // individual bytes are packed low-order-bits first
118      // a bitset for 8 bits fills the full byte
119      ipmi::message::Payload p;
120      std::bitset<8> v(0xc9);
121      p.pack(v);
122      // check that the number of bytes matches
123      ASSERT_EQ(p.size(), v.size() / CHAR_BIT);
124      // check that the bytes were correctly packed (LSB first)
125      ipmi::SecureBuffer k = {0xc9};
126      ASSERT_EQ(p.raw, k);
127  }
128  
TEST(PackBasics,Bitset3Bitset5)129  TEST(PackBasics, Bitset3Bitset5)
130  {
131      // individual bytes are packed low-order-bits first
132      // v1 will occupy [2:0], v2 will occupy [7:3]
133      ipmi::message::Payload p;
134      std::bitset<3> v1(0x1);
135      std::bitset<5> v2(0x19);
136      p.pack(v1, v2);
137      // check that the number of bytes matches
138      ASSERT_EQ(p.size(), (v1.size() + v2.size()) / CHAR_BIT);
139      // check that the bytes were correctly packed (LSB first)
140      ipmi::SecureBuffer k = {0xc9};
141      ASSERT_EQ(p.raw, k);
142  }
143  
TEST(PackBasics,Bitset32)144  TEST(PackBasics, Bitset32)
145  {
146      // individual bytes are packed low-order-bits first
147      // v1 will occupy 4 bytes, but in LSByte first order
148      // v1[7:0] v1[15:9] v1[23:16] v1[31:24]
149      ipmi::message::Payload p;
150      std::bitset<32> v(0x02008604);
151      p.pack(v);
152      // check that the number of bytes matches
153      ASSERT_EQ(p.size(), v.size() / CHAR_BIT);
154      // check that the bytes were correctly packed (LSB first)
155      ipmi::SecureBuffer k = {0x04, 0x86, 0x00, 0x02};
156      ASSERT_EQ(p.raw, k);
157  }
158  
TEST(PackBasics,Tuple)159  TEST(PackBasics, Tuple)
160  {
161      // tuples are the new struct, pack a tuple
162      ipmi::message::Payload p;
163      auto v = std::make_tuple(static_cast<uint16_t>(0x8604), 'A');
164      p.pack(v);
165      // check that the number of bytes matches
166      ASSERT_EQ(p.size(), sizeof(uint16_t) + sizeof(char));
167      // check that the bytes were correctly packed (LSB first)
168      ipmi::SecureBuffer k = {0x04, 0x86, 0x41};
169      ASSERT_EQ(p.raw, k);
170  }
171  
TEST(PackBasics,Array4xUint8)172  TEST(PackBasics, Array4xUint8)
173  {
174      // an array of bytes will be output verbatim, low-order element first
175      ipmi::message::Payload p;
176      std::array<uint8_t, 4> v = {{0x02, 0x00, 0x86, 0x04}};
177      p.pack(v);
178      // check that the number of bytes matches
179      ASSERT_EQ(p.size(), v.size() * sizeof(v[0]));
180      // check that the bytes were correctly packed (in byte order)
181      ipmi::SecureBuffer k = {0x02, 0x00, 0x86, 0x04};
182      ASSERT_EQ(p.raw, k);
183  }
184  
TEST(PackBasics,Array4xUint32)185  TEST(PackBasics, Array4xUint32)
186  {
187      // an array of multi-byte values will be output in order low-order
188      // element first, each multi-byte element in LSByte order
189      // v[0][7:0] v[0][15:9] v[0][23:16] v[0][31:24]
190      // v[1][7:0] v[1][15:9] v[1][23:16] v[1][31:24]
191      // v[2][7:0] v[2][15:9] v[2][23:16] v[2][31:24]
192      // v[3][7:0] v[3][15:9] v[3][23:16] v[3][31:24]
193      ipmi::message::Payload p;
194      std::array<uint32_t, 4> v = {
195          {0x11223344, 0x22446688, 0x33557799, 0x12345678}};
196      p.pack(v);
197      // check that the number of bytes matches
198      ASSERT_EQ(p.size(), v.size() * sizeof(v[0]));
199      // check that the bytes were correctly packed (in byte order)
200      ipmi::SecureBuffer k = {0x44, 0x33, 0x22, 0x11, 0x88, 0x66, 0x44, 0x22,
201                              0x99, 0x77, 0x55, 0x33, 0x78, 0x56, 0x34, 0x12};
202      ASSERT_EQ(p.raw, k);
203  }
204  
TEST(PackBasics,VectorUint32)205  TEST(PackBasics, VectorUint32)
206  {
207      // a vector of multi-byte values will be output in order low-order
208      // element first, each multi-byte element in LSByte order
209      // v[0][7:0] v[0][15:9] v[0][23:16] v[0][31:24]
210      // v[1][7:0] v[1][15:9] v[1][23:16] v[1][31:24]
211      // v[2][7:0] v[2][15:9] v[2][23:16] v[2][31:24]
212      // v[3][7:0] v[3][15:9] v[3][23:16] v[3][31:24]
213      ipmi::message::Payload p;
214      std::vector<uint32_t> v = {
215          {0x11223344, 0x22446688, 0x33557799, 0x12345678}};
216      p.pack(v);
217      // check that the number of bytes matches
218      ASSERT_EQ(p.size(), v.size() * sizeof(v[0]));
219      // check that the bytes were correctly packed (in byte order)
220      ipmi::SecureBuffer k = {0x44, 0x33, 0x22, 0x11, 0x88, 0x66, 0x44, 0x22,
221                              0x99, 0x77, 0x55, 0x33, 0x78, 0x56, 0x34, 0x12};
222      ASSERT_EQ(p.raw, k);
223  }
224  
TEST(PackBasics,VectorUint8)225  TEST(PackBasics, VectorUint8)
226  {
227      // a vector of bytes will be output verbatim, low-order element first
228      ipmi::message::Payload p;
229      std::vector<uint8_t> v = {0x02, 0x00, 0x86, 0x04};
230      p.pack(v);
231      // check that the number of bytes matches
232      ASSERT_EQ(p.size(), v.size() * sizeof(v[0]));
233      // check that the bytes were correctly packed (in byte order)
234      ipmi::SecureBuffer k = {0x02, 0x00, 0x86, 0x04};
235      ASSERT_EQ(p.raw, k);
236  }
237  
TEST(PackBasics,VectorUnaligned)238  TEST(PackBasics, VectorUnaligned)
239  {
240      ipmi::message::Payload p;
241      EXPECT_EQ(p.pack(true, std::vector<uint8_t>{1}), 1);
242      EXPECT_EQ(p.raw, ipmi::SecureBuffer{0b1});
243  }
244  
TEST(PackBasics,StringView)245  TEST(PackBasics, StringView)
246  {
247      ipmi::message::Payload p;
248      EXPECT_EQ(p.pack(std::string_view{"\x24\x30\x11"}), 0);
249      EXPECT_EQ(p.raw, ipmi::SecureBuffer({0x24, 0x30, 0x11}));
250  }
251  
TEST(PackBasics,StringViewUnaligned)252  TEST(PackBasics, StringViewUnaligned)
253  {
254      ipmi::message::Payload p;
255      EXPECT_EQ(p.pack(true, std::string_view{"abc"}), 1);
256      EXPECT_EQ(p.raw, ipmi::SecureBuffer({0b1}));
257  }
258  
TEST(PackBasics,OptionalEmpty)259  TEST(PackBasics, OptionalEmpty)
260  {
261      // an optional will only pack if the value is present
262      ipmi::message::Payload p;
263      std::optional<uint32_t> v;
264      p.pack(v);
265      // check that the number of bytes matches
266      ASSERT_EQ(p.size(), 0);
267      // check that the bytes were correctly packed (in byte order)
268      ipmi::SecureBuffer k = {};
269      ASSERT_EQ(p.raw, k);
270  }
271  
TEST(PackBasics,OptionalContainsValue)272  TEST(PackBasics, OptionalContainsValue)
273  {
274      // an optional will only pack if the value is present
275      ipmi::message::Payload p;
276      std::optional<uint32_t> v(0x04860002);
277      p.pack(v);
278      // check that the number of bytes matches
279      ASSERT_EQ(p.size(), sizeof(uint32_t));
280      // check that the bytes were correctly packed (in byte order)
281      ipmi::SecureBuffer k = {0x02, 0x00, 0x86, 0x04};
282      ASSERT_EQ(p.raw, k);
283  }
284  
TEST(PackBasics,Payload)285  TEST(PackBasics, Payload)
286  {
287      ipmi::message::Payload p;
288      EXPECT_EQ(p.pack(true), 0);
289      EXPECT_EQ(p.pack(ipmi::message::Payload({0x24, 0x30})), 0);
290      EXPECT_EQ(p.raw, ipmi::SecureBuffer({0b1, 0x24, 0x30}));
291  }
292  
TEST(PackBasics,PayloadUnaligned)293  TEST(PackBasics, PayloadUnaligned)
294  {
295      ipmi::message::Payload p;
296      EXPECT_EQ(p.pack(true, ipmi::message::Payload({0x24})), 1);
297      EXPECT_EQ(p.raw, ipmi::SecureBuffer({0b1}));
298  }
299  
TEST(PackBasics,PayloadOtherUnaligned)300  TEST(PackBasics, PayloadOtherUnaligned)
301  {
302      ipmi::message::Payload p, q;
303      q.appendBits(1, 1);
304      EXPECT_EQ(p.pack(true), 0);
305      EXPECT_EQ(p.pack(q), 1);
306      EXPECT_EQ(p.raw, ipmi::SecureBuffer({0b1}));
307  }
308  
TEST(PackBasics,PrependPayload)309  TEST(PackBasics, PrependPayload)
310  {
311      ipmi::message::Payload p;
312      EXPECT_EQ(p.pack(true), 0);
313      EXPECT_EQ(p.prepend(ipmi::message::Payload({0x24, 0x30})), 0);
314      EXPECT_EQ(p.raw, ipmi::SecureBuffer({0x24, 0x30, 0b1}));
315  }
316  
TEST(PackBasics,PrependPayloadUnaligned)317  TEST(PackBasics, PrependPayloadUnaligned)
318  {
319      ipmi::message::Payload p;
320      p.appendBits(1, 1);
321      EXPECT_EQ(p.prepend(ipmi::message::Payload({0x24})), 1);
322      p.drain();
323      EXPECT_EQ(p.raw, ipmi::SecureBuffer({0b1}));
324  }
325  
TEST(PackBasics,PrependPayloadOtherUnaligned)326  TEST(PackBasics, PrependPayloadOtherUnaligned)
327  {
328      ipmi::message::Payload p, q;
329      q.appendBits(1, 1);
330      EXPECT_EQ(p.pack(true), 0);
331      EXPECT_EQ(p.prepend(q), 1);
332      EXPECT_EQ(p.raw, ipmi::SecureBuffer({0b1}));
333  }
334  
TEST(PackAdvanced,Uints)335  TEST(PackAdvanced, Uints)
336  {
337      // all elements will be processed in order, with each multi-byte
338      // element being processed LSByte first
339      // v1[7:0] v2[7:0] v2[15:8] v3[7:0] v3[15:8] v3[23:16] v3[31:24]
340      // v4[7:0] v4[15:8] v4[23:16] v4[31:24]
341      // v4[39:25] v4[47:40] v4[55:48] v4[63:56]
342      ipmi::message::Payload p;
343      uint8_t v1 = 0x02;
344      uint16_t v2 = 0x0604;
345      uint32_t v3 = 0x44332211;
346      uint64_t v4 = 0xccbbaa9988776655ull;
347      p.pack(v1, v2, v3, v4);
348      // check that the number of bytes matches
349      ASSERT_EQ(p.size(), sizeof(v1) + sizeof(v2) + sizeof(v3) + sizeof(v4));
350      // check that the bytes were correctly packed (LSB first)
351      ipmi::SecureBuffer k = {0x02, 0x04, 0x06, 0x11, 0x22, 0x33, 0x44, 0x55,
352                              0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc};
353      ASSERT_EQ(p.raw, k);
354  }
355  
TEST(PackAdvanced,TupleInts)356  TEST(PackAdvanced, TupleInts)
357  {
358      // all elements will be processed in order, with each multi-byte
359      // element being processed LSByte first
360      // v1[7:0] v2[7:0] v2[15:8] v3[7:0] v3[15:8] v3[23:16] v3[31:24]
361      // v4[7:0] v4[15:8] v4[23:16] v4[31:24]
362      // v4[39:25] v4[47:40] v4[55:48] v4[63:56]
363      ipmi::message::Payload p;
364      uint8_t v1 = 0x02;
365      uint16_t v2 = 0x0604;
366      uint32_t v3 = 0x44332211;
367      uint64_t v4 = 0xccbbaa9988776655ull;
368      auto v = std::make_tuple(v1, v2, v3, v4);
369      p.pack(v);
370      // check that the number of bytes matches
371      ASSERT_EQ(p.size(), sizeof(v1) + sizeof(v2) + sizeof(v3) + sizeof(v4));
372      // check that the bytes were correctly packed (LSB first)
373      ipmi::SecureBuffer k = {0x02, 0x04, 0x06, 0x11, 0x22, 0x33, 0x44, 0x55,
374                              0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc};
375      ASSERT_EQ(p.raw, k);
376  }
377  
TEST(PackAdvanced,VariantArray)378  TEST(PackAdvanced, VariantArray)
379  {
380      ipmi::message::Payload p;
381      std::variant<std::array<uint8_t, 2>, uint32_t> variant;
382      auto data = std::array<uint8_t, 2>{2, 4};
383      variant = data;
384  
385      p.pack(variant);
386      ASSERT_EQ(p.size(), sizeof(data));
387  
388      // check that the bytes were correctly packed packed (LSB first)
389      ipmi::SecureBuffer k = {2, 4};
390      ASSERT_EQ(p.raw, k);
391  }
392  
TEST(PackAdvanced,BoolsnBitfieldsnFixedIntsOhMy)393  TEST(PackAdvanced, BoolsnBitfieldsnFixedIntsOhMy)
394  {
395      // each element will be added, filling the low-order bits first
396      // with multi-byte values getting added LSByte first
397      // v1 will occupy k[0][1:0]
398      // v2 will occupy k[0][2]
399      // v3[4:0] will occupy k[0][7:3], v3[6:5] will occupy k[1][1:0]
400      // v4 will occupy k[1][2]
401      // v5 will occupy k[1][7:3]
402      ipmi::message::Payload p;
403      uint2_t v1 = 2;          // binary 0b10
404      bool v2 = true;          // binary 0b1
405      std::bitset<7> v3(0x73); // binary 0b1110011
406      bool v4 = false;         // binary 0b0
407      uint5_t v5 = 27;         // binary 0b11011
408      // concat binary: 0b1101101110011110 -> 0xdb9e -> 0x9e 0xdb (LSByte first)
409      p.pack(v1, v2, v3, v4, v5);
410      // check that the number of bytes matches
411      ASSERT_EQ(p.size(), sizeof(uint16_t));
412      // check that the bytes were correctly packed (LSB first)
413      ipmi::SecureBuffer k = {0x9e, 0xdb};
414      ASSERT_EQ(p.raw, k);
415  }
416  
TEST(PackAdvanced,UnalignedBitPacking)417  TEST(PackAdvanced, UnalignedBitPacking)
418  {
419      // unaligned multi-byte values will be packed the same as
420      // other bits, effectively building up a large value, low-order
421      // bits first, then outputting a stream of LSByte values
422      // v1 will occupy k[0][1:0]
423      // v2[5:0] will occupy k[0][7:2], v2[7:6] will occupy k[1][1:0]
424      // v3 will occupy k[1][2]
425      // v4[4:0] will occupy k[1][7:3] v4[12:5] will occupy k[2][7:0]
426      // v4[15:13] will occupy k[3][2:0]
427      // v5 will occupy k[3][3]
428      // v6[3:0] will occupy k[3][7:0] v6[11:4] will occupy k[4][7:0]
429      // v6[19:12] will occupy k[5][7:0] v6[27:20] will occupy k[6][7:0]
430      // v6[31:28] will occupy k[7][3:0]
431      // v7 will occupy k[7][7:4]
432      ipmi::message::Payload p;
433      uint2_t v1 = 2;           // binary 0b10
434      uint8_t v2 = 0xa5;        // binary 0b10100101
435      bool v3 = false;          // binary 0b0
436      uint16_t v4 = 0xa55a;     // binary 0b1010010101011010
437      bool v5 = true;           // binary 0b1
438      uint32_t v6 = 0xdbc3bd3c; // binary 0b11011011110000111011110100111100
439      uint4_t v7 = 9;           // binary 0b1001
440      // concat binary:
441      //   0b1001110110111100001110111101001111001101001010101101001010010110
442      //   -> 0x9dbc3bd3cd2ad296 -> 0x96 0xd2 0x2a 0xcd 0xd3 0x3b 0xbc 0x9d
443      p.pack(v1, v2, v3, v4, v5, v6, v7);
444      // check that the number of bytes matches
445      ASSERT_EQ(p.size(), sizeof(uint64_t));
446      // check that the bytes were correctly packed (LSB first)
447      ipmi::SecureBuffer k = {0x96, 0xd2, 0x2a, 0xcd, 0xd3, 0x3b, 0xbc, 0x9d};
448      ASSERT_EQ(p.raw, k);
449  }
450  
TEST(PackAdvanced,ComplexOptionalTuple)451  TEST(PackAdvanced, ComplexOptionalTuple)
452  {
453      constexpr size_t macSize = 6;
454      // inspired from a real-world case of Get Session Info
455      constexpr uint8_t handle = 0x23;       // handle for active session
456      constexpr uint8_t maxSessions = 15;    // number of possible active sessions
457      constexpr uint8_t currentSessions = 4; // number of current active sessions
458      std::optional<                         // only returned for active session
459          std::tuple<uint8_t,                // user ID
460                     uint8_t,                // privilege
461                     uint4_t,                // channel number
462                     uint4_t                 // protocol (RMCP+)
463                     >>
464          activeSession;
465      std::optional<           // only returned for channel type LAN
466          std::tuple<uint32_t, // IPv4 address
467                     std::array<uint8_t, macSize>, // MAC address
468                     uint16_t                      // port
469                     >>
470          lanSession;
471  
472      constexpr uint8_t userID = 7;
473      constexpr uint8_t priv = 4;
474      constexpr uint4_t channel = 2;
475      constexpr uint4_t protocol = 1;
476      activeSession.emplace(userID, priv, channel, protocol);
477      constexpr std::array<uint8_t, macSize> macAddr{0};
478      lanSession.emplace(0x0a010105, macAddr, 55327);
479  
480      ipmi::message::Payload p;
481      p.pack(handle, maxSessions, currentSessions, activeSession, lanSession);
482      ASSERT_EQ(p.size(),
483                sizeof(handle) + sizeof(maxSessions) + sizeof(currentSessions) +
484                    3 * sizeof(uint8_t) + sizeof(uint32_t) +
485                    sizeof(uint8_t) * macSize + sizeof(uint16_t));
486      uint8_t protocol_channel =
487          (static_cast<uint8_t>(protocol) << 4) | static_cast<uint8_t>(channel);
488      ipmi::SecureBuffer k = {
489          handle, maxSessions, currentSessions, userID, priv, protocol_channel,
490          // ip addr
491          0x05, 0x01, 0x01, 0x0a,
492          // mac addr
493          0, 0, 0, 0, 0, 0,
494          // port
495          0x1f, 0xd8};
496      ASSERT_EQ(p.raw, k);
497  }
498