1e7329c71SVernon Mauery /**
2e7329c71SVernon Mauery * Copyright © 2018 Intel Corporation
3e7329c71SVernon Mauery *
4e7329c71SVernon Mauery * Licensed under the Apache License, Version 2.0 (the "License");
5e7329c71SVernon Mauery * you may not use this file except in compliance with the License.
6e7329c71SVernon Mauery * You may obtain a copy of the License at
7e7329c71SVernon Mauery *
8e7329c71SVernon Mauery * http://www.apache.org/licenses/LICENSE-2.0
9e7329c71SVernon Mauery *
10e7329c71SVernon Mauery * Unless required by applicable law or agreed to in writing, software
11e7329c71SVernon Mauery * distributed under the License is distributed on an "AS IS" BASIS,
12e7329c71SVernon Mauery * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e7329c71SVernon Mauery * See the License for the specific language governing permissions and
14e7329c71SVernon Mauery * limitations under the License.
15e7329c71SVernon Mauery */
16e7329c71SVernon Mauery #pragma once
17e7329c71SVernon Mauery
18e7329c71SVernon Mauery #include <ipmid/message/types.hpp>
19fbc6c9d7SPatrick Williams #include <phosphor-logging/log.hpp>
20fbc6c9d7SPatrick Williams
21fbc6c9d7SPatrick Williams #include <array>
22e7329c71SVernon Mauery #include <memory>
23bae91350SVernon Mauery #include <optional>
24*c329ceeaSWilly Tu #include <span>
25e2aec26cSWilliam A. Kennington III #include <string_view>
26e7329c71SVernon Mauery #include <tuple>
27e7329c71SVernon Mauery #include <utility>
2800b096d1SAlexander Amelkin #include <variant>
29e7329c71SVernon Mauery #include <vector>
30e7329c71SVernon Mauery
31e7329c71SVernon Mauery namespace ipmi
32e7329c71SVernon Mauery {
33e7329c71SVernon Mauery
34e7329c71SVernon Mauery namespace message
35e7329c71SVernon Mauery {
36e7329c71SVernon Mauery
37e7329c71SVernon Mauery namespace details
38e7329c71SVernon Mauery {
39e7329c71SVernon Mauery
40e7329c71SVernon Mauery /**************************************
41e7329c71SVernon Mauery * ipmi return type helpers
42e7329c71SVernon Mauery **************************************/
43e7329c71SVernon Mauery
44e7329c71SVernon Mauery template <typename NumericType, size_t byteIndex = 0>
PackBytes(uint8_t * pointer,const NumericType & i)45e7329c71SVernon Mauery void PackBytes(uint8_t* pointer, const NumericType& i)
46e7329c71SVernon Mauery {
47e7329c71SVernon Mauery if constexpr (byteIndex < sizeof(NumericType))
48e7329c71SVernon Mauery {
49e7329c71SVernon Mauery *pointer = static_cast<uint8_t>(i >> (8 * byteIndex));
50e7329c71SVernon Mauery PackBytes<NumericType, byteIndex + 1>(pointer + 1, i);
51e7329c71SVernon Mauery }
52e7329c71SVernon Mauery }
53e7329c71SVernon Mauery
54e7329c71SVernon Mauery template <typename NumericType, size_t byteIndex = 0>
PackBytesUnaligned(Payload & p,const NumericType & i)55e7329c71SVernon Mauery void PackBytesUnaligned(Payload& p, const NumericType& i)
56e7329c71SVernon Mauery {
57e7329c71SVernon Mauery if constexpr (byteIndex < sizeof(NumericType))
58e7329c71SVernon Mauery {
59e7329c71SVernon Mauery p.appendBits(CHAR_BIT, static_cast<uint8_t>(i >> (8 * byteIndex)));
60e7329c71SVernon Mauery PackBytesUnaligned<NumericType, byteIndex + 1>(p, i);
61e7329c71SVernon Mauery }
62e7329c71SVernon Mauery }
63e7329c71SVernon Mauery
64e7329c71SVernon Mauery /** @struct PackSingle
65e7329c71SVernon Mauery * @brief Utility to pack a single C++ element into a Payload
66e7329c71SVernon Mauery *
67e7329c71SVernon Mauery * User-defined types are expected to specialize this template in order to
68e7329c71SVernon Mauery * get their functionality.
69e7329c71SVernon Mauery *
70e7329c71SVernon Mauery * @tparam S - Type of element to pack.
71e7329c71SVernon Mauery */
72e7329c71SVernon Mauery template <typename T>
73e7329c71SVernon Mauery struct PackSingle
74e7329c71SVernon Mauery {
75e7329c71SVernon Mauery /** @brief Do the operation to pack element.
76e7329c71SVernon Mauery *
77e7329c71SVernon Mauery * @param[in] p - Payload to pack into.
78e7329c71SVernon Mauery * @param[out] t - The reference to pack item into.
79e7329c71SVernon Mauery */
opipmi::message::details::PackSingle80f299807fSJames Feist static int op(Payload& p, const T& t)
81e7329c71SVernon Mauery {
82336405b8SVernon Mauery static_assert(std::is_integral_v<T>,
83336405b8SVernon Mauery "Attempt to pack a type that has no IPMI pack operation");
84e7329c71SVernon Mauery // if not on a byte boundary, must pack values LSbit/LSByte first
85e7329c71SVernon Mauery if (p.bitCount)
86e7329c71SVernon Mauery {
87e7329c71SVernon Mauery PackBytesUnaligned<T>(p, t);
88e7329c71SVernon Mauery }
89e7329c71SVernon Mauery else
90e7329c71SVernon Mauery {
91e7329c71SVernon Mauery // copy in bits to vector....
92e7329c71SVernon Mauery p.raw.resize(p.raw.size() + sizeof(T));
93e7329c71SVernon Mauery uint8_t* out = p.raw.data() + p.raw.size() - sizeof(T);
94e7329c71SVernon Mauery PackBytes<T>(out, t);
95e7329c71SVernon Mauery }
96e7329c71SVernon Mauery return 0;
97e7329c71SVernon Mauery }
98e7329c71SVernon Mauery };
99e7329c71SVernon Mauery
100508c4576SVernon Mauery /** @brief Specialization of PackSingle for std::tuple<T> */
101508c4576SVernon Mauery template <typename... T>
102508c4576SVernon Mauery struct PackSingle<std::tuple<T...>>
103508c4576SVernon Mauery {
opipmi::message::details::PackSingle104508c4576SVernon Mauery static int op(Payload& p, const std::tuple<T...>& v)
105508c4576SVernon Mauery {
106508c4576SVernon Mauery return std::apply([&p](const T&... args) { return p.pack(args...); },
107508c4576SVernon Mauery v);
108508c4576SVernon Mauery }
109508c4576SVernon Mauery };
110508c4576SVernon Mauery
111e7329c71SVernon Mauery /** @brief Specialization of PackSingle for std::string
112e7329c71SVernon Mauery * represented as a UCSD-Pascal style string
113e7329c71SVernon Mauery */
114e7329c71SVernon Mauery template <>
115e7329c71SVernon Mauery struct PackSingle<std::string>
116e7329c71SVernon Mauery {
opipmi::message::details::PackSingle117f299807fSJames Feist static int op(Payload& p, const std::string& t)
118e7329c71SVernon Mauery {
119e7329c71SVernon Mauery // check length first
120e7329c71SVernon Mauery uint8_t len;
121e7329c71SVernon Mauery if (t.length() > std::numeric_limits<decltype(len)>::max())
122e7329c71SVernon Mauery {
123e7329c71SVernon Mauery using namespace phosphor::logging;
124e7329c71SVernon Mauery log<level::ERR>("long string truncated on IPMI message pack");
125e7329c71SVernon Mauery return 1;
126e7329c71SVernon Mauery }
127e7329c71SVernon Mauery len = static_cast<uint8_t>(t.length());
128e7329c71SVernon Mauery PackSingle<uint8_t>::op(p, len);
129e7329c71SVernon Mauery p.append(t.c_str(), t.c_str() + t.length());
130e7329c71SVernon Mauery return 0;
131e7329c71SVernon Mauery }
132e7329c71SVernon Mauery };
133e7329c71SVernon Mauery
134e7329c71SVernon Mauery /** @brief Specialization of PackSingle for fixed_uint_t types
135e7329c71SVernon Mauery */
136b4905919STim Lee template <bitcount_t N>
137e7329c71SVernon Mauery struct PackSingle<fixed_uint_t<N>>
138e7329c71SVernon Mauery {
opipmi::message::details::PackSingle139f299807fSJames Feist static int op(Payload& p, const fixed_uint_t<N>& t)
140e7329c71SVernon Mauery {
141e7329c71SVernon Mauery size_t count = N;
142e7329c71SVernon Mauery static_assert(N <= (details::bitStreamSize - CHAR_BIT));
14330f88f02SLei YU static_assert(N <= std::numeric_limits<uint64_t>::digits,
14430f88f02SLei YU "Type exceeds uint64_t limit");
14530f88f02SLei YU uint64_t bits = static_cast<uint64_t>(t);
146e7329c71SVernon Mauery while (count > 0)
147e7329c71SVernon Mauery {
148e7329c71SVernon Mauery size_t appendCount = std::min(count, static_cast<size_t>(CHAR_BIT));
149e7329c71SVernon Mauery p.appendBits(appendCount, static_cast<uint8_t>(bits));
150e7329c71SVernon Mauery bits >>= CHAR_BIT;
151e7329c71SVernon Mauery count -= appendCount;
152e7329c71SVernon Mauery }
153e7329c71SVernon Mauery return 0;
154e7329c71SVernon Mauery }
155e7329c71SVernon Mauery };
156e7329c71SVernon Mauery
157e7329c71SVernon Mauery /** @brief Specialization of PackSingle for bool. */
158e7329c71SVernon Mauery template <>
159e7329c71SVernon Mauery struct PackSingle<bool>
160e7329c71SVernon Mauery {
opipmi::message::details::PackSingle161f299807fSJames Feist static int op(Payload& p, const bool& b)
162e7329c71SVernon Mauery {
163e7329c71SVernon Mauery p.appendBits(1, b);
164e7329c71SVernon Mauery return 0;
165e7329c71SVernon Mauery }
166e7329c71SVernon Mauery };
167e7329c71SVernon Mauery
168e7329c71SVernon Mauery /** @brief Specialization of PackSingle for std::bitset<N> */
169e7329c71SVernon Mauery template <size_t N>
170e7329c71SVernon Mauery struct PackSingle<std::bitset<N>>
171e7329c71SVernon Mauery {
opipmi::message::details::PackSingle172f299807fSJames Feist static int op(Payload& p, const std::bitset<N>& t)
173e7329c71SVernon Mauery {
174e7329c71SVernon Mauery size_t count = N;
175e7329c71SVernon Mauery static_assert(N <= (details::bitStreamSize - CHAR_BIT));
176e7329c71SVernon Mauery unsigned long long bits = t.to_ullong();
177e7329c71SVernon Mauery while (count > 0)
178e7329c71SVernon Mauery {
179e7329c71SVernon Mauery size_t appendCount = std::min(count, size_t(CHAR_BIT));
180e7329c71SVernon Mauery p.appendBits(appendCount, static_cast<uint8_t>(bits));
181e7329c71SVernon Mauery bits >>= CHAR_BIT;
182e7329c71SVernon Mauery count -= appendCount;
183e7329c71SVernon Mauery }
184e7329c71SVernon Mauery return 0;
185e7329c71SVernon Mauery }
186e7329c71SVernon Mauery };
187e7329c71SVernon Mauery
188bae91350SVernon Mauery /** @brief Specialization of PackSingle for std::optional<T> */
189bae91350SVernon Mauery template <typename T>
190bae91350SVernon Mauery struct PackSingle<std::optional<T>>
191bae91350SVernon Mauery {
opipmi::message::details::PackSingle192bae91350SVernon Mauery static int op(Payload& p, const std::optional<T>& t)
193bae91350SVernon Mauery {
194bae91350SVernon Mauery int ret = 0;
195bae91350SVernon Mauery if (t)
196bae91350SVernon Mauery {
197bae91350SVernon Mauery ret = PackSingle<T>::op(p, *t);
198bae91350SVernon Mauery }
199bae91350SVernon Mauery return ret;
200bae91350SVernon Mauery }
201bae91350SVernon Mauery };
202bae91350SVernon Mauery
203e7329c71SVernon Mauery /** @brief Specialization of PackSingle for std::array<T, N> */
204e7329c71SVernon Mauery template <typename T, size_t N>
205e7329c71SVernon Mauery struct PackSingle<std::array<T, N>>
206e7329c71SVernon Mauery {
opipmi::message::details::PackSingle207f299807fSJames Feist static int op(Payload& p, const std::array<T, N>& t)
208e7329c71SVernon Mauery {
209e7329c71SVernon Mauery int ret = 0;
210f299807fSJames Feist for (const auto& v : t)
211e7329c71SVernon Mauery {
212e7329c71SVernon Mauery int ret = PackSingle<T>::op(p, v);
213e7329c71SVernon Mauery if (ret)
214e7329c71SVernon Mauery {
215e7329c71SVernon Mauery break;
216e7329c71SVernon Mauery }
217e7329c71SVernon Mauery }
218e7329c71SVernon Mauery return ret;
219e7329c71SVernon Mauery }
220e7329c71SVernon Mauery };
221e7329c71SVernon Mauery
222e7329c71SVernon Mauery /** @brief Specialization of PackSingle for std::vector<T> */
223e7329c71SVernon Mauery template <typename T>
224e7329c71SVernon Mauery struct PackSingle<std::vector<T>>
225e7329c71SVernon Mauery {
opipmi::message::details::PackSingle226f299807fSJames Feist static int op(Payload& p, const std::vector<T>& t)
227e7329c71SVernon Mauery {
228e7329c71SVernon Mauery int ret = 0;
229f299807fSJames Feist for (const auto& v : t)
230e7329c71SVernon Mauery {
231e7329c71SVernon Mauery int ret = PackSingle<T>::op(p, v);
232e7329c71SVernon Mauery if (ret)
233e7329c71SVernon Mauery {
234e7329c71SVernon Mauery break;
235e7329c71SVernon Mauery }
236e7329c71SVernon Mauery }
237e7329c71SVernon Mauery return ret;
238e7329c71SVernon Mauery }
239e7329c71SVernon Mauery };
240e7329c71SVernon Mauery
241e7329c71SVernon Mauery /** @brief Specialization of PackSingle for std::vector<uint8_t> */
242e7329c71SVernon Mauery template <>
243e7329c71SVernon Mauery struct PackSingle<std::vector<uint8_t>>
244e7329c71SVernon Mauery {
opipmi::message::details::PackSingle245f299807fSJames Feist static int op(Payload& p, const std::vector<uint8_t>& t)
246e7329c71SVernon Mauery {
247906e0f80SWilliam A. Kennington III if (p.bitCount != 0)
248906e0f80SWilliam A. Kennington III {
249906e0f80SWilliam A. Kennington III return 1;
250906e0f80SWilliam A. Kennington III }
251e7329c71SVernon Mauery p.raw.reserve(p.raw.size() + t.size());
252e7329c71SVernon Mauery p.raw.insert(p.raw.end(), t.begin(), t.end());
253e7329c71SVernon Mauery return 0;
254e7329c71SVernon Mauery }
255e7329c71SVernon Mauery };
256e7329c71SVernon Mauery
257997952afSVernon Mauery /** @brief Specialization of PackSingle for SecureBuffer */
258997952afSVernon Mauery template <>
259997952afSVernon Mauery struct PackSingle<SecureBuffer>
260997952afSVernon Mauery {
opipmi::message::details::PackSingle261997952afSVernon Mauery static int op(Payload& p, const SecureBuffer& t)
262997952afSVernon Mauery {
263997952afSVernon Mauery if (p.bitCount != 0)
264997952afSVernon Mauery {
265997952afSVernon Mauery return 1;
266997952afSVernon Mauery }
267997952afSVernon Mauery p.raw.reserve(p.raw.size() + t.size());
268997952afSVernon Mauery p.raw.insert(p.raw.end(), t.begin(), t.end());
269997952afSVernon Mauery return 0;
270997952afSVernon Mauery }
271997952afSVernon Mauery };
272997952afSVernon Mauery
273*c329ceeaSWilly Tu /** @brief Specialization of PackSingle for std::span<const uint8_t> */
274*c329ceeaSWilly Tu template <>
275*c329ceeaSWilly Tu struct PackSingle<std::span<const uint8_t>>
276*c329ceeaSWilly Tu {
opipmi::message::details::PackSingle277*c329ceeaSWilly Tu static int op(Payload& p, const std::span<const uint8_t>& t)
278*c329ceeaSWilly Tu {
279*c329ceeaSWilly Tu if (p.bitCount != 0)
280*c329ceeaSWilly Tu {
281*c329ceeaSWilly Tu return 1;
282*c329ceeaSWilly Tu }
283*c329ceeaSWilly Tu p.raw.reserve(p.raw.size() + t.size());
284*c329ceeaSWilly Tu p.raw.insert(p.raw.end(), t.begin(), t.end());
285*c329ceeaSWilly Tu return 0;
286*c329ceeaSWilly Tu }
287*c329ceeaSWilly Tu };
288*c329ceeaSWilly Tu
289e2aec26cSWilliam A. Kennington III /** @brief Specialization of PackSingle for std::string_view */
290e2aec26cSWilliam A. Kennington III template <>
291e2aec26cSWilliam A. Kennington III struct PackSingle<std::string_view>
292e2aec26cSWilliam A. Kennington III {
opipmi::message::details::PackSingle293e2aec26cSWilliam A. Kennington III static int op(Payload& p, const std::string_view& t)
294e2aec26cSWilliam A. Kennington III {
295e2aec26cSWilliam A. Kennington III if (p.bitCount != 0)
296e2aec26cSWilliam A. Kennington III {
297e2aec26cSWilliam A. Kennington III return 1;
298e2aec26cSWilliam A. Kennington III }
299e2aec26cSWilliam A. Kennington III p.raw.reserve(p.raw.size() + t.size());
300e2aec26cSWilliam A. Kennington III p.raw.insert(p.raw.end(), t.begin(), t.end());
301e2aec26cSWilliam A. Kennington III return 0;
302e2aec26cSWilliam A. Kennington III }
303e2aec26cSWilliam A. Kennington III };
304e2aec26cSWilliam A. Kennington III
305f299807fSJames Feist /** @brief Specialization of PackSingle for std::variant<T, N> */
306f299807fSJames Feist template <typename... T>
307f299807fSJames Feist struct PackSingle<std::variant<T...>>
308f299807fSJames Feist {
opipmi::message::details::PackSingle309f299807fSJames Feist static int op(Payload& p, const std::variant<T...>& v)
310f299807fSJames Feist {
311f299807fSJames Feist return std::visit(
312f299807fSJames Feist [&p](const auto& arg) {
313f299807fSJames Feist return PackSingle<std::decay_t<decltype(arg)>>::op(p, arg);
314f299807fSJames Feist },
315f299807fSJames Feist v);
316f299807fSJames Feist }
317f299807fSJames Feist };
318f299807fSJames Feist
319e15e53ebSWilliam A. Kennington III /** @brief Specialization of PackSingle for Payload */
320e15e53ebSWilliam A. Kennington III template <>
321e15e53ebSWilliam A. Kennington III struct PackSingle<Payload>
322e15e53ebSWilliam A. Kennington III {
opipmi::message::details::PackSingle323e15e53ebSWilliam A. Kennington III static int op(Payload& p, const Payload& t)
324e15e53ebSWilliam A. Kennington III {
325e15e53ebSWilliam A. Kennington III if (p.bitCount != 0 || t.bitCount != 0)
326e15e53ebSWilliam A. Kennington III {
327e15e53ebSWilliam A. Kennington III return 1;
328e15e53ebSWilliam A. Kennington III }
329e15e53ebSWilliam A. Kennington III p.raw.reserve(p.raw.size() + t.raw.size());
330e15e53ebSWilliam A. Kennington III p.raw.insert(p.raw.end(), t.raw.begin(), t.raw.end());
331e15e53ebSWilliam A. Kennington III return 0;
332e15e53ebSWilliam A. Kennington III }
333e15e53ebSWilliam A. Kennington III };
334e15e53ebSWilliam A. Kennington III
335e7329c71SVernon Mauery } // namespace details
336e7329c71SVernon Mauery
337e7329c71SVernon Mauery } // namespace message
338e7329c71SVernon Mauery
339e7329c71SVernon Mauery } // namespace ipmi
340