1 #pragma once 2 3 #include "console_buffer.hpp" 4 #include "session.hpp" 5 6 namespace sol 7 { 8 9 /** @struct Outbound 10 * 11 * Operation/Status in an outbound SOL payload format(BMC to Remote Console). 12 */ 13 struct Outbound 14 { 15 #if BYTE_ORDER == LITTLE_ENDIAN 16 uint8_t testMode : 2; //!< Not supported. 17 uint8_t breakDetected : 1; //!< Not supported. 18 uint8_t transmitOverrun : 1; //!< Not supported. 19 uint8_t SOLDeactivating : 1; //!< 0 : SOL is active, 1 : SOL deactivated. 20 uint8_t charUnavailable : 1; //!< 0 : Available, 1 : Unavailable. 21 uint8_t ack : 1; //!< 0 : ACK, 1 : NACK. 22 uint8_t reserved : 1; //!< Reserved. 23 #endif 24 25 #if BYTE_ORDER == BIG_ENDIAN 26 uint8_t reserved : 1; //!< Reserved. 27 uint8_t ack : 1; //!< 0 : ACK, 1 : NACK. 28 uint8_t charUnavailable : 1; //!< 0 : Available, 1 : Unavailable. 29 uint8_t SOLDeactivating : 1; //!< 0 : SOL is active, 1 : SOL deactivated. 30 uint8_t transmitOverrun : 1; //!< Not supported. 31 uint8_t breakDetected : 1; //!< Not supported. 32 uint8_t testMode : 2; //!< Not supported. 33 #endif 34 } __attribute__((packed)); 35 36 /** @struct Inbound 37 * 38 * Operation/Status in an Inbound SOL Payload format(Remote Console to BMC). 39 */ 40 struct Inbound 41 { 42 #if BYTE_ORDER == LITTLE_ENDIAN 43 uint8_t flushOut : 1; //!< Not supported. 44 uint8_t flushIn : 1; //!< Not supported. 45 uint8_t dcd : 1; //!< Not supported. 46 uint8_t cts : 1; //!< Not supported. 47 uint8_t generateBreak : 1; //!< Not supported. 48 uint8_t ring : 1; //!< Not supported. 49 uint8_t ack : 1; //!< 0 : ACK, 1 : NACK. 50 uint8_t reserved : 1; //!< Reserved. 51 #endif 52 53 #if BYTE_ORDER == BIG_ENDIAN 54 uint8_t reserved : 1; //!< Reserved. 55 uint8_t ack : 1; //!< 0 : ACK, 1 : NACK. 56 uint8_t ring : 1; //!< Not supported. 57 uint8_t generateBreak : 1; //!< Not supported. 58 uint8_t cts : 1; //!< Not supported. 59 uint8_t dcd : 1; //!< Not supported. 60 uint8_t flushIn : 1; //!< Not supported. 61 uint8_t flushOut : 1; //!< Not supported. 62 #endif 63 } __attribute__((packed)); 64 65 /** @struct Payload 66 * 67 * SOL Payload Data Format.The following fields make up the SOL payload in an 68 * RMCP+ packet, followed by the console character data. 69 */ 70 struct Payload 71 { 72 uint8_t packetSeqNum; //!< Packet sequence number 73 uint8_t packetAckSeqNum; //!< Packet ACK/NACK sequence number 74 uint8_t acceptedCharCount; //!< Accepted character count 75 union 76 { 77 uint8_t operation; //!< Operation/Status 78 struct Outbound outOperation; //!< BMC to Remote Console 79 struct Inbound inOperation; //!< Remote Console to BMC 80 }; 81 } __attribute__((packed)); 82 83 namespace internal 84 { 85 86 /** @struct SequenceNumbers 87 * 88 * SOL sequence numbers. At the session level, SOL Payloads share the session 89 * sequence numbers for authenticated and unauthenticated packets with other 90 * packets under the IPMI session. At the payload level, SOL packets include 91 * their own message sequence numbers that are used for tracking missing and 92 * retried SOL messages. The sequence numbers must be non-zero. Retried 93 * packets use the same sequence number as the first packet. 94 */ 95 struct SequenceNumbers 96 { 97 static constexpr uint8_t MAX_SOL_SEQUENCE_NUMBER = 0x10; 98 99 /** @brief Get the SOL sequence number. 100 * 101 * @param[in] inbound - true for inbound sequence number and false for 102 * outbound sequence number 103 * 104 * @return sequence number 105 */ 106 auto get(bool inbound = true) const 107 { 108 return inbound ? in : out; 109 } 110 111 /** @brief Increment the inbound SOL sequence number. */ 112 void incInboundSeqNum() 113 { 114 if ((++in) == MAX_SOL_SEQUENCE_NUMBER) 115 { 116 in = 1; 117 } 118 } 119 120 /** @brief Increment the outbound SOL sequence number. 121 * 122 * @return outbound sequence number to populate the SOL payload. 123 */ 124 auto incOutboundSeqNum() 125 { 126 if ((++out) == MAX_SOL_SEQUENCE_NUMBER) 127 { 128 out = 1; 129 } 130 131 return out; 132 } 133 134 private: 135 uint8_t in = 1; //!< Inbound sequence number. 136 uint8_t out = 0; //!< Outbound sequence number, since the first 137 //!< operation is increment, it is initialised to 0 138 }; 139 140 } // namespace internal 141 142 /** @class Context 143 * 144 * Context keeps the state of the SOL session. The information needed to 145 * maintain the state of the SOL is part of this class. This class provides 146 * interfaces to handle incoming SOL payload, send response and send outbound 147 * SOL payload. 148 */ 149 class Context 150 { 151 public: 152 Context() = default; 153 ~Context() = default; 154 Context(const Context&) = delete; 155 Context& operator=(const Context&) = delete; 156 Context(Context&&) = default; 157 Context& operator=(Context&&) = default; 158 159 /** @brief Context Constructor. 160 * 161 * This is issued by the SOL Manager when a SOL payload instance is 162 * started for the activate payload command. 163 * 164 * @param[in] maxRetryCount - Retry count max value. 165 * @param[in] sendThreshold - Character send threshold. 166 * @param[in] instance - SOL payload instance. 167 * @param[in] sessionID - BMC session ID. 168 */ 169 Context(uint8_t maxRetryCount, uint8_t sendThreshold, uint8_t instance, 170 session::SessionID sessionID) : 171 maxRetryCount(maxRetryCount), 172 retryCounter(maxRetryCount), sendThreshold(sendThreshold), 173 payloadInstance(instance), sessionID(sessionID) 174 { 175 } 176 177 static constexpr auto clear = true; 178 static constexpr auto noClear = false; 179 180 /** @brief Retry count max value. */ 181 const uint8_t maxRetryCount = 0; 182 183 /** @brief Retry counter. */ 184 uint8_t retryCounter = 0; 185 186 /** @brief Character send threshold. */ 187 const uint8_t sendThreshold = 0; 188 189 /** @brief SOL payload instance. */ 190 const uint8_t payloadInstance = 0; 191 192 /** @brief Session ID. */ 193 const session::SessionID sessionID = 0; 194 195 /** @brief Process the Inbound SOL payload. 196 * 197 * The SOL payload from the remote console is processed and the 198 * acknowledgment handling is done. 199 * 200 * @param[in] seqNum - Packet sequence number. 201 * @param[in] ackSeqNum - Packet ACK/NACK sequence number. 202 * @param[in] count - Accepted character count. 203 * @param[in] operation - ACK is false, NACK is true 204 * @param[in] input - Incoming SOL character data. 205 */ 206 void processInboundPayload(uint8_t seqNum, uint8_t ackSeqNum, uint8_t count, 207 bool status, const std::vector<uint8_t>& input); 208 209 /** @brief Send the outbound SOL payload. 210 * 211 * @return zero on success and negative value if condition for sending 212 * the payload fails. 213 */ 214 int sendOutboundPayload(); 215 216 /** @brief Resend the SOL payload. 217 * 218 * @param[in] clear - if true then send the payload and clear the 219 * cached payload, if false only send the payload. 220 */ 221 void resendPayload(bool clear); 222 223 private: 224 /** @brief Expected character count. 225 * 226 * Expected Sequence number and expected character count is set before 227 * sending the SOL payload. The check is done against these values when 228 * an incoming SOL payload is received. 229 */ 230 size_t expectedCharCount = 0; 231 232 /** @brief Inbound and Outbound sequence numbers. */ 233 internal::SequenceNumbers seqNums; 234 235 /** @brief Copy of the last sent SOL payload. 236 * 237 * A copy of the SOL payload is kept here, so that when a retry needs 238 * to be attempted the payload is sent again. 239 */ 240 std::vector<uint8_t> payloadCache; 241 242 /** 243 * @brief Send Response for Incoming SOL payload. 244 * 245 * @param[in] ackSeqNum - Packet ACK/NACK Sequence Number. 246 * @param[in] count - Accepted Character Count. 247 * @param[in] ack - Set ACK/NACK in the Operation. 248 */ 249 void prepareResponse(uint8_t ackSeqNum, uint8_t count, bool ack); 250 251 /** @brief Send the outgoing SOL payload. 252 * 253 * @param[in] out - buffer containing the SOL payload. 254 */ 255 void sendPayload(const std::vector<uint8_t>& out) const; 256 }; 257 258 } // namespace sol 259