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 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 Constructor. 163 * 164 * This is issued by the SOL Manager when a SOL payload instance is 165 * started for the activate payload command. 166 * 167 * @param[in] io - boost::asio io context for event scheduling. 168 * @param[in] maxRetryCount - Retry count max value. 169 * @param[in] sendThreshold - Character send threshold. 170 * @param[in] instance - SOL payload instance. 171 * @param[in] sessionID - BMC session ID. 172 */ 173 Context(std::shared_ptr<boost::asio::io_context> io, uint8_t maxRetryCount, 174 uint8_t sendThreshold, uint8_t instance, 175 session::SessionID sessionID); 176 177 static constexpr auto clear = true; 178 static constexpr auto noClear = false; 179 180 /** @brief accumulate timer */ 181 boost::asio::steady_timer accumulateTimer; 182 183 /** @brief retry timer */ 184 boost::asio::steady_timer retryTimer; 185 186 /** @brief Retry count max value. */ 187 const uint8_t maxRetryCount = 0; 188 189 /** @brief Retry counter. */ 190 uint8_t retryCounter = 0; 191 192 /** @brief Character send threshold. */ 193 const uint8_t sendThreshold = 0; 194 195 /** @brief SOL payload instance. */ 196 const uint8_t payloadInstance = 0; 197 198 /** @brief Session ID. */ 199 const session::SessionID sessionID = 0; 200 201 /** @brief session pointer 202 */ 203 std::shared_ptr<session::Session> session; 204 205 /** @brief enable/disable accumulate timer 206 * 207 * The timeout interval is managed by the SOL Manager; 208 * this function only enables or disable the timer 209 * 210 * @param[in] enable - enable(true) or disable(false) accumulation timer 211 */ 212 void enableAccumulateTimer(bool enable); 213 214 /** @brief enable/disable retry timer 215 * 216 * The timeout interval is managed by the SOL Manager; 217 * this function only enables or disable the timer 218 * 219 * @param[in] enable - enable(true) or disable(false) retry timer 220 */ 221 void enableRetryTimer(bool enable); 222 223 /** @brief Process the Inbound SOL payload. 224 * 225 * The SOL payload from the remote console is processed and the 226 * acknowledgment handling is done. 227 * 228 * @param[in] seqNum - Packet sequence number. 229 * @param[in] ackSeqNum - Packet ACK/NACK sequence number. 230 * @param[in] count - Accepted character count. 231 * @param[in] operation - ACK is false, NACK is true 232 * @param[in] input - Incoming SOL character data. 233 */ 234 void processInboundPayload(uint8_t seqNum, uint8_t ackSeqNum, uint8_t count, 235 bool status, const std::vector<uint8_t>& input); 236 237 /** @brief Send the outbound SOL payload. 238 * 239 * @return zero on success and negative value if condition for sending 240 * the payload fails. 241 */ 242 int sendOutboundPayload(); 243 244 /** @brief Resend the SOL payload. 245 * 246 * @param[in] clear - if true then send the payload and clear the 247 * cached payload, if false only send the payload. 248 */ 249 void resendPayload(bool clear); 250 251 private: 252 /** @brief Expected character count. 253 * 254 * Expected Sequence number and expected character count is set before 255 * sending the SOL payload. The check is done against these values when 256 * an incoming SOL payload is received. 257 */ 258 size_t expectedCharCount = 0; 259 260 /** @brief Inbound and Outbound sequence numbers. */ 261 internal::SequenceNumbers seqNums; 262 263 /** @brief Copy of the last sent SOL payload. 264 * 265 * A copy of the SOL payload is kept here, so that when a retry needs 266 * to be attempted the payload is sent again. 267 */ 268 std::vector<uint8_t> payloadCache; 269 270 /** 271 * @brief Send Response for Incoming SOL payload. 272 * 273 * @param[in] ackSeqNum - Packet ACK/NACK Sequence Number. 274 * @param[in] count - Accepted Character Count. 275 * @param[in] ack - Set ACK/NACK in the Operation. 276 */ 277 void prepareResponse(uint8_t ackSeqNum, uint8_t count, bool ack); 278 279 /** @brief Send the outgoing SOL payload. 280 * 281 * @param[in] out - buffer containing the SOL payload. 282 */ 283 void sendPayload(const std::vector<uint8_t>& out) const; 284 285 /** @brief accumlate timer handler called by timer */ 286 void charAccTimerHandler(); 287 288 /** @brief retry timer handler called by timer */ 289 void retryTimerHandler(); 290 }; 291 292 } // namespace sol 293