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, 170 uint8_t sendThreshold, 171 uint8_t instance, 172 session::SessionID sessionID): 173 maxRetryCount(maxRetryCount), 174 retryCounter(maxRetryCount), 175 sendThreshold(sendThreshold), 176 payloadInstance(instance), 177 sessionID(sessionID) {} 178 179 static constexpr auto clear = true; 180 static constexpr auto noClear = false; 181 182 /** @brief Retry count max value. */ 183 const uint8_t maxRetryCount = 0; 184 185 /** @brief Retry counter. */ 186 uint8_t retryCounter = 0; 187 188 /** @brief Character send threshold. */ 189 const uint8_t sendThreshold = 0; 190 191 /** @brief SOL payload instance. */ 192 const uint8_t payloadInstance = 0; 193 194 /** @brief Session ID. */ 195 const session::SessionID sessionID = 0; 196 197 /** @brief Process the Inbound SOL payload. 198 * 199 * The SOL payload from the remote console is processed and the 200 * acknowledgment handling is done. 201 * 202 * @param[in] seqNum - Packet sequence number. 203 * @param[in] ackSeqNum - Packet ACK/NACK sequence number. 204 * @param[in] count - Accepted character count. 205 * @param[in] operation - ACK is false, NACK is true 206 * @param[in] input - Incoming SOL character data. 207 */ 208 void processInboundPayload(uint8_t seqNum, 209 uint8_t ackSeqNum, 210 uint8_t count, 211 bool status, 212 const std::vector<uint8_t>& input); 213 214 /** @brief Send the outbound SOL payload. 215 * 216 * @return zero on success and negative value if condition for sending 217 * the payload fails. 218 */ 219 int sendOutboundPayload(); 220 221 /** @brief Resend the SOL payload. 222 * 223 * @param[in] clear - if true then send the payload and clear the 224 * cached payload, if false only send the payload. 225 */ 226 void resendPayload(bool clear); 227 228 private: 229 /** @brief Expected character count. 230 * 231 * Expected Sequence number and expected character count is set before 232 * sending the SOL payload. The check is done against these values when 233 * an incoming SOL payload is received. 234 */ 235 size_t expectedCharCount = 0; 236 237 /** @brief Inbound and Outbound sequence numbers. */ 238 internal::SequenceNumbers seqNums; 239 240 /** @brief Copy of the last sent SOL payload. 241 * 242 * A copy of the SOL payload is kept here, so that when a retry needs 243 * to be attempted the payload is sent again. 244 */ 245 std::vector<uint8_t> payloadCache; 246 247 /** 248 * @brief Send Response for Incoming SOL payload. 249 * 250 * @param[in] ackSeqNum - Packet ACK/NACK Sequence Number. 251 * @param[in] count - Accepted Character Count. 252 * @param[in] ack - Set ACK/NACK in the Operation. 253 */ 254 void prepareResponse(uint8_t ackSeqNum, uint8_t count, bool ack); 255 256 /** @brief Send the outgoing SOL payload. 257 * 258 * @param[in] out - buffer containing the SOL payload. 259 */ 260 void sendPayload(const std::vector<uint8_t>& out) const; 261 }; 262 263 } // namespace sol 264