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