blob: e66e39c260729782e3011a1377c9a53d380c5ac5 [file] [log] [blame]
Tom Josephe6361a22016-08-10 06:56:25 -05001#include "message_handler.hpp"
2
3#include <sys/socket.h>
4
5#include <iostream>
6#include <memory>
7#include <string>
8#include <vector>
9
10#include "command_table.hpp"
11#include "main.hpp"
12#include "message.hpp"
13#include "message_parsers.hpp"
14#include "sessions_manager.hpp"
15
16namespace message
17{
18
19std::unique_ptr<Message> Handler::receive()
20{
21 std::vector<uint8_t> packet;
22 auto readStatus = 0;
23
24 // Read the packet
25 std::tie(readStatus, packet) = channel->read();
26
27 // Read of the packet failed
28 if (readStatus < 0)
29 {
30 std::cerr << "E> Error in Read : " << std::hex << readStatus << "\n";
31 return nullptr;
32 }
33
34 // Unflatten the packet
35 std::unique_ptr<Message> message;
36 std::tie(message, sessionHeader) = parser::unflatten(packet);
37
Tom Josephe6361a22016-08-10 06:56:25 -050038 auto session = (std::get<session::Manager&>(singletonPool).getSession(
39 message->bmcSessionID)).lock();
40
41 sessionID = message->bmcSessionID;
42 message->rcSessionID = session->getRCSessionID();
43 session->updateLastTransactionTime();
44
45 return message;
46}
47
48template<>
49std::unique_ptr<Message> Handler::createResponse<PayloadType::IPMI>(
50 std::vector<uint8_t>& output, Message& inMessage)
51{
52 auto outMessage = std::make_unique<Message>();
Tom Josephe6361a22016-08-10 06:56:25 -050053 outMessage->payloadType = PayloadType::IPMI;
54
55 outMessage->payload.resize(sizeof(LAN::header::Response) +
56 output.size() +
57 sizeof(LAN::trailer::Response));
58
59 auto reqHeader = reinterpret_cast<LAN::header::Request*>
60 (inMessage.payload.data());
61 auto respHeader = reinterpret_cast<LAN::header::Response*>
62 (outMessage->payload.data());
63
64 // Add IPMI LAN Message Response Header
65 respHeader->rqaddr = reqHeader->rqaddr;
66 respHeader->netfn = reqHeader->netfn | 0x04;
67 respHeader->cs = crc8bit(&(respHeader->rqaddr), 2);
68 respHeader->rsaddr = reqHeader->rsaddr;
69 respHeader->rqseq = reqHeader->rqseq;
70 respHeader->cmd = reqHeader->cmd;
71
72 auto assembledSize = sizeof(LAN::header::Response);
73
74 // Copy the output by the execution of the command
75 std::copy(output.begin(), output.end(),
76 outMessage->payload.begin() + assembledSize);
77 assembledSize += output.size();
78
79 // Add the IPMI LAN Message Trailer
80 auto trailer = reinterpret_cast<LAN::trailer::Response*>
81 (outMessage->payload.data() + assembledSize);
82 trailer->checksum = crc8bit(&respHeader->rsaddr, assembledSize - 3);
83
84 return outMessage;
85}
86
87std::unique_ptr<Message> Handler::executeCommand(Message& inMessage)
88{
89 // Get the CommandID to map into the command table
90 auto command = getCommand(inMessage);
91 std::vector<uint8_t> output{};
92
93 if (inMessage.payloadType == PayloadType::IPMI)
94 {
95 if (inMessage.payload.size() < (sizeof(LAN::header::Request) +
96 sizeof(LAN::trailer::Request)))
97 {
98 return nullptr;
99 }
100
101 auto start = inMessage.payload.begin() + sizeof(LAN::header::Request);
102 auto end = inMessage.payload.end() - sizeof(LAN::trailer::Request);
103 std::vector<uint8_t> inPayload(start, end);
104
105 output = std::get<command::Table&>(singletonPool).executeCommand(
106 command,
107 inPayload,
108 *this);
109 }
110 else
111 {
112 output = std::get<command::Table&>(singletonPool).executeCommand(
113 command,
114 inMessage.payload,
115 *this);
116 }
117
118 std::unique_ptr<Message> outMessage = nullptr;
119
120 switch (inMessage.payloadType)
121 {
122 case PayloadType::IPMI:
123 outMessage = createResponse<PayloadType::IPMI>(output, inMessage);
124 break;
125 case PayloadType::OPEN_SESSION_REQUEST:
126 outMessage = createResponse<PayloadType::OPEN_SESSION_RESPONSE>(
127 output, inMessage);
128 break;
129 case PayloadType::RAKP1:
130 outMessage = createResponse<PayloadType::RAKP2>(output, inMessage);
131 break;
132 case PayloadType::RAKP3:
133 outMessage = createResponse<PayloadType::RAKP4>(output, inMessage);
134 break;
Tom Joseph703adbf2017-03-31 10:50:22 +0530135 case PayloadType::SOL:
136 return outMessage;
137 break;
Tom Josephe6361a22016-08-10 06:56:25 -0500138 default:
139 break;
Tom Josephe6361a22016-08-10 06:56:25 -0500140 }
141
Tom Joseph8dfa0f02017-01-10 15:38:20 +0530142 outMessage->isPacketEncrypted = inMessage.isPacketEncrypted;
143 outMessage->isPacketAuthenticated = inMessage.isPacketAuthenticated;
144 outMessage->rcSessionID = inMessage.rcSessionID;
145 outMessage->bmcSessionID = inMessage.bmcSessionID;
146
Tom Josephe6361a22016-08-10 06:56:25 -0500147 return outMessage;
148}
149
150uint32_t Handler::getCommand(Message& message)
151{
152 uint32_t command = 0 ;
153
154 command |= (static_cast<uint8_t>(message.payloadType) << 16);
155 if (message.payloadType == PayloadType::IPMI)
156 {
157 command |= ((reinterpret_cast<LAN::header::Request*>
158 (message.payload.data()))->netfn) << 8;
159 command |= (reinterpret_cast<LAN::header::Request*>
160 (message.payload.data()))->cmd;
161 }
162
163 return command;
164}
165
Tom Joseph04b30382017-04-03 01:06:51 +0530166void Handler::send(Message& outMessage)
Tom Josephe6361a22016-08-10 06:56:25 -0500167{
168 auto session = (std::get<session::Manager&>(singletonPool).getSession(
169 sessionID)).lock();
170
171 // Flatten the packet
172 auto packet = parser::flatten(outMessage, sessionHeader, *session);
173
Tom Joseph04b30382017-04-03 01:06:51 +0530174 // Write the packet
Tom Josephe6361a22016-08-10 06:56:25 -0500175 auto writeStatus = channel->write(packet);
176 if (writeStatus < 0)
177 {
Tom Joseph04b30382017-04-03 01:06:51 +0530178 throw std::runtime_error("Error in writing to socket");
Tom Josephe6361a22016-08-10 06:56:25 -0500179 }
Tom Josephe6361a22016-08-10 06:56:25 -0500180}
181
Tom Josephff848492017-03-31 10:43:48 +0530182void Handler::setChannelInSession() const
183{
184 auto session = (std::get<session::Manager&>(singletonPool).getSession(
185 sessionID)).lock();
186
187 session->channelPtr = channel;
188}
189
Tom Joseph22596f22017-03-31 10:52:27 +0530190void Handler::sendSOLPayload(const sol::Buffer& input)
191{
192 Message outMessage;
193
194 auto session = (std::get<session::Manager&>(singletonPool).getSession(
195 sessionID)).lock();
196
197 outMessage.payloadType = PayloadType::SOL;
198 outMessage.payload = input;
199 outMessage.isPacketEncrypted = session->isCryptAlgoEnabled();
200 outMessage.isPacketAuthenticated = session->isIntegrityAlgoEnabled();
201 outMessage.rcSessionID = session->getRCSessionID();
202 outMessage.bmcSessionID = sessionID;
203
204 send(outMessage);
205}
206
Tom Joseph63d3e492017-03-31 11:01:08 +0530207void Handler::sendUnsolicitedIPMIPayload(uint8_t netfn,
208 uint8_t cmd,
209 const std::vector<uint8_t>& output)
210{
211 Message outMessage;
212
213 auto session = (std::get<session::Manager&>(singletonPool).getSession(
214 sessionID)).lock();
215
216 outMessage.payloadType = PayloadType::IPMI;
217 outMessage.isPacketEncrypted = session->isCryptAlgoEnabled();
218 outMessage.isPacketAuthenticated = session->isIntegrityAlgoEnabled();
219 outMessage.rcSessionID = session->getRCSessionID();
220 outMessage.bmcSessionID = sessionID;
221
222 outMessage.payload.resize(sizeof(LAN::header::Request) +
223 output.size() +
224 sizeof(LAN::trailer::Request));
225
226 auto respHeader = reinterpret_cast<LAN::header::Request*>
227 (outMessage.payload.data());
228
229 // Add IPMI LAN Message Request Header
230 respHeader->rsaddr = LAN::requesterBMCAddress;
231 respHeader->netfn = (netfn << 0x02);
232 respHeader->cs = crc8bit(&(respHeader->rsaddr), 2);
233 respHeader->rqaddr = LAN::responderBMCAddress;
234 respHeader->rqseq = 0;
235 respHeader->cmd = cmd;
236
237 auto assembledSize = sizeof(LAN::header::Request);
238
239 // Copy the output by the execution of the command
240 std::copy(output.begin(),
241 output.end(),
242 outMessage.payload.begin() + assembledSize);
243 assembledSize += output.size();
244
245 // Add the IPMI LAN Message Trailer
246 auto trailer = reinterpret_cast<LAN::trailer::Request*>
247 (outMessage.payload.data() + assembledSize);
248
249 // Calculate the checksum for the field rqaddr in the header to the
250 // command data, 3 corresponds to size of the fields before rqaddr( rsaddr,
251 // netfn, cs).
252 trailer->checksum = crc8bit(&respHeader->rqaddr, assembledSize - 3);
253
254 send(outMessage);
255}
256
Tom Josephe6361a22016-08-10 06:56:25 -0500257} //namespace message
258