blob: 357f0b4312650100166190ef6516c43f0226fa1f [file] [log] [blame]
Vernon Mauerye7329c72018-10-08 12:05:16 -07001/**
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#pragma once
17
Jayanth Othayotha8205ff2025-03-07 06:57:54 -060018#include <include/ipmid/message.hpp>
Vernon Mauerye7329c72018-10-08 12:05:16 -070019#include <ipmid/message/types.hpp>
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -050020
21#include <array>
Vernon Mauerye7329c72018-10-08 12:05:16 -070022#include <optional>
Willy Tuc329cee2023-09-01 08:58:10 -070023#include <span>
Vernon Mauerye7329c72018-10-08 12:05:16 -070024#include <string>
25#include <tuple>
26#include <vector>
27
28namespace ipmi
29{
30
31namespace message
32{
33
34namespace details
35{
36
37/**************************************
38 * ipmi return type helpers
39 **************************************/
40
41template <typename NumericType, size_t byteIndex = 0>
42void UnpackBytes(uint8_t* pointer, NumericType& i)
43{
44 if constexpr (byteIndex < sizeof(NumericType))
45 {
46 i |= static_cast<NumericType>(*pointer) << (CHAR_BIT * byteIndex);
47 UnpackBytes<NumericType, byteIndex + 1>(pointer + 1, i);
48 }
49}
50
51template <typename NumericType, size_t byteIndex = 0>
52void UnpackBytesUnaligned(Payload& p, NumericType& i)
53{
54 if constexpr (byteIndex < sizeof(NumericType))
55 {
56 i |= static_cast<NumericType>(p.popBits(CHAR_BIT))
57 << (CHAR_BIT * byteIndex);
58 UnpackBytesUnaligned<NumericType, byteIndex + 1>(p, i);
59 }
60}
61
62/** @struct UnpackSingle
63 * @brief Utility to unpack a single C++ element from a Payload
64 *
65 * User-defined types are expected to specialize this template in order to
66 * get their functionality.
67 *
68 * @tparam T - Type of element to unpack.
69 */
70template <typename T>
71struct UnpackSingle
72{
73 /** @brief Do the operation to unpack element.
74 *
75 * @param[in] p - Payload to unpack from.
76 * @param[out] t - The reference to unpack item into.
77 */
78 static int op(Payload& p, T& t)
79 {
80 if constexpr (std::is_fundamental<T>::value)
81 {
82 t = 0;
83 if (p.bitCount)
84 {
85 if (p.fillBits(CHAR_BIT * sizeof(t)))
86 {
87 return 1;
88 }
89 UnpackBytesUnaligned<T>(p, t);
90 }
91 else
92 {
93 // copy out bits from vector....
94 if (p.raw.size() < (p.rawIndex + sizeof(t)))
95 {
96 return 1;
97 }
98 auto iter = p.raw.data() + p.rawIndex;
99 t = 0;
100 UnpackBytes<T>(iter, t);
101 p.rawIndex += sizeof(t);
102 }
103 return 0;
104 }
Vernon Mauerya3dd7662019-05-30 15:20:52 -0700105 else if constexpr (utility::is_tuple<T>::value)
106 {
107 bool priorError = p.unpackError;
108 size_t priorIndex = p.rawIndex;
109 // more stuff to unroll if partial bytes are out
110 size_t priorBitCount = p.bitCount;
111 fixed_uint_t<details::bitStreamSize> priorBits = p.bitStream;
112 int ret = p.unpack(t);
113 if (ret != 0)
114 {
115 t = T();
116 p.rawIndex = priorIndex;
117 p.bitStream = priorBits;
118 p.bitCount = priorBitCount;
119 p.unpackError = priorError;
120 }
Vernon Mauerycaabc362019-07-23 16:49:34 -0700121 return ret;
Vernon Mauerya3dd7662019-05-30 15:20:52 -0700122 }
Vernon Mauerye7329c72018-10-08 12:05:16 -0700123 else
124 {
Vernon Mauerya3dd7662019-05-30 15:20:52 -0700125 static_assert(
126 utility::dependent_false<T>::value,
127 "Attempt to unpack a type that has no IPMI unpack operation");
Vernon Mauerye7329c72018-10-08 12:05:16 -0700128 }
129 }
130};
131
132/** @struct UnpackSingle
133 * @brief Utility to unpack a single C++ element from a Payload
134 *
135 * Specialization to unpack std::string represented as a
136 * UCSD-Pascal style string
137 */
138template <>
139struct UnpackSingle<std::string>
140{
141 static int op(Payload& p, std::string& t)
142 {
143 // pop len first
144 if (p.rawIndex > (p.raw.size() - sizeof(uint8_t)))
145 {
146 return 1;
147 }
148 uint8_t len = p.raw[p.rawIndex++];
149 // check to see that there are n bytes left
150 auto [first, last] = p.pop<char>(len);
151 if (first == last)
152 {
153 return 1;
154 }
155 t.reserve(last - first);
156 t.insert(0, first, (last - first));
157 return 0;
158 }
159};
160
161/** @brief Specialization of UnpackSingle for fixed_uint_t types
162 */
Tim Leeb4905912022-06-18 02:51:13 +0800163template <bitcount_t N>
Vernon Mauerye7329c72018-10-08 12:05:16 -0700164struct UnpackSingle<fixed_uint_t<N>>
165{
166 static int op(Payload& p, fixed_uint_t<N>& t)
167 {
168 static_assert(N <= (details::bitStreamSize - CHAR_BIT));
169 constexpr size_t count = N;
170 // acquire enough bits in the stream to fulfill the Payload
171 if (p.fillBits(count))
172 {
173 return -1;
174 }
175 fixed_uint_t<details::bitStreamSize> bitmask = ((1 << count) - 1);
176 t = (p.bitStream & bitmask).convert_to<fixed_uint_t<N>>();
177 p.bitStream >>= count;
178 p.bitCount -= count;
179 return 0;
180 }
181};
182
183/** @brief Specialization of UnpackSingle for bool. */
184template <>
185struct UnpackSingle<bool>
186{
187 static int op(Payload& p, bool& b)
188 {
189 // acquire enough bits in the stream to fulfill the Payload
190 if (p.fillBits(1))
191 {
192 return -1;
193 }
194 b = static_cast<bool>(p.bitStream & 0x01);
195 // clear bits from stream
196 p.bitStream >>= 1;
197 p.bitCount -= 1;
198 return 0;
199 }
200};
201
202/** @brief Specialization of UnpackSingle for std::bitset<N>
203 */
204template <size_t N>
205struct UnpackSingle<std::bitset<N>>
206{
207 static int op(Payload& p, std::bitset<N>& t)
208 {
209 static_assert(N <= (details::bitStreamSize - CHAR_BIT));
210 size_t count = N;
211 // acquire enough bits in the stream to fulfill the Payload
212 if (p.fillBits(count))
213 {
214 return -1;
215 }
William A. Kennington III0d49e472019-04-08 20:27:26 -0700216 fixed_uint_t<details::bitStreamSize> bitmask =
217 ~fixed_uint_t<details::bitStreamSize>(0) >>
218 (details::bitStreamSize - count);
Vernon Mauerye7329c72018-10-08 12:05:16 -0700219 t |= (p.bitStream & bitmask).convert_to<unsigned long long>();
220 p.bitStream >>= count;
221 p.bitCount -= count;
222 return 0;
223 }
224};
225
226/** @brief Specialization of UnpackSingle for std::optional<T> */
227template <typename T>
228struct UnpackSingle<std::optional<T>>
229{
230 static int op(Payload& p, std::optional<T>& t)
231 {
232 bool priorError = p.unpackError;
233 size_t priorIndex = p.rawIndex;
234 // more stuff to unroll if partial bytes are out
235 size_t priorBitCount = p.bitCount;
236 fixed_uint_t<details::bitStreamSize> priorBits = p.bitStream;
Jonathan Doman202702b2023-09-15 16:21:22 -0700237 T value;
238 int ret = UnpackSingle<T>::op(p, value);
Vernon Mauerye7329c72018-10-08 12:05:16 -0700239 if (ret != 0)
240 {
241 t.reset();
242 p.rawIndex = priorIndex;
243 p.bitStream = priorBits;
244 p.bitCount = priorBitCount;
245 p.unpackError = priorError;
246 }
Jonathan Doman202702b2023-09-15 16:21:22 -0700247 else
248 {
249 t.emplace(std::move(value));
250 }
Vernon Mauerye7329c72018-10-08 12:05:16 -0700251 return 0;
252 }
253};
254
255/** @brief Specialization of UnpackSingle for std::array<T, N> */
256template <typename T, size_t N>
257struct UnpackSingle<std::array<T, N>>
258{
259 static int op(Payload& p, std::array<T, N>& t)
260 {
261 int ret = 0;
262 size_t priorIndex = p.rawIndex;
263 for (auto& v : t)
264 {
265 ret = UnpackSingle<T>::op(p, v);
266 if (ret)
267 {
268 p.rawIndex = priorIndex;
269 t = std::array<T, N>();
270 break;
271 }
272 }
273 return ret;
274 }
275};
276
277/** @brief Specialization of UnpackSingle for std::array<uint8_t> */
278template <size_t N>
279struct UnpackSingle<std::array<uint8_t, N>>
280{
281 static int op(Payload& p, std::array<uint8_t, N>& t)
282 {
283 if (p.raw.size() - p.rawIndex < N)
284 {
285 t.fill(0);
286 return -1;
287 }
288 // copy out the bytes
289 std::copy(p.raw.begin() + p.rawIndex, p.raw.begin() + p.rawIndex + N,
290 t.begin());
291 p.rawIndex += N;
292 return 0;
293 }
294};
295
296/** @brief Specialization of UnpackSingle for std::vector<T> */
297template <typename T>
298struct UnpackSingle<std::vector<T>>
299{
300 static int op(Payload& p, std::vector<T>& t)
301 {
Vernon Mauerye7329c72018-10-08 12:05:16 -0700302 while (p.rawIndex < p.raw.size())
303 {
304 t.emplace_back();
Vernon Mauerycaabc362019-07-23 16:49:34 -0700305 if (UnpackSingle<T>::op(p, t.back()))
Vernon Mauerye7329c72018-10-08 12:05:16 -0700306 {
307 t.pop_back();
308 break;
309 }
310 }
Vernon Mauerycaabc362019-07-23 16:49:34 -0700311 // unpacking a vector is always successful:
312 // either stuff was unpacked successfully (return 0)
313 // or stuff was not unpacked, but should still return
314 // success because an empty vector or a not-fully-unpacked
315 // payload is not a failure.
316 return 0;
Vernon Mauerye7329c72018-10-08 12:05:16 -0700317 }
318};
319
320/** @brief Specialization of UnpackSingle for std::vector<uint8_t> */
321template <>
322struct UnpackSingle<std::vector<uint8_t>>
323{
324 static int op(Payload& p, std::vector<uint8_t>& t)
325 {
326 // copy out the remainder of the message
327 t.reserve(p.raw.size() - p.rawIndex);
328 t.insert(t.begin(), p.raw.begin() + p.rawIndex, p.raw.end());
329 p.rawIndex = p.raw.size();
330 return 0;
331 }
332};
333
Vernon Mauery997952a2021-07-30 14:06:14 -0700334/** @brief Specialization of UnpackSingle for SecureBuffer */
335template <>
336struct UnpackSingle<SecureBuffer>
337{
338 static int op(Payload& p, SecureBuffer& t)
339 {
340 // copy out the remainder of the message
341 t.reserve(p.raw.size() - p.rawIndex);
342 t.insert(t.begin(), p.raw.begin() + p.rawIndex, p.raw.end());
343 p.rawIndex = p.raw.size();
344 return 0;
345 }
346};
347
Willy Tuc329cee2023-09-01 08:58:10 -0700348/** @brief Specialization of UnpackSingle for std::span<const uint8_t> */
349template <>
350struct UnpackSingle<std::span<const uint8_t>>
351{
352 static int op(Payload& p, std::span<const uint8_t>& t)
353 {
354 // copy out the remainder of the message
355 t = std::span<const uint8_t>(p.raw.begin() + p.rawIndex, p.raw.end());
356 p.rawIndex = p.raw.size();
357 return 0;
358 }
359};
360
Vernon Mauerye7329c72018-10-08 12:05:16 -0700361/** @brief Specialization of UnpackSingle for Payload */
362template <>
363struct UnpackSingle<Payload>
364{
365 static int op(Payload& p, Payload& t)
366 {
William A. Kennington III51694c22019-04-24 01:44:44 -0700367 t = p;
Vernon Mauerye7329c72018-10-08 12:05:16 -0700368 // mark that this payload is being included in the args
369 p.trailingOk = true;
Vernon Mauerye7329c72018-10-08 12:05:16 -0700370 return 0;
371 }
372};
373
374} // namespace details
375
376} // namespace message
377
378} // namespace ipmi