blob: 724bffc86f5721c38c68be2bd76abd6dc1e2560e [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 Othayoth9706bc82025-03-17 07:28:38 -050018#include <ipmid/message.hpp>
Vernon Mauerye7329c72018-10-08 12:05:16 -070019#include <ipmid/message/types.hpp>
George Liub4b40912024-07-17 16:14:17 +080020#include <phosphor-logging/lg2.hpp>
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -050021#include <phosphor-logging/log.hpp>
22
23#include <array>
Vernon Mauerye7329c72018-10-08 12:05:16 -070024#include <memory>
Vernon Mauerybae91352019-04-03 12:11:08 -070025#include <optional>
Willy Tuc329cee2023-09-01 08:58:10 -070026#include <span>
William A. Kennington IIIe2aec262019-04-24 14:44:26 -070027#include <string_view>
Vernon Mauerye7329c72018-10-08 12:05:16 -070028#include <tuple>
29#include <utility>
Alexander Amelkin00b096d2019-04-15 15:11:03 +030030#include <variant>
Vernon Mauerye7329c72018-10-08 12:05:16 -070031#include <vector>
32
33namespace ipmi
34{
35
36namespace message
37{
38
39namespace details
40{
41
42/**************************************
43 * ipmi return type helpers
44 **************************************/
45
46template <typename NumericType, size_t byteIndex = 0>
47void PackBytes(uint8_t* pointer, const NumericType& i)
48{
49 if constexpr (byteIndex < sizeof(NumericType))
50 {
51 *pointer = static_cast<uint8_t>(i >> (8 * byteIndex));
52 PackBytes<NumericType, byteIndex + 1>(pointer + 1, i);
53 }
54}
55
56template <typename NumericType, size_t byteIndex = 0>
57void PackBytesUnaligned(Payload& p, const NumericType& i)
58{
59 if constexpr (byteIndex < sizeof(NumericType))
60 {
61 p.appendBits(CHAR_BIT, static_cast<uint8_t>(i >> (8 * byteIndex)));
62 PackBytesUnaligned<NumericType, byteIndex + 1>(p, i);
63 }
64}
65
66/** @struct PackSingle
67 * @brief Utility to pack a single C++ element into a Payload
68 *
69 * User-defined types are expected to specialize this template in order to
70 * get their functionality.
71 *
72 * @tparam S - Type of element to pack.
73 */
74template <typename T>
75struct PackSingle
76{
77 /** @brief Do the operation to pack element.
78 *
79 * @param[in] p - Payload to pack into.
80 * @param[out] t - The reference to pack item into.
81 */
James Feistf2998072019-04-03 11:54:52 -070082 static int op(Payload& p, const T& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -070083 {
Vernon Mauery336405b2019-04-08 09:59:01 -070084 static_assert(std::is_integral_v<T>,
85 "Attempt to pack a type that has no IPMI pack operation");
Vernon Mauerye7329c72018-10-08 12:05:16 -070086 // if not on a byte boundary, must pack values LSbit/LSByte first
87 if (p.bitCount)
88 {
89 PackBytesUnaligned<T>(p, t);
90 }
91 else
92 {
93 // copy in bits to vector....
94 p.raw.resize(p.raw.size() + sizeof(T));
95 uint8_t* out = p.raw.data() + p.raw.size() - sizeof(T);
96 PackBytes<T>(out, t);
97 }
98 return 0;
99 }
100};
101
Vernon Mauery508c4572019-04-08 10:01:33 -0700102/** @brief Specialization of PackSingle for std::tuple<T> */
103template <typename... T>
104struct PackSingle<std::tuple<T...>>
105{
106 static int op(Payload& p, const std::tuple<T...>& v)
107 {
108 return std::apply([&p](const T&... args) { return p.pack(args...); },
109 v);
110 }
111};
112
Vernon Mauerye7329c72018-10-08 12:05:16 -0700113/** @brief Specialization of PackSingle for std::string
114 * represented as a UCSD-Pascal style string
115 */
116template <>
117struct PackSingle<std::string>
118{
James Feistf2998072019-04-03 11:54:52 -0700119 static int op(Payload& p, const std::string& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700120 {
121 // check length first
122 uint8_t len;
123 if (t.length() > std::numeric_limits<decltype(len)>::max())
124 {
George Liub4b40912024-07-17 16:14:17 +0800125 lg2::error("long string truncated on IPMI message pack");
Vernon Mauerye7329c72018-10-08 12:05:16 -0700126 return 1;
127 }
128 len = static_cast<uint8_t>(t.length());
129 PackSingle<uint8_t>::op(p, len);
130 p.append(t.c_str(), t.c_str() + t.length());
131 return 0;
132 }
133};
134
135/** @brief Specialization of PackSingle for fixed_uint_t types
136 */
Tim Leeb4905912022-06-18 02:51:13 +0800137template <bitcount_t N>
Vernon Mauerye7329c72018-10-08 12:05:16 -0700138struct PackSingle<fixed_uint_t<N>>
139{
James Feistf2998072019-04-03 11:54:52 -0700140 static int op(Payload& p, const fixed_uint_t<N>& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700141 {
142 size_t count = N;
143 static_assert(N <= (details::bitStreamSize - CHAR_BIT));
Lei YU30f88f02022-02-11 17:40:39 +0800144 static_assert(N <= std::numeric_limits<uint64_t>::digits,
145 "Type exceeds uint64_t limit");
146 uint64_t bits = static_cast<uint64_t>(t);
Vernon Mauerye7329c72018-10-08 12:05:16 -0700147 while (count > 0)
148 {
149 size_t appendCount = std::min(count, static_cast<size_t>(CHAR_BIT));
150 p.appendBits(appendCount, static_cast<uint8_t>(bits));
151 bits >>= CHAR_BIT;
152 count -= appendCount;
153 }
154 return 0;
155 }
156};
157
158/** @brief Specialization of PackSingle for bool. */
159template <>
160struct PackSingle<bool>
161{
James Feistf2998072019-04-03 11:54:52 -0700162 static int op(Payload& p, const bool& b)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700163 {
164 p.appendBits(1, b);
165 return 0;
166 }
167};
168
169/** @brief Specialization of PackSingle for std::bitset<N> */
170template <size_t N>
171struct PackSingle<std::bitset<N>>
172{
James Feistf2998072019-04-03 11:54:52 -0700173 static int op(Payload& p, const std::bitset<N>& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700174 {
175 size_t count = N;
176 static_assert(N <= (details::bitStreamSize - CHAR_BIT));
177 unsigned long long bits = t.to_ullong();
178 while (count > 0)
179 {
180 size_t appendCount = std::min(count, size_t(CHAR_BIT));
181 p.appendBits(appendCount, static_cast<uint8_t>(bits));
182 bits >>= CHAR_BIT;
183 count -= appendCount;
184 }
185 return 0;
186 }
187};
188
Vernon Mauerybae91352019-04-03 12:11:08 -0700189/** @brief Specialization of PackSingle for std::optional<T> */
190template <typename T>
191struct PackSingle<std::optional<T>>
192{
193 static int op(Payload& p, const std::optional<T>& t)
194 {
195 int ret = 0;
196 if (t)
197 {
198 ret = PackSingle<T>::op(p, *t);
199 }
200 return ret;
201 }
202};
203
Vernon Mauerye7329c72018-10-08 12:05:16 -0700204/** @brief Specialization of PackSingle for std::array<T, N> */
205template <typename T, size_t N>
206struct PackSingle<std::array<T, N>>
207{
James Feistf2998072019-04-03 11:54:52 -0700208 static int op(Payload& p, const std::array<T, N>& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700209 {
210 int ret = 0;
James Feistf2998072019-04-03 11:54:52 -0700211 for (const auto& v : t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700212 {
213 int ret = PackSingle<T>::op(p, v);
214 if (ret)
215 {
216 break;
217 }
218 }
219 return ret;
220 }
221};
222
223/** @brief Specialization of PackSingle for std::vector<T> */
224template <typename T>
225struct PackSingle<std::vector<T>>
226{
James Feistf2998072019-04-03 11:54:52 -0700227 static int op(Payload& p, const std::vector<T>& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700228 {
229 int ret = 0;
James Feistf2998072019-04-03 11:54:52 -0700230 for (const auto& v : t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700231 {
232 int ret = PackSingle<T>::op(p, v);
233 if (ret)
234 {
235 break;
236 }
237 }
238 return ret;
239 }
240};
241
242/** @brief Specialization of PackSingle for std::vector<uint8_t> */
243template <>
244struct PackSingle<std::vector<uint8_t>>
245{
James Feistf2998072019-04-03 11:54:52 -0700246 static int op(Payload& p, const std::vector<uint8_t>& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700247 {
William A. Kennington III906e0f82019-04-24 14:44:03 -0700248 if (p.bitCount != 0)
249 {
250 return 1;
251 }
Vernon Mauerye7329c72018-10-08 12:05:16 -0700252 p.raw.reserve(p.raw.size() + t.size());
253 p.raw.insert(p.raw.end(), t.begin(), t.end());
254 return 0;
255 }
256};
257
Vernon Mauery997952a2021-07-30 14:06:14 -0700258/** @brief Specialization of PackSingle for SecureBuffer */
259template <>
260struct PackSingle<SecureBuffer>
261{
262 static int op(Payload& p, const SecureBuffer& t)
263 {
264 if (p.bitCount != 0)
265 {
266 return 1;
267 }
268 p.raw.reserve(p.raw.size() + t.size());
269 p.raw.insert(p.raw.end(), t.begin(), t.end());
270 return 0;
271 }
272};
273
Willy Tuc329cee2023-09-01 08:58:10 -0700274/** @brief Specialization of PackSingle for std::span<const uint8_t> */
275template <>
276struct PackSingle<std::span<const uint8_t>>
277{
278 static int op(Payload& p, const std::span<const uint8_t>& t)
279 {
280 if (p.bitCount != 0)
281 {
282 return 1;
283 }
284 p.raw.reserve(p.raw.size() + t.size());
285 p.raw.insert(p.raw.end(), t.begin(), t.end());
286 return 0;
287 }
288};
289
William A. Kennington IIIe2aec262019-04-24 14:44:26 -0700290/** @brief Specialization of PackSingle for std::string_view */
291template <>
292struct PackSingle<std::string_view>
293{
294 static int op(Payload& p, const std::string_view& t)
295 {
296 if (p.bitCount != 0)
297 {
298 return 1;
299 }
300 p.raw.reserve(p.raw.size() + t.size());
301 p.raw.insert(p.raw.end(), t.begin(), t.end());
302 return 0;
303 }
304};
305
James Feistf2998072019-04-03 11:54:52 -0700306/** @brief Specialization of PackSingle for std::variant<T, N> */
307template <typename... T>
308struct PackSingle<std::variant<T...>>
309{
310 static int op(Payload& p, const std::variant<T...>& v)
311 {
312 return std::visit(
313 [&p](const auto& arg) {
Patrick Williams1318a5e2024-08-16 15:19:54 -0400314 return PackSingle<std::decay_t<decltype(arg)>>::op(p, arg);
315 },
James Feistf2998072019-04-03 11:54:52 -0700316 v);
317 }
318};
319
William A. Kennington IIIe15e53e2019-04-24 14:45:20 -0700320/** @brief Specialization of PackSingle for Payload */
321template <>
322struct PackSingle<Payload>
323{
324 static int op(Payload& p, const Payload& t)
325 {
326 if (p.bitCount != 0 || t.bitCount != 0)
327 {
328 return 1;
329 }
330 p.raw.reserve(p.raw.size() + t.raw.size());
331 p.raw.insert(p.raw.end(), t.raw.begin(), t.raw.end());
332 return 0;
333 }
334};
335
Vernon Mauerye7329c72018-10-08 12:05:16 -0700336} // namespace details
337
338} // namespace message
339
340} // namespace ipmi