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