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