blob: ee0eb39e9de7d1fc0dff47a5efc3cffb4e4b414b [file] [log] [blame]
Tom Josephfbcac2e2017-03-14 18:15:07 +05301#include <phosphor-logging/log.hpp>
2#include "main.hpp"
3#include "sd_event_loop.hpp"
4#include "sol_context.hpp"
5#include "sol_manager.hpp"
6
7namespace sol
8{
9
10using namespace phosphor::logging;
11
12void Context::processInboundPayload(uint8_t seqNum,
13 uint8_t ackSeqNum,
14 uint8_t count,
15 bool status,
16 const Buffer& input)
17{
18 uint8_t respAckSeqNum = 0;
19 uint8_t acceptedCount = 0;
20 auto ack = false;
21
22 /*
23 * Check if the Inbound sequence number is same as the expected one.
24 * If the Packet Sequence Number is 0, it is an ACK-Only packet. Multiple
25 * outstanding sequence numbers are not supported in this version of the SOL
26 * specification. Retried packets use the same sequence number as the first
27 * packet.
28 */
29 if(seqNum && (seqNum != seqNums.get(true)))
30 {
31 log<level::INFO>("Out of sequence SOL packet - packet is dropped");
32 return;
33 }
34
35 /*
36 * Check if the expected ACK/NACK sequence number is same as the
37 * ACK/NACK sequence number in the packet. If packet ACK/NACK sequence
38 * number is 0, then it is an informational packet. No request packet being
39 * ACK'd or NACK'd.
40 */
41 if (ackSeqNum && (ackSeqNum != seqNums.get(false)))
42 {
43 log<level::INFO>("Out of sequence ack number - SOL packet is dropped");
44 return;
45 }
46
47 /*
48 * Retry the SOL payload packet in the following conditions:
49 *
50 * a) NACK in Operation/Status
51 * b) Accepted Character Count does not match with the sent out SOL payload
52 * c) Non-zero Packet ACK/NACK Sequence Number
53 */
54 if (status || ((count != expectedCharCount) && ackSeqNum))
55 {
56 resendPayload(noClear);
57 std::get<eventloop::EventLoop&>(singletonPool).switchTimer
58 (payloadInstance, eventloop::Timers::RETRY, false);
59 std::get<eventloop::EventLoop&>(singletonPool).switchTimer
60 (payloadInstance, eventloop::Timers::RETRY, true);
61 return;
62 }
63 /*
64 * Clear the sent data once the acknowledgment sequence number matches
65 * and the expected character count matches.
66 */
67 else if ((count == expectedCharCount) && ackSeqNum)
68 {
69 // Clear the Host Console Buffer
70 std::get<sol::Manager&>(singletonPool).dataBuffer.erase(count);
71
72 // Once it is acknowledged stop the retry interval timer
73 std::get<eventloop::EventLoop&>(singletonPool).switchTimer(
74 payloadInstance, eventloop::Timers::RETRY, false);
75
76 retryCounter = maxRetryCount;
77 expectedCharCount = 0;
78 payloadCache.clear();
79 }
80
81 // Write character data to the Host Console
82 if (!input.empty() && seqNum)
83 {
84 auto rc = std::get<sol::Manager&>(singletonPool).writeConsoleSocket(
85 input);
86 if (rc)
87 {
88 log<level::ERR>("Writing to console socket descriptor failed");
89 ack = true;
90 }
91 else
92 {
93 respAckSeqNum = seqNum;
94 ack = false;
95 acceptedCount = input.size();
96 }
97 }
98
99 if (seqNum != 0)
100 {
101 seqNums.incInboundSeqNum();
102 prepareResponse(respAckSeqNum, acceptedCount, ack);
103 }
104 else
105 {
106 std::get<eventloop::EventLoop&>(singletonPool).switchTimer
107 (payloadInstance, eventloop::Timers::ACCUMULATE, true);
108 }
109}
110
Tom Joseph75e15db2017-03-14 18:16:22 +0530111void Context::prepareResponse(uint8_t ackSeqNum, uint8_t count, bool ack)
112{
113 auto bufferSize = std::get<sol::Manager&>(singletonPool).dataBuffer.
114 size();
115
116 /* Sent a ACK only response */
117 if (payloadCache.size() != 0 || (bufferSize < sendThreshold))
118 {
119 std::get<eventloop::EventLoop&>(singletonPool).switchTimer
120 (payloadInstance, eventloop::Timers::ACCUMULATE, true);
121
122 Buffer outPayload(sizeof(Payload));
123 auto response = reinterpret_cast<Payload*>(outPayload.data());
124 response->packetSeqNum = 0;
125 response->packetAckSeqNum = ackSeqNum;
126 response->acceptedCharCount = count;
127 response->outOperation.ack = ack;
128 sendPayload(outPayload);
129 return;
130 }
131
132 auto readSize = std::min(bufferSize, MAX_PAYLOAD_SIZE);
133 payloadCache.resize(sizeof(Payload) + readSize);
134 auto response = reinterpret_cast<Payload*>(payloadCache.data());
135 response->packetAckSeqNum = ackSeqNum;
136 response->acceptedCharCount = count;
137 response->outOperation.ack = ack;
138 response->packetSeqNum = seqNums.incOutboundSeqNum();
139
140
141 auto handle = std::get<sol::Manager&>(singletonPool).dataBuffer.read();
142 std::copy_n(handle, readSize, payloadCache.data() + sizeof(Payload));
143 expectedCharCount = readSize;
144
145 std::get<eventloop::EventLoop&>(singletonPool).switchTimer(
146 payloadInstance, eventloop::Timers::RETRY, true);
147 std::get<eventloop::EventLoop&>(singletonPool).switchTimer
148 (payloadInstance, eventloop::Timers::ACCUMULATE, false);
149
150 sendPayload(payloadCache);
151}
152
153void Context::resendPayload(bool clear)
Tom Josephfbcac2e2017-03-14 18:15:07 +0530154{
155
156}
157
Tom Joseph75e15db2017-03-14 18:16:22 +0530158void Context::sendPayload(const Buffer& out) const
Tom Josephfbcac2e2017-03-14 18:15:07 +0530159{
160
161}
162
163} // namespace sol