blob: 86a12be514e08ae7195872dbe5e98c64233f1e79 [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
18#include <array>
19#include <ipmid/message/types.hpp>
20#include <memory>
Vernon Mauerybae91352019-04-03 12:11:08 -070021#include <optional>
Vernon Mauerye7329c72018-10-08 12:05:16 -070022#include <phosphor-logging/log.hpp>
William A. Kennington IIIe2aec262019-04-24 14:44:26 -070023#include <string_view>
Vernon Mauerye7329c72018-10-08 12:05:16 -070024#include <tuple>
25#include <utility>
Alexander Amelkin00b096d2019-04-15 15:11:03 +030026#include <variant>
Vernon Mauerye7329c72018-10-08 12:05:16 -070027#include <vector>
28
29namespace ipmi
30{
31
32namespace message
33{
34
35namespace details
36{
37
38/**************************************
39 * ipmi return type helpers
40 **************************************/
41
42template <typename NumericType, size_t byteIndex = 0>
43void PackBytes(uint8_t* pointer, const NumericType& i)
44{
45 if constexpr (byteIndex < sizeof(NumericType))
46 {
47 *pointer = static_cast<uint8_t>(i >> (8 * byteIndex));
48 PackBytes<NumericType, byteIndex + 1>(pointer + 1, i);
49 }
50}
51
52template <typename NumericType, size_t byteIndex = 0>
53void PackBytesUnaligned(Payload& p, const NumericType& i)
54{
55 if constexpr (byteIndex < sizeof(NumericType))
56 {
57 p.appendBits(CHAR_BIT, static_cast<uint8_t>(i >> (8 * byteIndex)));
58 PackBytesUnaligned<NumericType, byteIndex + 1>(p, i);
59 }
60}
61
62/** @struct PackSingle
63 * @brief Utility to pack a single C++ element into a Payload
64 *
65 * User-defined types are expected to specialize this template in order to
66 * get their functionality.
67 *
68 * @tparam S - Type of element to pack.
69 */
70template <typename T>
71struct PackSingle
72{
73 /** @brief Do the operation to pack element.
74 *
75 * @param[in] p - Payload to pack into.
76 * @param[out] t - The reference to pack item into.
77 */
James Feistf2998072019-04-03 11:54:52 -070078 static int op(Payload& p, const T& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -070079 {
Vernon Mauery336405b2019-04-08 09:59:01 -070080 static_assert(std::is_integral_v<T>,
81 "Attempt to pack a type that has no IPMI pack operation");
Vernon Mauerye7329c72018-10-08 12:05:16 -070082 // if not on a byte boundary, must pack values LSbit/LSByte first
83 if (p.bitCount)
84 {
85 PackBytesUnaligned<T>(p, t);
86 }
87 else
88 {
89 // copy in bits to vector....
90 p.raw.resize(p.raw.size() + sizeof(T));
91 uint8_t* out = p.raw.data() + p.raw.size() - sizeof(T);
92 PackBytes<T>(out, t);
93 }
94 return 0;
95 }
96};
97
Vernon Mauery508c4572019-04-08 10:01:33 -070098/** @brief Specialization of PackSingle for std::tuple<T> */
99template <typename... T>
100struct PackSingle<std::tuple<T...>>
101{
102 static int op(Payload& p, const std::tuple<T...>& v)
103 {
104 return std::apply([&p](const T&... args) { return p.pack(args...); },
105 v);
106 }
107};
108
Vernon Mauerye7329c72018-10-08 12:05:16 -0700109/** @brief Specialization of PackSingle for std::string
110 * represented as a UCSD-Pascal style string
111 */
112template <>
113struct PackSingle<std::string>
114{
James Feistf2998072019-04-03 11:54:52 -0700115 static int op(Payload& p, const std::string& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700116 {
117 // check length first
118 uint8_t len;
119 if (t.length() > std::numeric_limits<decltype(len)>::max())
120 {
121 using namespace phosphor::logging;
122 log<level::ERR>("long string truncated on IPMI message pack");
123 return 1;
124 }
125 len = static_cast<uint8_t>(t.length());
126 PackSingle<uint8_t>::op(p, len);
127 p.append(t.c_str(), t.c_str() + t.length());
128 return 0;
129 }
130};
131
132/** @brief Specialization of PackSingle for fixed_uint_t types
133 */
Tim Leeb4905912022-06-18 02:51:13 +0800134template <bitcount_t N>
Vernon Mauerye7329c72018-10-08 12:05:16 -0700135struct PackSingle<fixed_uint_t<N>>
136{
James Feistf2998072019-04-03 11:54:52 -0700137 static int op(Payload& p, const fixed_uint_t<N>& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700138 {
139 size_t count = N;
140 static_assert(N <= (details::bitStreamSize - CHAR_BIT));
Lei YU30f88f02022-02-11 17:40:39 +0800141 static_assert(N <= std::numeric_limits<uint64_t>::digits,
142 "Type exceeds uint64_t limit");
143 uint64_t bits = static_cast<uint64_t>(t);
Vernon Mauerye7329c72018-10-08 12:05:16 -0700144 while (count > 0)
145 {
146 size_t appendCount = std::min(count, static_cast<size_t>(CHAR_BIT));
147 p.appendBits(appendCount, static_cast<uint8_t>(bits));
148 bits >>= CHAR_BIT;
149 count -= appendCount;
150 }
151 return 0;
152 }
153};
154
155/** @brief Specialization of PackSingle for bool. */
156template <>
157struct PackSingle<bool>
158{
James Feistf2998072019-04-03 11:54:52 -0700159 static int op(Payload& p, const bool& b)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700160 {
161 p.appendBits(1, b);
162 return 0;
163 }
164};
165
166/** @brief Specialization of PackSingle for std::bitset<N> */
167template <size_t N>
168struct PackSingle<std::bitset<N>>
169{
James Feistf2998072019-04-03 11:54:52 -0700170 static int op(Payload& p, const std::bitset<N>& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700171 {
172 size_t count = N;
173 static_assert(N <= (details::bitStreamSize - CHAR_BIT));
174 unsigned long long bits = t.to_ullong();
175 while (count > 0)
176 {
177 size_t appendCount = std::min(count, size_t(CHAR_BIT));
178 p.appendBits(appendCount, static_cast<uint8_t>(bits));
179 bits >>= CHAR_BIT;
180 count -= appendCount;
181 }
182 return 0;
183 }
184};
185
Vernon Mauerybae91352019-04-03 12:11:08 -0700186/** @brief Specialization of PackSingle for std::optional<T> */
187template <typename T>
188struct PackSingle<std::optional<T>>
189{
190 static int op(Payload& p, const std::optional<T>& t)
191 {
192 int ret = 0;
193 if (t)
194 {
195 ret = PackSingle<T>::op(p, *t);
196 }
197 return ret;
198 }
199};
200
Vernon Mauerye7329c72018-10-08 12:05:16 -0700201/** @brief Specialization of PackSingle for std::array<T, N> */
202template <typename T, size_t N>
203struct PackSingle<std::array<T, N>>
204{
James Feistf2998072019-04-03 11:54:52 -0700205 static int op(Payload& p, const std::array<T, N>& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700206 {
207 int ret = 0;
James Feistf2998072019-04-03 11:54:52 -0700208 for (const auto& v : t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700209 {
210 int ret = PackSingle<T>::op(p, v);
211 if (ret)
212 {
213 break;
214 }
215 }
216 return ret;
217 }
218};
219
220/** @brief Specialization of PackSingle for std::vector<T> */
221template <typename T>
222struct PackSingle<std::vector<T>>
223{
James Feistf2998072019-04-03 11:54:52 -0700224 static int op(Payload& p, const std::vector<T>& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700225 {
226 int ret = 0;
James Feistf2998072019-04-03 11:54:52 -0700227 for (const auto& v : t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700228 {
229 int ret = PackSingle<T>::op(p, v);
230 if (ret)
231 {
232 break;
233 }
234 }
235 return ret;
236 }
237};
238
239/** @brief Specialization of PackSingle for std::vector<uint8_t> */
240template <>
241struct PackSingle<std::vector<uint8_t>>
242{
James Feistf2998072019-04-03 11:54:52 -0700243 static int op(Payload& p, const std::vector<uint8_t>& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700244 {
William A. Kennington III906e0f82019-04-24 14:44:03 -0700245 if (p.bitCount != 0)
246 {
247 return 1;
248 }
Vernon Mauerye7329c72018-10-08 12:05:16 -0700249 p.raw.reserve(p.raw.size() + t.size());
250 p.raw.insert(p.raw.end(), t.begin(), t.end());
251 return 0;
252 }
253};
254
Vernon Mauery997952a2021-07-30 14:06:14 -0700255/** @brief Specialization of PackSingle for SecureBuffer */
256template <>
257struct PackSingle<SecureBuffer>
258{
259 static int op(Payload& p, const SecureBuffer& t)
260 {
261 if (p.bitCount != 0)
262 {
263 return 1;
264 }
265 p.raw.reserve(p.raw.size() + t.size());
266 p.raw.insert(p.raw.end(), t.begin(), t.end());
267 return 0;
268 }
269};
270
William A. Kennington IIIe2aec262019-04-24 14:44:26 -0700271/** @brief Specialization of PackSingle for std::string_view */
272template <>
273struct PackSingle<std::string_view>
274{
275 static int op(Payload& p, const std::string_view& t)
276 {
277 if (p.bitCount != 0)
278 {
279 return 1;
280 }
281 p.raw.reserve(p.raw.size() + t.size());
282 p.raw.insert(p.raw.end(), t.begin(), t.end());
283 return 0;
284 }
285};
286
James Feistf2998072019-04-03 11:54:52 -0700287/** @brief Specialization of PackSingle for std::variant<T, N> */
288template <typename... T>
289struct PackSingle<std::variant<T...>>
290{
291 static int op(Payload& p, const std::variant<T...>& v)
292 {
293 return std::visit(
294 [&p](const auto& arg) {
295 return PackSingle<std::decay_t<decltype(arg)>>::op(p, arg);
296 },
297 v);
298 }
299};
300
William A. Kennington IIIe15e53e2019-04-24 14:45:20 -0700301/** @brief Specialization of PackSingle for Payload */
302template <>
303struct PackSingle<Payload>
304{
305 static int op(Payload& p, const Payload& t)
306 {
307 if (p.bitCount != 0 || t.bitCount != 0)
308 {
309 return 1;
310 }
311 p.raw.reserve(p.raw.size() + t.raw.size());
312 p.raw.insert(p.raw.end(), t.raw.begin(), t.raw.end());
313 return 0;
314 }
315};
316
Vernon Mauerye7329c72018-10-08 12:05:16 -0700317} // namespace details
318
319} // namespace message
320
321} // namespace ipmi