blob: 62855a9344b7c5f47f1624b180565ff53a682abc [file] [log] [blame]
Tom Josephe6361a22016-08-10 06:56:25 -05001#include "message_handler.hpp"
2
Vernon Mauery9e801a22018-10-12 13:20:49 -07003#include "command_table.hpp"
4#include "main.hpp"
5#include "message.hpp"
6#include "message_parsers.hpp"
7#include "sessions_manager.hpp"
8
Tom Josephe6361a22016-08-10 06:56:25 -05009#include <sys/socket.h>
10
11#include <iostream>
12#include <memory>
13#include <string>
14#include <vector>
15
Tom Josephe6361a22016-08-10 06:56:25 -050016namespace 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
Vernon Mauery9e801a22018-10-12 13:20:49 -070038 auto session = (std::get<session::Manager&>(singletonPool)
39 .getSession(message->bmcSessionID))
40 .lock();
Tom Josephe6361a22016-08-10 06:56:25 -050041
42 sessionID = message->bmcSessionID;
43 message->rcSessionID = session->getRCSessionID();
44 session->updateLastTransactionTime();
45
46 return message;
47}
48
Vernon Mauery9e801a22018-10-12 13:20:49 -070049template <>
50std::unique_ptr<Message>
51 Handler::createResponse<PayloadType::IPMI>(std::vector<uint8_t>& output,
52 Message& inMessage)
Tom Josephe6361a22016-08-10 06:56:25 -050053{
54 auto outMessage = std::make_unique<Message>();
Tom Josephe6361a22016-08-10 06:56:25 -050055 outMessage->payloadType = PayloadType::IPMI;
56
Vernon Mauery9e801a22018-10-12 13:20:49 -070057 outMessage->payload.resize(sizeof(LAN::header::Response) + output.size() +
Tom Josephe6361a22016-08-10 06:56:25 -050058 sizeof(LAN::trailer::Response));
59
Vernon Mauery9e801a22018-10-12 13:20:49 -070060 auto reqHeader =
61 reinterpret_cast<LAN::header::Request*>(inMessage.payload.data());
62 auto respHeader =
63 reinterpret_cast<LAN::header::Response*>(outMessage->payload.data());
Tom Josephe6361a22016-08-10 06:56:25 -050064
65 // Add IPMI LAN Message Response Header
66 respHeader->rqaddr = reqHeader->rqaddr;
Vernon Mauery9e801a22018-10-12 13:20:49 -070067 respHeader->netfn = reqHeader->netfn | 0x04;
68 respHeader->cs = crc8bit(&(respHeader->rqaddr), 2);
Tom Josephe6361a22016-08-10 06:56:25 -050069 respHeader->rsaddr = reqHeader->rsaddr;
Vernon Mauery9e801a22018-10-12 13:20:49 -070070 respHeader->rqseq = reqHeader->rqseq;
71 respHeader->cmd = reqHeader->cmd;
Tom Josephe6361a22016-08-10 06:56:25 -050072
73 auto assembledSize = sizeof(LAN::header::Response);
74
75 // Copy the output by the execution of the command
76 std::copy(output.begin(), output.end(),
77 outMessage->payload.begin() + assembledSize);
78 assembledSize += output.size();
79
80 // Add the IPMI LAN Message Trailer
Vernon Mauery9e801a22018-10-12 13:20:49 -070081 auto trailer = reinterpret_cast<LAN::trailer::Response*>(
82 outMessage->payload.data() + assembledSize);
Tom Josephe6361a22016-08-10 06:56:25 -050083 trailer->checksum = crc8bit(&respHeader->rsaddr, assembledSize - 3);
84
85 return outMessage;
86}
87
88std::unique_ptr<Message> Handler::executeCommand(Message& inMessage)
89{
90 // Get the CommandID to map into the command table
91 auto command = getCommand(inMessage);
92 std::vector<uint8_t> output{};
93
94 if (inMessage.payloadType == PayloadType::IPMI)
95 {
Vernon Mauery9e801a22018-10-12 13:20:49 -070096 if (inMessage.payload.size() <
97 (sizeof(LAN::header::Request) + sizeof(LAN::trailer::Request)))
Tom Josephe6361a22016-08-10 06:56:25 -050098 {
99 return nullptr;
100 }
101
102 auto start = inMessage.payload.begin() + sizeof(LAN::header::Request);
103 auto end = inMessage.payload.end() - sizeof(LAN::trailer::Request);
104 std::vector<uint8_t> inPayload(start, end);
105
Vernon Mauery9e801a22018-10-12 13:20:49 -0700106 output = std::get<command::Table&>(singletonPool)
107 .executeCommand(command, inPayload, *this);
Tom Josephe6361a22016-08-10 06:56:25 -0500108 }
109 else
110 {
Vernon Mauery9e801a22018-10-12 13:20:49 -0700111 output = std::get<command::Table&>(singletonPool)
112 .executeCommand(command, inMessage.payload, *this);
Tom Josephe6361a22016-08-10 06:56:25 -0500113 }
114
115 std::unique_ptr<Message> outMessage = nullptr;
116
117 switch (inMessage.payloadType)
118 {
119 case PayloadType::IPMI:
120 outMessage = createResponse<PayloadType::IPMI>(output, inMessage);
121 break;
122 case PayloadType::OPEN_SESSION_REQUEST:
123 outMessage = createResponse<PayloadType::OPEN_SESSION_RESPONSE>(
Vernon Mauery9e801a22018-10-12 13:20:49 -0700124 output, inMessage);
Tom Josephe6361a22016-08-10 06:56:25 -0500125 break;
126 case PayloadType::RAKP1:
127 outMessage = createResponse<PayloadType::RAKP2>(output, inMessage);
128 break;
129 case PayloadType::RAKP3:
130 outMessage = createResponse<PayloadType::RAKP4>(output, inMessage);
131 break;
Tom Joseph703adbf2017-03-31 10:50:22 +0530132 case PayloadType::SOL:
133 return outMessage;
134 break;
Tom Josephe6361a22016-08-10 06:56:25 -0500135 default:
136 break;
Tom Josephe6361a22016-08-10 06:56:25 -0500137 }
138
Tom Joseph8dfa0f02017-01-10 15:38:20 +0530139 outMessage->isPacketEncrypted = inMessage.isPacketEncrypted;
140 outMessage->isPacketAuthenticated = inMessage.isPacketAuthenticated;
141 outMessage->rcSessionID = inMessage.rcSessionID;
142 outMessage->bmcSessionID = inMessage.bmcSessionID;
143
Tom Josephe6361a22016-08-10 06:56:25 -0500144 return outMessage;
145}
146
147uint32_t Handler::getCommand(Message& message)
148{
Vernon Mauery9e801a22018-10-12 13:20:49 -0700149 uint32_t command = 0;
Tom Josephe6361a22016-08-10 06:56:25 -0500150
151 command |= (static_cast<uint8_t>(message.payloadType) << 16);
152 if (message.payloadType == PayloadType::IPMI)
153 {
Vernon Mauery9e801a22018-10-12 13:20:49 -0700154 command |=
155 ((reinterpret_cast<LAN::header::Request*>(message.payload.data()))
156 ->netfn)
157 << 8;
158 command |=
159 (reinterpret_cast<LAN::header::Request*>(message.payload.data()))
160 ->cmd;
Tom Josephe6361a22016-08-10 06:56:25 -0500161 }
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{
Vernon Mauery9e801a22018-10-12 13:20:49 -0700168 auto session =
169 (std::get<session::Manager&>(singletonPool).getSession(sessionID))
170 .lock();
Tom Josephe6361a22016-08-10 06:56:25 -0500171
172 // Flatten the packet
173 auto packet = parser::flatten(outMessage, sessionHeader, *session);
174
Tom Joseph04b30382017-04-03 01:06:51 +0530175 // Write the packet
Tom Josephe6361a22016-08-10 06:56:25 -0500176 auto writeStatus = channel->write(packet);
177 if (writeStatus < 0)
178 {
Tom Joseph04b30382017-04-03 01:06:51 +0530179 throw std::runtime_error("Error in writing to socket");
Tom Josephe6361a22016-08-10 06:56:25 -0500180 }
Tom Josephe6361a22016-08-10 06:56:25 -0500181}
182
Tom Josephff848492017-03-31 10:43:48 +0530183void Handler::setChannelInSession() const
184{
Vernon Mauery9e801a22018-10-12 13:20:49 -0700185 auto session =
186 (std::get<session::Manager&>(singletonPool).getSession(sessionID))
187 .lock();
Tom Josephff848492017-03-31 10:43:48 +0530188
189 session->channelPtr = channel;
190}
191
Vernon Mauery70fd29c2017-11-30 13:11:43 -0800192void Handler::sendSOLPayload(const std::vector<uint8_t>& input)
Tom Joseph22596f22017-03-31 10:52:27 +0530193{
194 Message outMessage;
195
Vernon Mauery9e801a22018-10-12 13:20:49 -0700196 auto session =
197 (std::get<session::Manager&>(singletonPool).getSession(sessionID))
198 .lock();
Tom Joseph22596f22017-03-31 10:52:27 +0530199
200 outMessage.payloadType = PayloadType::SOL;
201 outMessage.payload = input;
202 outMessage.isPacketEncrypted = session->isCryptAlgoEnabled();
203 outMessage.isPacketAuthenticated = session->isIntegrityAlgoEnabled();
204 outMessage.rcSessionID = session->getRCSessionID();
205 outMessage.bmcSessionID = sessionID;
206
207 send(outMessage);
208}
209
Vernon Mauery9e801a22018-10-12 13:20:49 -0700210void Handler::sendUnsolicitedIPMIPayload(uint8_t netfn, uint8_t cmd,
Tom Joseph63d3e492017-03-31 11:01:08 +0530211 const std::vector<uint8_t>& output)
212{
213 Message outMessage;
214
Vernon Mauery9e801a22018-10-12 13:20:49 -0700215 auto session =
216 (std::get<session::Manager&>(singletonPool).getSession(sessionID))
217 .lock();
Tom Joseph63d3e492017-03-31 11:01:08 +0530218
219 outMessage.payloadType = PayloadType::IPMI;
220 outMessage.isPacketEncrypted = session->isCryptAlgoEnabled();
221 outMessage.isPacketAuthenticated = session->isIntegrityAlgoEnabled();
222 outMessage.rcSessionID = session->getRCSessionID();
223 outMessage.bmcSessionID = sessionID;
224
Vernon Mauery9e801a22018-10-12 13:20:49 -0700225 outMessage.payload.resize(sizeof(LAN::header::Request) + output.size() +
Tom Joseph63d3e492017-03-31 11:01:08 +0530226 sizeof(LAN::trailer::Request));
227
Vernon Mauery9e801a22018-10-12 13:20:49 -0700228 auto respHeader =
229 reinterpret_cast<LAN::header::Request*>(outMessage.payload.data());
Tom Joseph63d3e492017-03-31 11:01:08 +0530230
231 // Add IPMI LAN Message Request Header
232 respHeader->rsaddr = LAN::requesterBMCAddress;
Vernon Mauery9e801a22018-10-12 13:20:49 -0700233 respHeader->netfn = (netfn << 0x02);
234 respHeader->cs = crc8bit(&(respHeader->rsaddr), 2);
Tom Joseph63d3e492017-03-31 11:01:08 +0530235 respHeader->rqaddr = LAN::responderBMCAddress;
Vernon Mauery9e801a22018-10-12 13:20:49 -0700236 respHeader->rqseq = 0;
237 respHeader->cmd = cmd;
Tom Joseph63d3e492017-03-31 11:01:08 +0530238
239 auto assembledSize = sizeof(LAN::header::Request);
240
241 // Copy the output by the execution of the command
Vernon Mauery9e801a22018-10-12 13:20:49 -0700242 std::copy(output.begin(), output.end(),
Tom Joseph63d3e492017-03-31 11:01:08 +0530243 outMessage.payload.begin() + assembledSize);
244 assembledSize += output.size();
245
246 // Add the IPMI LAN Message Trailer
Vernon Mauery9e801a22018-10-12 13:20:49 -0700247 auto trailer = reinterpret_cast<LAN::trailer::Request*>(
248 outMessage.payload.data() + assembledSize);
Tom Joseph63d3e492017-03-31 11:01:08 +0530249
250 // Calculate the checksum for the field rqaddr in the header to the
251 // command data, 3 corresponds to size of the fields before rqaddr( rsaddr,
252 // netfn, cs).
253 trailer->checksum = crc8bit(&respHeader->rqaddr, assembledSize - 3);
254
255 send(outMessage);
256}
257
Vernon Mauery9e801a22018-10-12 13:20:49 -0700258} // namespace message