1 #pragma once 2 3 #include "message.hpp" 4 #include "session.hpp" 5 6 #include <cstddef> 7 8 namespace message 9 { 10 11 namespace parser 12 { 13 14 constexpr size_t RMCP_VERSION = 6; 15 16 // RMCP Messages with class=IPMI should be sent with an RMCP Sequence 17 // Number of FFh to indicate that an RMCP ACK message should not be 18 // generated by the message receiver. 19 constexpr size_t RMCP_SEQ = 0xFF; 20 21 // RMCP Message Class 7h is for IPMI 22 constexpr size_t RMCP_MESSAGE_CLASS_IPMI = 7; 23 24 // RMCP Session Header Size 25 constexpr size_t RMCP_SESSION_HEADER_SIZE = 4; 26 27 // RMCP/ASF Pong Message ASF Header Data Length 28 // as per IPMI spec 13.2.4 29 constexpr size_t RMCP_ASF_PONG_DATA_LEN = 16; 30 31 // ASF IANA 32 constexpr uint32_t ASF_IANA = 4542; 33 34 // ASF Supported Entities 35 constexpr uint32_t ASF_SUPP_ENT = 0x81; 36 37 // ASF Supported Entities 38 constexpr uint32_t ASF_SUPP_INT = 0x00; 39 40 // Maximum payload size 41 constexpr size_t MAX_PAYLOAD_SIZE = 255; 42 43 enum class SessionHeader 44 { 45 IPMI15 = 0x00, 46 IPMI20 = 0x06, 47 INVALID = 0xFF, 48 }; 49 50 // RMCP Header 51 struct RmcpHeader_t 52 { 53 // RMCP Header 54 uint8_t version; 55 uint8_t reserved; 56 uint8_t rmcpSeqNum; 57 uint8_t classOfMsg; 58 } __attribute__((packed)); 59 60 struct BasicHeader_t 61 { 62 // RMCP Header 63 struct RmcpHeader_t rmcp; 64 65 // IPMI partial session header 66 union 67 { 68 uint8_t reserved1:4; 69 uint8_t authType:4; 70 uint8_t formatType; 71 } format; 72 } __attribute__((packed)); 73 74 /** 75 * @brief Unflatten an incoming packet and prepare the IPMI message 76 * 77 * @param[in] inPacket - Incoming IPMI packet 78 * 79 * @return A tuple with IPMI message and the session header type to sent the 80 * response packet. In case of success incoming message and session 81 * header type. In case of failure nullptr and session header type 82 * would be invalid. 83 */ 84 std::tuple<std::shared_ptr<Message>, SessionHeader> 85 unflatten(std::vector<uint8_t>& inPacket); 86 87 /** 88 * @brief Flatten an IPMI message and generate the IPMI packet with the 89 * session header 90 * 91 * @param[in] outMessage - IPMI message to be flattened 92 * @param[in] authType - Session header type to be added to the IPMI 93 * packet 94 * 95 * @return IPMI packet on success 96 */ 97 std::vector<uint8_t> flatten(const std::shared_ptr<Message>& outMessage, 98 SessionHeader authType, 99 const std::shared_ptr<session::Session>& session); 100 101 } // namespace parser 102 103 namespace ipmi15parser 104 { 105 106 struct SessionHeader_t 107 { 108 struct parser::BasicHeader_t base; 109 uint32_t sessSeqNum; 110 uint32_t sessId; 111 // <Optional Field: AuthCode> 112 uint8_t payloadLength; 113 } __attribute__((packed)); 114 115 struct SessionTrailer_t 116 { 117 uint8_t legacyPad; 118 } __attribute__((packed)); 119 120 /** 121 * @brief Unflatten an incoming packet and prepare the IPMI message 122 * 123 * @param[in] inPacket - Incoming IPMI packet 124 * 125 * @return IPMI message in the packet on success 126 */ 127 std::shared_ptr<Message> unflatten(std::vector<uint8_t>& inPacket); 128 129 /** 130 * @brief Flatten an IPMI message and generate the IPMI packet with the 131 * session header 132 * 133 * @param[in] outMessage - IPMI message to be flattened 134 * 135 * @return IPMI packet on success 136 */ 137 std::vector<uint8_t> flatten(const std::shared_ptr<Message>& outMessage, 138 const std::shared_ptr<session::Session>& session); 139 140 } // namespace ipmi15parser 141 142 namespace ipmi20parser 143 { 144 145 constexpr size_t MAX_INTEGRITY_DATA_LENGTH = 12; 146 constexpr size_t PAYLOAD_ENCRYPT_MASK = 0x80; 147 constexpr size_t PAYLOAD_AUTH_MASK = 0x40; 148 149 struct SessionHeader_t 150 { 151 struct parser::BasicHeader_t base; 152 153 uint8_t payloadType; 154 155 uint32_t sessId; 156 uint32_t sessSeqNum; 157 uint16_t payloadLength; 158 } __attribute__((packed)); 159 160 struct SessionTrailer_t 161 { 162 // Integrity Pad 163 uint8_t padLength; 164 uint8_t nextHeader; 165 } __attribute__((packed)); 166 167 /** 168 * @brief Unflatten an incoming packet and prepare the IPMI message 169 * 170 * @param[in] inPacket - Incoming IPMI packet 171 * 172 * @return IPMI message in the packet on success 173 */ 174 std::shared_ptr<Message> unflatten(std::vector<uint8_t>& inPacket); 175 176 /** 177 * @brief Flatten an IPMI message and generate the IPMI packet with the 178 * session header 179 * 180 * @param[in] outMessage - IPMI message to be flattened 181 * @param[in] session - session handle 182 * 183 * @return IPMI packet on success 184 */ 185 std::vector<uint8_t> flatten(const std::shared_ptr<Message>& outMessage, 186 const std::shared_ptr<session::Session>& session); 187 188 namespace internal 189 { 190 191 /** 192 * @brief Add sequence number to the message 193 * 194 * @param[in] packet - outgoing packet to which to add sequence number 195 * @param[in] session - session handle 196 * 197 */ 198 void addSequenceNumber(std::vector<uint8_t>& packet, 199 const std::shared_ptr<session::Session>& session); 200 201 /** 202 * @brief Verify the integrity data of the incoming IPMI packet 203 * 204 * @param[in] packet - Incoming IPMI packet 205 * @param[in] message - IPMI Message populated from the incoming packet 206 * @param[in] payloadLen - Length of the IPMI payload 207 * @param[in] session - session handle 208 * 209 */ 210 bool verifyPacketIntegrity(const std::vector<uint8_t>& packet, 211 const std::shared_ptr<Message>& message, 212 size_t payloadLen, 213 const std::shared_ptr<session::Session>& session); 214 215 /** 216 * @brief Add Integrity data to the outgoing IPMI packet 217 * 218 * @param[in] packet - Outgoing IPMI packet 219 * @param[in] message - IPMI Message populated for the outgoing packet 220 * @param[in] payloadLen - Length of the IPMI payload 221 */ 222 void addIntegrityData(std::vector<uint8_t>& packet, 223 const std::shared_ptr<Message>& message, 224 size_t payloadLen, 225 const std::shared_ptr<session::Session>& session); 226 227 /** 228 * @brief Decrypt the encrypted payload in the incoming IPMI packet 229 * 230 * @param[in] packet - Incoming IPMI packet 231 * @param[in] message - IPMI Message populated from the incoming packet 232 * @param[in] payloadLen - Length of encrypted IPMI payload 233 * @param[in] session - session handle 234 * 235 * @return on successful completion, return the plain text payload 236 */ 237 std::vector<uint8_t> decryptPayload( 238 const std::vector<uint8_t>& packet, const std::shared_ptr<Message>& message, 239 size_t payloadLen, const std::shared_ptr<session::Session>& session); 240 241 /** 242 * @brief Encrypt the plain text payload for the outgoing IPMI packet 243 * 244 * @param[in] message - IPMI Message populated for the outgoing packet 245 * @param[in] session - session handle 246 * 247 * @return on successful completion, return the encrypted payload 248 */ 249 std::vector<uint8_t> 250 encryptPayload(const std::shared_ptr<Message>& message, 251 const std::shared_ptr<session::Session>& session); 252 253 } // namespace internal 254 255 } // namespace ipmi20parser 256 257 #ifdef RMCP_PING 258 namespace asfparser 259 { 260 261 // ASF message fields for RMCP Ping message 262 struct AsfMessagePing_t 263 { 264 struct parser::RmcpHeader_t rmcp; 265 266 uint32_t iana; 267 uint8_t msgType; 268 uint8_t msgTag; 269 uint8_t reserved; 270 uint8_t dataLen; 271 } __attribute__((packed)); 272 273 // ASF message fields for RMCP Pong message 274 struct AsfMessagePong_t 275 { 276 struct AsfMessagePing_t ping; 277 278 uint32_t iana; 279 uint32_t oemDefined; 280 uint8_t suppEntities; 281 uint8_t suppInteract; 282 uint32_t reserved1; 283 uint16_t reserved2; 284 } __attribute__((packed)); 285 286 /** 287 * @brief Unflatten an incoming packet and prepare the ASF message 288 * 289 * @param[in] inPacket - Incoming ASF packet 290 * 291 * @return ASF message in the packet on success 292 */ 293 std::shared_ptr<Message> unflatten(std::vector<uint8_t>& inPacket); 294 295 /** 296 * @brief Generate the ASF packet with the RMCP header 297 * 298 * @param[in] asfMsgTag - ASF Message Tag from Ping request 299 * 300 * @return ASF packet on success 301 */ 302 std::vector<uint8_t> flatten(uint8_t asfMsgTag); 303 304 } // namespace asfparser 305 #endif // RMCP_PING 306 307 } // namespace message 308