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