1 /** 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> 21 #include <phosphor-logging/log.hpp> 22 #include <tuple> 23 #include <utility> 24 #include <vector> 25 26 namespace ipmi 27 { 28 29 namespace message 30 { 31 32 namespace details 33 { 34 35 /************************************** 36 * ipmi return type helpers 37 **************************************/ 38 39 template <typename NumericType, size_t byteIndex = 0> 40 void PackBytes(uint8_t* pointer, const NumericType& i) 41 { 42 if constexpr (byteIndex < sizeof(NumericType)) 43 { 44 *pointer = static_cast<uint8_t>(i >> (8 * byteIndex)); 45 PackBytes<NumericType, byteIndex + 1>(pointer + 1, i); 46 } 47 } 48 49 template <typename NumericType, size_t byteIndex = 0> 50 void PackBytesUnaligned(Payload& p, const NumericType& i) 51 { 52 if constexpr (byteIndex < sizeof(NumericType)) 53 { 54 p.appendBits(CHAR_BIT, static_cast<uint8_t>(i >> (8 * byteIndex))); 55 PackBytesUnaligned<NumericType, byteIndex + 1>(p, i); 56 } 57 } 58 59 /** @struct PackSingle 60 * @brief Utility to pack a single C++ element into a Payload 61 * 62 * User-defined types are expected to specialize this template in order to 63 * get their functionality. 64 * 65 * @tparam S - Type of element to pack. 66 */ 67 template <typename T> 68 struct PackSingle 69 { 70 /** @brief Do the operation to pack element. 71 * 72 * @param[in] p - Payload to pack into. 73 * @param[out] t - The reference to pack item into. 74 */ 75 static int op(Payload& p, T& t) 76 { 77 // if not on a byte boundary, must pack values LSbit/LSByte first 78 if (p.bitCount) 79 { 80 PackBytesUnaligned<T>(p, t); 81 } 82 else 83 { 84 // copy in bits to vector.... 85 p.raw.resize(p.raw.size() + sizeof(T)); 86 uint8_t* out = p.raw.data() + p.raw.size() - sizeof(T); 87 PackBytes<T>(out, t); 88 } 89 return 0; 90 } 91 }; 92 93 /** @brief Specialization of PackSingle for std::string 94 * represented as a UCSD-Pascal style string 95 */ 96 template <> 97 struct PackSingle<std::string> 98 { 99 static int op(Payload& p, std::string& t) 100 { 101 // check length first 102 uint8_t len; 103 if (t.length() > std::numeric_limits<decltype(len)>::max()) 104 { 105 using namespace phosphor::logging; 106 log<level::ERR>("long string truncated on IPMI message pack"); 107 return 1; 108 } 109 len = static_cast<uint8_t>(t.length()); 110 PackSingle<uint8_t>::op(p, len); 111 p.append(t.c_str(), t.c_str() + t.length()); 112 return 0; 113 } 114 }; 115 116 /** @brief Specialization of PackSingle for fixed_uint_t types 117 */ 118 template <unsigned N> 119 struct PackSingle<fixed_uint_t<N>> 120 { 121 static int op(Payload& p, fixed_uint_t<N>& t) 122 { 123 size_t count = N; 124 static_assert(N <= (details::bitStreamSize - CHAR_BIT)); 125 uint64_t bits = t; 126 while (count > 0) 127 { 128 size_t appendCount = std::min(count, static_cast<size_t>(CHAR_BIT)); 129 p.appendBits(appendCount, static_cast<uint8_t>(bits)); 130 bits >>= CHAR_BIT; 131 count -= appendCount; 132 } 133 return 0; 134 } 135 }; 136 137 /** @brief Specialization of PackSingle for bool. */ 138 template <> 139 struct PackSingle<bool> 140 { 141 static int op(Payload& p, bool& b) 142 { 143 p.appendBits(1, b); 144 return 0; 145 } 146 }; 147 148 /** @brief Specialization of PackSingle for std::bitset<N> */ 149 template <size_t N> 150 struct PackSingle<std::bitset<N>> 151 { 152 static int op(Payload& p, std::bitset<N>& t) 153 { 154 size_t count = N; 155 static_assert(N <= (details::bitStreamSize - CHAR_BIT)); 156 unsigned long long bits = t.to_ullong(); 157 while (count > 0) 158 { 159 size_t appendCount = std::min(count, size_t(CHAR_BIT)); 160 p.appendBits(appendCount, static_cast<uint8_t>(bits)); 161 bits >>= CHAR_BIT; 162 count -= appendCount; 163 } 164 return 0; 165 } 166 }; 167 168 /** @brief Specialization of PackSingle for std::array<T, N> */ 169 template <typename T, size_t N> 170 struct PackSingle<std::array<T, N>> 171 { 172 static int op(Payload& p, std::array<T, N>& t) 173 { 174 int ret = 0; 175 for (auto& v : t) 176 { 177 int ret = PackSingle<T>::op(p, v); 178 if (ret) 179 { 180 break; 181 } 182 } 183 return ret; 184 } 185 }; 186 187 /** @brief Specialization of PackSingle for std::vector<T> */ 188 template <typename T> 189 struct PackSingle<std::vector<T>> 190 { 191 static int op(Payload& p, std::vector<T>& t) 192 { 193 int ret = 0; 194 for (auto& v : t) 195 { 196 int ret = PackSingle<T>::op(p, v); 197 if (ret) 198 { 199 break; 200 } 201 } 202 return ret; 203 } 204 }; 205 206 /** @brief Specialization of PackSingle for std::vector<uint8_t> */ 207 template <> 208 struct PackSingle<std::vector<uint8_t>> 209 { 210 static int op(Payload& p, std::vector<uint8_t>& t) 211 { 212 p.raw.reserve(p.raw.size() + t.size()); 213 p.raw.insert(p.raw.end(), t.begin(), t.end()); 214 return 0; 215 } 216 }; 217 218 } // namespace details 219 220 } // namespace message 221 222 } // namespace ipmi 223