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