blob: 30baa595cd864c3eb17aa011816bfd59fb950c48 [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>
William A. Kennington IIIe2aec262019-04-24 14:44:26 -070024#include <string_view>
Vernon Mauerye7329c72018-10-08 12:05:16 -070025#include <tuple>
26#include <utility>
Alexander Amelkin00b096d2019-04-15 15:11:03 +030027#include <variant>
Vernon Mauerye7329c72018-10-08 12:05:16 -070028#include <vector>
29
30namespace ipmi
31{
32
33namespace message
34{
35
36namespace details
37{
38
39/**************************************
40 * ipmi return type helpers
41 **************************************/
42
43template <typename NumericType, size_t byteIndex = 0>
44void PackBytes(uint8_t* pointer, const NumericType& i)
45{
46 if constexpr (byteIndex < sizeof(NumericType))
47 {
48 *pointer = static_cast<uint8_t>(i >> (8 * byteIndex));
49 PackBytes<NumericType, byteIndex + 1>(pointer + 1, i);
50 }
51}
52
53template <typename NumericType, size_t byteIndex = 0>
54void PackBytesUnaligned(Payload& p, const NumericType& i)
55{
56 if constexpr (byteIndex < sizeof(NumericType))
57 {
58 p.appendBits(CHAR_BIT, static_cast<uint8_t>(i >> (8 * byteIndex)));
59 PackBytesUnaligned<NumericType, byteIndex + 1>(p, i);
60 }
61}
62
63/** @struct PackSingle
64 * @brief Utility to pack a single C++ element into a Payload
65 *
66 * User-defined types are expected to specialize this template in order to
67 * get their functionality.
68 *
69 * @tparam S - Type of element to pack.
70 */
71template <typename T>
72struct PackSingle
73{
74 /** @brief Do the operation to pack element.
75 *
76 * @param[in] p - Payload to pack into.
77 * @param[out] t - The reference to pack item into.
78 */
James Feistf2998072019-04-03 11:54:52 -070079 static int op(Payload& p, const T& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -070080 {
Vernon Mauery336405b2019-04-08 09:59:01 -070081 static_assert(std::is_integral_v<T>,
82 "Attempt to pack a type that has no IPMI pack operation");
Vernon Mauerye7329c72018-10-08 12:05:16 -070083 // if not on a byte boundary, must pack values LSbit/LSByte first
84 if (p.bitCount)
85 {
86 PackBytesUnaligned<T>(p, t);
87 }
88 else
89 {
90 // copy in bits to vector....
91 p.raw.resize(p.raw.size() + sizeof(T));
92 uint8_t* out = p.raw.data() + p.raw.size() - sizeof(T);
93 PackBytes<T>(out, t);
94 }
95 return 0;
96 }
97};
98
Vernon Mauery508c4572019-04-08 10:01:33 -070099/** @brief Specialization of PackSingle for std::tuple<T> */
100template <typename... T>
101struct PackSingle<std::tuple<T...>>
102{
103 static int op(Payload& p, const std::tuple<T...>& v)
104 {
105 return std::apply([&p](const T&... args) { return p.pack(args...); },
106 v);
107 }
108};
109
Vernon Mauerye7329c72018-10-08 12:05:16 -0700110/** @brief Specialization of PackSingle for std::string
111 * represented as a UCSD-Pascal style string
112 */
113template <>
114struct PackSingle<std::string>
115{
James Feistf2998072019-04-03 11:54:52 -0700116 static int op(Payload& p, const std::string& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700117 {
118 // check length first
119 uint8_t len;
120 if (t.length() > std::numeric_limits<decltype(len)>::max())
121 {
122 using namespace phosphor::logging;
123 log<level::ERR>("long string truncated on IPMI message pack");
124 return 1;
125 }
126 len = static_cast<uint8_t>(t.length());
127 PackSingle<uint8_t>::op(p, len);
128 p.append(t.c_str(), t.c_str() + t.length());
129 return 0;
130 }
131};
132
133/** @brief Specialization of PackSingle for fixed_uint_t types
134 */
Tim Leeb4905912022-06-18 02:51:13 +0800135template <bitcount_t N>
Vernon Mauerye7329c72018-10-08 12:05:16 -0700136struct PackSingle<fixed_uint_t<N>>
137{
James Feistf2998072019-04-03 11:54:52 -0700138 static int op(Payload& p, const fixed_uint_t<N>& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700139 {
140 size_t count = N;
141 static_assert(N <= (details::bitStreamSize - CHAR_BIT));
Lei YU30f88f02022-02-11 17:40:39 +0800142 static_assert(N <= std::numeric_limits<uint64_t>::digits,
143 "Type exceeds uint64_t limit");
144 uint64_t bits = static_cast<uint64_t>(t);
Vernon Mauerye7329c72018-10-08 12:05:16 -0700145 while (count > 0)
146 {
147 size_t appendCount = std::min(count, static_cast<size_t>(CHAR_BIT));
148 p.appendBits(appendCount, static_cast<uint8_t>(bits));
149 bits >>= CHAR_BIT;
150 count -= appendCount;
151 }
152 return 0;
153 }
154};
155
156/** @brief Specialization of PackSingle for bool. */
157template <>
158struct PackSingle<bool>
159{
James Feistf2998072019-04-03 11:54:52 -0700160 static int op(Payload& p, const bool& b)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700161 {
162 p.appendBits(1, b);
163 return 0;
164 }
165};
166
167/** @brief Specialization of PackSingle for std::bitset<N> */
168template <size_t N>
169struct PackSingle<std::bitset<N>>
170{
James Feistf2998072019-04-03 11:54:52 -0700171 static int op(Payload& p, const std::bitset<N>& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700172 {
173 size_t count = N;
174 static_assert(N <= (details::bitStreamSize - CHAR_BIT));
175 unsigned long long bits = t.to_ullong();
176 while (count > 0)
177 {
178 size_t appendCount = std::min(count, size_t(CHAR_BIT));
179 p.appendBits(appendCount, static_cast<uint8_t>(bits));
180 bits >>= CHAR_BIT;
181 count -= appendCount;
182 }
183 return 0;
184 }
185};
186
Vernon Mauerybae91352019-04-03 12:11:08 -0700187/** @brief Specialization of PackSingle for std::optional<T> */
188template <typename T>
189struct PackSingle<std::optional<T>>
190{
191 static int op(Payload& p, const std::optional<T>& t)
192 {
193 int ret = 0;
194 if (t)
195 {
196 ret = PackSingle<T>::op(p, *t);
197 }
198 return ret;
199 }
200};
201
Vernon Mauerye7329c72018-10-08 12:05:16 -0700202/** @brief Specialization of PackSingle for std::array<T, N> */
203template <typename T, size_t N>
204struct PackSingle<std::array<T, N>>
205{
James Feistf2998072019-04-03 11:54:52 -0700206 static int op(Payload& p, const std::array<T, N>& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700207 {
208 int ret = 0;
James Feistf2998072019-04-03 11:54:52 -0700209 for (const auto& v : t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700210 {
211 int ret = PackSingle<T>::op(p, v);
212 if (ret)
213 {
214 break;
215 }
216 }
217 return ret;
218 }
219};
220
221/** @brief Specialization of PackSingle for std::vector<T> */
222template <typename T>
223struct PackSingle<std::vector<T>>
224{
James Feistf2998072019-04-03 11:54:52 -0700225 static int op(Payload& p, const std::vector<T>& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700226 {
227 int ret = 0;
James Feistf2998072019-04-03 11:54:52 -0700228 for (const auto& v : t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700229 {
230 int ret = PackSingle<T>::op(p, v);
231 if (ret)
232 {
233 break;
234 }
235 }
236 return ret;
237 }
238};
239
240/** @brief Specialization of PackSingle for std::vector<uint8_t> */
241template <>
242struct PackSingle<std::vector<uint8_t>>
243{
James Feistf2998072019-04-03 11:54:52 -0700244 static int op(Payload& p, const std::vector<uint8_t>& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700245 {
William A. Kennington III906e0f82019-04-24 14:44:03 -0700246 if (p.bitCount != 0)
247 {
248 return 1;
249 }
Vernon Mauerye7329c72018-10-08 12:05:16 -0700250 p.raw.reserve(p.raw.size() + t.size());
251 p.raw.insert(p.raw.end(), t.begin(), t.end());
252 return 0;
253 }
254};
255
Vernon Mauery997952a2021-07-30 14:06:14 -0700256/** @brief Specialization of PackSingle for SecureBuffer */
257template <>
258struct PackSingle<SecureBuffer>
259{
260 static int op(Payload& p, const SecureBuffer& t)
261 {
262 if (p.bitCount != 0)
263 {
264 return 1;
265 }
266 p.raw.reserve(p.raw.size() + t.size());
267 p.raw.insert(p.raw.end(), t.begin(), t.end());
268 return 0;
269 }
270};
271
William A. Kennington IIIe2aec262019-04-24 14:44:26 -0700272/** @brief Specialization of PackSingle for std::string_view */
273template <>
274struct PackSingle<std::string_view>
275{
276 static int op(Payload& p, const std::string_view& t)
277 {
278 if (p.bitCount != 0)
279 {
280 return 1;
281 }
282 p.raw.reserve(p.raw.size() + t.size());
283 p.raw.insert(p.raw.end(), t.begin(), t.end());
284 return 0;
285 }
286};
287
James Feistf2998072019-04-03 11:54:52 -0700288/** @brief Specialization of PackSingle for std::variant<T, N> */
289template <typename... T>
290struct PackSingle<std::variant<T...>>
291{
292 static int op(Payload& p, const std::variant<T...>& v)
293 {
294 return std::visit(
295 [&p](const auto& arg) {
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500296 return PackSingle<std::decay_t<decltype(arg)>>::op(p, arg);
James Feistf2998072019-04-03 11:54:52 -0700297 },
298 v);
299 }
300};
301
William A. Kennington IIIe15e53e2019-04-24 14:45:20 -0700302/** @brief Specialization of PackSingle for Payload */
303template <>
304struct PackSingle<Payload>
305{
306 static int op(Payload& p, const Payload& t)
307 {
308 if (p.bitCount != 0 || t.bitCount != 0)
309 {
310 return 1;
311 }
312 p.raw.reserve(p.raw.size() + t.raw.size());
313 p.raw.insert(p.raw.end(), t.raw.begin(), t.raw.end());
314 return 0;
315 }
316};
317
Vernon Mauerye7329c72018-10-08 12:05:16 -0700318} // namespace details
319
320} // namespace message
321
322} // namespace ipmi