blob: 00fcf4632ab4e50aaeb38df806e1528681a664fa [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>
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -050019#include <phosphor-logging/log.hpp>
20
21#include <array>
Vernon Mauerye7329c72018-10-08 12:05:16 -070022#include <memory>
Vernon Mauerybae91352019-04-03 12:11:08 -070023#include <optional>
Willy Tuc329cee2023-09-01 08:58:10 -070024#include <span>
William A. Kennington IIIe2aec262019-04-24 14:44:26 -070025#include <string_view>
Vernon Mauerye7329c72018-10-08 12:05:16 -070026#include <tuple>
27#include <utility>
Alexander Amelkin00b096d2019-04-15 15:11:03 +030028#include <variant>
Vernon Mauerye7329c72018-10-08 12:05:16 -070029#include <vector>
30
31namespace ipmi
32{
33
34namespace message
35{
36
37namespace details
38{
39
40/**************************************
41 * ipmi return type helpers
42 **************************************/
43
44template <typename NumericType, size_t byteIndex = 0>
45void PackBytes(uint8_t* pointer, const NumericType& i)
46{
47 if constexpr (byteIndex < sizeof(NumericType))
48 {
49 *pointer = static_cast<uint8_t>(i >> (8 * byteIndex));
50 PackBytes<NumericType, byteIndex + 1>(pointer + 1, i);
51 }
52}
53
54template <typename NumericType, size_t byteIndex = 0>
55void PackBytesUnaligned(Payload& p, const NumericType& i)
56{
57 if constexpr (byteIndex < sizeof(NumericType))
58 {
59 p.appendBits(CHAR_BIT, static_cast<uint8_t>(i >> (8 * byteIndex)));
60 PackBytesUnaligned<NumericType, byteIndex + 1>(p, i);
61 }
62}
63
64/** @struct PackSingle
65 * @brief Utility to pack a single C++ element into a Payload
66 *
67 * User-defined types are expected to specialize this template in order to
68 * get their functionality.
69 *
70 * @tparam S - Type of element to pack.
71 */
72template <typename T>
73struct PackSingle
74{
75 /** @brief Do the operation to pack element.
76 *
77 * @param[in] p - Payload to pack into.
78 * @param[out] t - The reference to pack item into.
79 */
James Feistf2998072019-04-03 11:54:52 -070080 static int op(Payload& p, const T& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -070081 {
Vernon Mauery336405b2019-04-08 09:59:01 -070082 static_assert(std::is_integral_v<T>,
83 "Attempt to pack a type that has no IPMI pack operation");
Vernon Mauerye7329c72018-10-08 12:05:16 -070084 // if not on a byte boundary, must pack values LSbit/LSByte first
85 if (p.bitCount)
86 {
87 PackBytesUnaligned<T>(p, t);
88 }
89 else
90 {
91 // copy in bits to vector....
92 p.raw.resize(p.raw.size() + sizeof(T));
93 uint8_t* out = p.raw.data() + p.raw.size() - sizeof(T);
94 PackBytes<T>(out, t);
95 }
96 return 0;
97 }
98};
99
Vernon Mauery508c4572019-04-08 10:01:33 -0700100/** @brief Specialization of PackSingle for std::tuple<T> */
101template <typename... T>
102struct PackSingle<std::tuple<T...>>
103{
104 static int op(Payload& p, const std::tuple<T...>& v)
105 {
106 return std::apply([&p](const T&... args) { return p.pack(args...); },
107 v);
108 }
109};
110
Vernon Mauerye7329c72018-10-08 12:05:16 -0700111/** @brief Specialization of PackSingle for std::string
112 * represented as a UCSD-Pascal style string
113 */
114template <>
115struct PackSingle<std::string>
116{
James Feistf2998072019-04-03 11:54:52 -0700117 static int op(Payload& p, const std::string& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700118 {
119 // check length first
120 uint8_t len;
121 if (t.length() > std::numeric_limits<decltype(len)>::max())
122 {
123 using namespace phosphor::logging;
124 log<level::ERR>("long string truncated on IPMI message pack");
125 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 Williamsfbc6c9d2023-05-10 07:50:16 -0500313 return PackSingle<std::decay_t<decltype(arg)>>::op(p, arg);
Patrick Williams369824e2023-10-20 11:18:23 -0500314 },
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