blob: 407c35fbc87ad335c825f3c122a4a1a185f2f227 [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
Vernon Mauerye7329c72018-10-08 12:05:16 -070018#include <ipmid/message/types.hpp>
George Liub4b40912024-07-17 16:14:17 +080019#include <phosphor-logging/lg2.hpp>
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -050020#include <phosphor-logging/log.hpp>
21
22#include <array>
Vernon Mauerye7329c72018-10-08 12:05:16 -070023#include <memory>
Vernon Mauerybae91352019-04-03 12:11:08 -070024#include <optional>
Willy Tuc329cee2023-09-01 08:58:10 -070025#include <span>
William A. Kennington IIIe2aec262019-04-24 14:44:26 -070026#include <string_view>
Vernon Mauerye7329c72018-10-08 12:05:16 -070027#include <tuple>
28#include <utility>
Alexander Amelkin00b096d2019-04-15 15:11:03 +030029#include <variant>
Vernon Mauerye7329c72018-10-08 12:05:16 -070030#include <vector>
31
32namespace ipmi
33{
34
35namespace message
36{
37
38namespace details
39{
40
41/**************************************
42 * ipmi return type helpers
43 **************************************/
44
45template <typename NumericType, size_t byteIndex = 0>
46void PackBytes(uint8_t* pointer, const NumericType& i)
47{
48 if constexpr (byteIndex < sizeof(NumericType))
49 {
50 *pointer = static_cast<uint8_t>(i >> (8 * byteIndex));
51 PackBytes<NumericType, byteIndex + 1>(pointer + 1, i);
52 }
53}
54
55template <typename NumericType, size_t byteIndex = 0>
56void PackBytesUnaligned(Payload& p, const NumericType& i)
57{
58 if constexpr (byteIndex < sizeof(NumericType))
59 {
60 p.appendBits(CHAR_BIT, static_cast<uint8_t>(i >> (8 * byteIndex)));
61 PackBytesUnaligned<NumericType, byteIndex + 1>(p, i);
62 }
63}
64
65/** @struct PackSingle
66 * @brief Utility to pack a single C++ element into a Payload
67 *
68 * User-defined types are expected to specialize this template in order to
69 * get their functionality.
70 *
71 * @tparam S - Type of element to pack.
72 */
73template <typename T>
74struct PackSingle
75{
76 /** @brief Do the operation to pack element.
77 *
78 * @param[in] p - Payload to pack into.
79 * @param[out] t - The reference to pack item into.
80 */
James Feistf2998072019-04-03 11:54:52 -070081 static int op(Payload& p, const T& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -070082 {
Vernon Mauery336405b2019-04-08 09:59:01 -070083 static_assert(std::is_integral_v<T>,
84 "Attempt to pack a type that has no IPMI pack operation");
Vernon Mauerye7329c72018-10-08 12:05:16 -070085 // if not on a byte boundary, must pack values LSbit/LSByte first
86 if (p.bitCount)
87 {
88 PackBytesUnaligned<T>(p, t);
89 }
90 else
91 {
92 // copy in bits to vector....
93 p.raw.resize(p.raw.size() + sizeof(T));
94 uint8_t* out = p.raw.data() + p.raw.size() - sizeof(T);
95 PackBytes<T>(out, t);
96 }
97 return 0;
98 }
99};
100
Vernon Mauery508c4572019-04-08 10:01:33 -0700101/** @brief Specialization of PackSingle for std::tuple<T> */
102template <typename... T>
103struct PackSingle<std::tuple<T...>>
104{
105 static int op(Payload& p, const std::tuple<T...>& v)
106 {
107 return std::apply([&p](const T&... args) { return p.pack(args...); },
108 v);
109 }
110};
111
Vernon Mauerye7329c72018-10-08 12:05:16 -0700112/** @brief Specialization of PackSingle for std::string
113 * represented as a UCSD-Pascal style string
114 */
115template <>
116struct PackSingle<std::string>
117{
James Feistf2998072019-04-03 11:54:52 -0700118 static int op(Payload& p, const std::string& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700119 {
120 // check length first
121 uint8_t len;
122 if (t.length() > std::numeric_limits<decltype(len)>::max())
123 {
George Liub4b40912024-07-17 16:14:17 +0800124 lg2::error("long string truncated on IPMI message pack");
Vernon Mauerye7329c72018-10-08 12:05:16 -0700125 return 1;
126 }
127 len = static_cast<uint8_t>(t.length());
128 PackSingle<uint8_t>::op(p, len);
129 p.append(t.c_str(), t.c_str() + t.length());
130 return 0;
131 }
132};
133
134/** @brief Specialization of PackSingle for fixed_uint_t types
135 */
Tim Leeb4905912022-06-18 02:51:13 +0800136template <bitcount_t N>
Vernon Mauerye7329c72018-10-08 12:05:16 -0700137struct PackSingle<fixed_uint_t<N>>
138{
James Feistf2998072019-04-03 11:54:52 -0700139 static int op(Payload& p, const fixed_uint_t<N>& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700140 {
141 size_t count = N;
142 static_assert(N <= (details::bitStreamSize - CHAR_BIT));
Lei YU30f88f02022-02-11 17:40:39 +0800143 static_assert(N <= std::numeric_limits<uint64_t>::digits,
144 "Type exceeds uint64_t limit");
145 uint64_t bits = static_cast<uint64_t>(t);
Vernon Mauerye7329c72018-10-08 12:05:16 -0700146 while (count > 0)
147 {
148 size_t appendCount = std::min(count, static_cast<size_t>(CHAR_BIT));
149 p.appendBits(appendCount, static_cast<uint8_t>(bits));
150 bits >>= CHAR_BIT;
151 count -= appendCount;
152 }
153 return 0;
154 }
155};
156
157/** @brief Specialization of PackSingle for bool. */
158template <>
159struct PackSingle<bool>
160{
James Feistf2998072019-04-03 11:54:52 -0700161 static int op(Payload& p, const bool& b)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700162 {
163 p.appendBits(1, b);
164 return 0;
165 }
166};
167
168/** @brief Specialization of PackSingle for std::bitset<N> */
169template <size_t N>
170struct PackSingle<std::bitset<N>>
171{
James Feistf2998072019-04-03 11:54:52 -0700172 static int op(Payload& p, const std::bitset<N>& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700173 {
174 size_t count = N;
175 static_assert(N <= (details::bitStreamSize - CHAR_BIT));
176 unsigned long long bits = t.to_ullong();
177 while (count > 0)
178 {
179 size_t appendCount = std::min(count, size_t(CHAR_BIT));
180 p.appendBits(appendCount, static_cast<uint8_t>(bits));
181 bits >>= CHAR_BIT;
182 count -= appendCount;
183 }
184 return 0;
185 }
186};
187
Vernon Mauerybae91352019-04-03 12:11:08 -0700188/** @brief Specialization of PackSingle for std::optional<T> */
189template <typename T>
190struct PackSingle<std::optional<T>>
191{
192 static int op(Payload& p, const std::optional<T>& t)
193 {
194 int ret = 0;
195 if (t)
196 {
197 ret = PackSingle<T>::op(p, *t);
198 }
199 return ret;
200 }
201};
202
Vernon Mauerye7329c72018-10-08 12:05:16 -0700203/** @brief Specialization of PackSingle for std::array<T, N> */
204template <typename T, size_t N>
205struct PackSingle<std::array<T, N>>
206{
James Feistf2998072019-04-03 11:54:52 -0700207 static int op(Payload& p, const std::array<T, N>& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700208 {
209 int ret = 0;
James Feistf2998072019-04-03 11:54:52 -0700210 for (const auto& v : t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700211 {
212 int ret = PackSingle<T>::op(p, v);
213 if (ret)
214 {
215 break;
216 }
217 }
218 return ret;
219 }
220};
221
222/** @brief Specialization of PackSingle for std::vector<T> */
223template <typename T>
224struct PackSingle<std::vector<T>>
225{
James Feistf2998072019-04-03 11:54:52 -0700226 static int op(Payload& p, const std::vector<T>& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700227 {
228 int ret = 0;
James Feistf2998072019-04-03 11:54:52 -0700229 for (const auto& v : t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700230 {
231 int ret = PackSingle<T>::op(p, v);
232 if (ret)
233 {
234 break;
235 }
236 }
237 return ret;
238 }
239};
240
241/** @brief Specialization of PackSingle for std::vector<uint8_t> */
242template <>
243struct PackSingle<std::vector<uint8_t>>
244{
James Feistf2998072019-04-03 11:54:52 -0700245 static int op(Payload& p, const std::vector<uint8_t>& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700246 {
William A. Kennington III906e0f82019-04-24 14:44:03 -0700247 if (p.bitCount != 0)
248 {
249 return 1;
250 }
Vernon Mauerye7329c72018-10-08 12:05:16 -0700251 p.raw.reserve(p.raw.size() + t.size());
252 p.raw.insert(p.raw.end(), t.begin(), t.end());
253 return 0;
254 }
255};
256
Vernon Mauery997952a2021-07-30 14:06:14 -0700257/** @brief Specialization of PackSingle for SecureBuffer */
258template <>
259struct PackSingle<SecureBuffer>
260{
261 static int op(Payload& p, const SecureBuffer& t)
262 {
263 if (p.bitCount != 0)
264 {
265 return 1;
266 }
267 p.raw.reserve(p.raw.size() + t.size());
268 p.raw.insert(p.raw.end(), t.begin(), t.end());
269 return 0;
270 }
271};
272
Willy Tuc329cee2023-09-01 08:58:10 -0700273/** @brief Specialization of PackSingle for std::span<const uint8_t> */
274template <>
275struct PackSingle<std::span<const uint8_t>>
276{
277 static int op(Payload& p, const std::span<const uint8_t>& t)
278 {
279 if (p.bitCount != 0)
280 {
281 return 1;
282 }
283 p.raw.reserve(p.raw.size() + t.size());
284 p.raw.insert(p.raw.end(), t.begin(), t.end());
285 return 0;
286 }
287};
288
William A. Kennington IIIe2aec262019-04-24 14:44:26 -0700289/** @brief Specialization of PackSingle for std::string_view */
290template <>
291struct PackSingle<std::string_view>
292{
293 static int op(Payload& p, const std::string_view& t)
294 {
295 if (p.bitCount != 0)
296 {
297 return 1;
298 }
299 p.raw.reserve(p.raw.size() + t.size());
300 p.raw.insert(p.raw.end(), t.begin(), t.end());
301 return 0;
302 }
303};
304
James Feistf2998072019-04-03 11:54:52 -0700305/** @brief Specialization of PackSingle for std::variant<T, N> */
306template <typename... T>
307struct PackSingle<std::variant<T...>>
308{
309 static int op(Payload& p, const std::variant<T...>& v)
310 {
311 return std::visit(
312 [&p](const auto& arg) {
Patrick Williams1318a5e2024-08-16 15:19:54 -0400313 return PackSingle<std::decay_t<decltype(arg)>>::op(p, arg);
314 },
James Feistf2998072019-04-03 11:54:52 -0700315 v);
316 }
317};
318
William A. Kennington IIIe15e53e2019-04-24 14:45:20 -0700319/** @brief Specialization of PackSingle for Payload */
320template <>
321struct PackSingle<Payload>
322{
323 static int op(Payload& p, const Payload& t)
324 {
325 if (p.bitCount != 0 || t.bitCount != 0)
326 {
327 return 1;
328 }
329 p.raw.reserve(p.raw.size() + t.raw.size());
330 p.raw.insert(p.raw.end(), t.raw.begin(), t.raw.end());
331 return 0;
332 }
333};
334
Vernon Mauerye7329c72018-10-08 12:05:16 -0700335} // namespace details
336
337} // namespace message
338
339} // namespace ipmi