blob: 68c1b60b75cbae7bea3a2f8ff77f6ae7aaea7106 [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
Vernon Maueryd999ffc2018-10-25 09:16:05 -070019std::shared_ptr<Message> Handler::receive()
Tom Josephe6361a22016-08-10 06:56:25 -050020{
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
Vernon Maueryd999ffc2018-10-25 09:16:05 -070035 std::shared_ptr<Message> message;
Tom Josephe6361a22016-08-10 06:56:25 -050036 std::tie(message, sessionHeader) = parser::unflatten(packet);
37
Vernon Maueryae1fda42018-10-15 12:55:34 -070038 auto session = std::get<session::Manager&>(singletonPool)
39 .getSession(message->bmcSessionID);
Tom Josephe6361a22016-08-10 06:56:25 -050040
41 sessionID = message->bmcSessionID;
42 message->rcSessionID = session->getRCSessionID();
43 session->updateLastTransactionTime();
44
45 return message;
46}
47
Vernon Mauery9e801a22018-10-12 13:20:49 -070048template <>
Vernon Maueryd999ffc2018-10-25 09:16:05 -070049std::shared_ptr<Message> Handler::createResponse<PayloadType::IPMI>(
50 std::vector<uint8_t>& output, std::shared_ptr<Message> inMessage)
Tom Josephe6361a22016-08-10 06:56:25 -050051{
Vernon Maueryd999ffc2018-10-25 09:16:05 -070052 auto outMessage = std::make_shared<Message>();
Tom Josephe6361a22016-08-10 06:56:25 -050053 outMessage->payloadType = PayloadType::IPMI;
54
Vernon Mauery9e801a22018-10-12 13:20:49 -070055 outMessage->payload.resize(sizeof(LAN::header::Response) + output.size() +
Tom Josephe6361a22016-08-10 06:56:25 -050056 sizeof(LAN::trailer::Response));
57
Vernon Mauery9e801a22018-10-12 13:20:49 -070058 auto reqHeader =
Vernon Maueryd999ffc2018-10-25 09:16:05 -070059 reinterpret_cast<LAN::header::Request*>(inMessage->payload.data());
Vernon Mauery9e801a22018-10-12 13:20:49 -070060 auto respHeader =
61 reinterpret_cast<LAN::header::Response*>(outMessage->payload.data());
Tom Josephe6361a22016-08-10 06:56:25 -050062
63 // Add IPMI LAN Message Response Header
64 respHeader->rqaddr = reqHeader->rqaddr;
Vernon Mauery9e801a22018-10-12 13:20:49 -070065 respHeader->netfn = reqHeader->netfn | 0x04;
66 respHeader->cs = crc8bit(&(respHeader->rqaddr), 2);
Tom Josephe6361a22016-08-10 06:56:25 -050067 respHeader->rsaddr = reqHeader->rsaddr;
Vernon Mauery9e801a22018-10-12 13:20:49 -070068 respHeader->rqseq = reqHeader->rqseq;
69 respHeader->cmd = reqHeader->cmd;
Tom Josephe6361a22016-08-10 06:56:25 -050070
71 auto assembledSize = sizeof(LAN::header::Response);
72
73 // Copy the output by the execution of the command
74 std::copy(output.begin(), output.end(),
75 outMessage->payload.begin() + assembledSize);
76 assembledSize += output.size();
77
78 // Add the IPMI LAN Message Trailer
Vernon Mauery9e801a22018-10-12 13:20:49 -070079 auto trailer = reinterpret_cast<LAN::trailer::Response*>(
80 outMessage->payload.data() + assembledSize);
Tom Josephe6361a22016-08-10 06:56:25 -050081 trailer->checksum = crc8bit(&respHeader->rsaddr, assembledSize - 3);
82
83 return outMessage;
84}
85
Vernon Maueryd999ffc2018-10-25 09:16:05 -070086std::shared_ptr<Message>
87 Handler::executeCommand(std::shared_ptr<Message> inMessage)
Tom Josephe6361a22016-08-10 06:56:25 -050088{
89 // Get the CommandID to map into the command table
90 auto command = getCommand(inMessage);
91 std::vector<uint8_t> output{};
92
Vernon Maueryd999ffc2018-10-25 09:16:05 -070093 if (inMessage->payloadType == PayloadType::IPMI)
Tom Josephe6361a22016-08-10 06:56:25 -050094 {
Vernon Maueryd999ffc2018-10-25 09:16:05 -070095 if (inMessage->payload.size() <
Vernon Mauery9e801a22018-10-12 13:20:49 -070096 (sizeof(LAN::header::Request) + sizeof(LAN::trailer::Request)))
Tom Josephe6361a22016-08-10 06:56:25 -050097 {
98 return nullptr;
99 }
100
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700101 auto start = inMessage->payload.begin() + sizeof(LAN::header::Request);
102 auto end = inMessage->payload.end() - sizeof(LAN::trailer::Request);
Tom Josephe6361a22016-08-10 06:56:25 -0500103 std::vector<uint8_t> inPayload(start, end);
104
Vernon Mauery9e801a22018-10-12 13:20:49 -0700105 output = std::get<command::Table&>(singletonPool)
106 .executeCommand(command, inPayload, *this);
Tom Josephe6361a22016-08-10 06:56:25 -0500107 }
108 else
109 {
Vernon Mauery9e801a22018-10-12 13:20:49 -0700110 output = std::get<command::Table&>(singletonPool)
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700111 .executeCommand(command, inMessage->payload, *this);
Tom Josephe6361a22016-08-10 06:56:25 -0500112 }
113
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700114 std::shared_ptr<Message> outMessage = nullptr;
Tom Josephe6361a22016-08-10 06:56:25 -0500115
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700116 switch (inMessage->payloadType)
Tom Josephe6361a22016-08-10 06:56:25 -0500117 {
118 case PayloadType::IPMI:
119 outMessage = createResponse<PayloadType::IPMI>(output, inMessage);
120 break;
121 case PayloadType::OPEN_SESSION_REQUEST:
122 outMessage = createResponse<PayloadType::OPEN_SESSION_RESPONSE>(
Vernon Mauery9e801a22018-10-12 13:20:49 -0700123 output, inMessage);
Tom Josephe6361a22016-08-10 06:56:25 -0500124 break;
125 case PayloadType::RAKP1:
126 outMessage = createResponse<PayloadType::RAKP2>(output, inMessage);
127 break;
128 case PayloadType::RAKP3:
129 outMessage = createResponse<PayloadType::RAKP4>(output, inMessage);
130 break;
Tom Joseph703adbf2017-03-31 10:50:22 +0530131 case PayloadType::SOL:
132 return outMessage;
133 break;
Tom Josephe6361a22016-08-10 06:56:25 -0500134 default:
135 break;
Tom Josephe6361a22016-08-10 06:56:25 -0500136 }
137
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700138 outMessage->isPacketEncrypted = inMessage->isPacketEncrypted;
139 outMessage->isPacketAuthenticated = inMessage->isPacketAuthenticated;
140 outMessage->rcSessionID = inMessage->rcSessionID;
141 outMessage->bmcSessionID = inMessage->bmcSessionID;
Tom Joseph8dfa0f02017-01-10 15:38:20 +0530142
Tom Josephe6361a22016-08-10 06:56:25 -0500143 return outMessage;
144}
145
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700146uint32_t Handler::getCommand(std::shared_ptr<Message> message)
Tom Josephe6361a22016-08-10 06:56:25 -0500147{
Vernon Mauery9e801a22018-10-12 13:20:49 -0700148 uint32_t command = 0;
Tom Josephe6361a22016-08-10 06:56:25 -0500149
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700150 command |= (static_cast<uint8_t>(message->payloadType) << 16);
151 if (message->payloadType == PayloadType::IPMI)
Tom Josephe6361a22016-08-10 06:56:25 -0500152 {
Vernon Mauery9e801a22018-10-12 13:20:49 -0700153 command |=
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700154 ((reinterpret_cast<LAN::header::Request*>(message->payload.data()))
Vernon Mauery9e801a22018-10-12 13:20:49 -0700155 ->netfn)
156 << 8;
157 command |=
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700158 (reinterpret_cast<LAN::header::Request*>(message->payload.data()))
Vernon Mauery9e801a22018-10-12 13:20:49 -0700159 ->cmd;
Tom Josephe6361a22016-08-10 06:56:25 -0500160 }
161
162 return command;
163}
164
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700165void Handler::send(std::shared_ptr<Message> outMessage)
Tom Josephe6361a22016-08-10 06:56:25 -0500166{
Vernon Mauery9e801a22018-10-12 13:20:49 -0700167 auto session =
Vernon Maueryae1fda42018-10-15 12:55:34 -0700168 std::get<session::Manager&>(singletonPool).getSession(sessionID);
Tom Josephe6361a22016-08-10 06:56:25 -0500169
170 // Flatten the packet
Vernon Mauery224f36a2018-10-25 08:52:23 -0700171 auto packet = parser::flatten(outMessage, sessionHeader, session);
Tom Josephe6361a22016-08-10 06:56:25 -0500172
Tom Joseph04b30382017-04-03 01:06:51 +0530173 // Write the packet
Tom Josephe6361a22016-08-10 06:56:25 -0500174 auto writeStatus = channel->write(packet);
175 if (writeStatus < 0)
176 {
Tom Joseph04b30382017-04-03 01:06:51 +0530177 throw std::runtime_error("Error in writing to socket");
Tom Josephe6361a22016-08-10 06:56:25 -0500178 }
Tom Josephe6361a22016-08-10 06:56:25 -0500179}
180
Tom Josephff848492017-03-31 10:43:48 +0530181void Handler::setChannelInSession() const
182{
Vernon Mauery9e801a22018-10-12 13:20:49 -0700183 auto session =
Vernon Maueryae1fda42018-10-15 12:55:34 -0700184 std::get<session::Manager&>(singletonPool).getSession(sessionID);
Tom Josephff848492017-03-31 10:43:48 +0530185
186 session->channelPtr = channel;
187}
188
Vernon Mauery70fd29c2017-11-30 13:11:43 -0800189void Handler::sendSOLPayload(const std::vector<uint8_t>& input)
Tom Joseph22596f22017-03-31 10:52:27 +0530190{
Vernon Mauery9e801a22018-10-12 13:20:49 -0700191 auto session =
Vernon Maueryae1fda42018-10-15 12:55:34 -0700192 std::get<session::Manager&>(singletonPool).getSession(sessionID);
Tom Joseph22596f22017-03-31 10:52:27 +0530193
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700194 auto outMessage = std::make_shared<Message>();
195 outMessage->payloadType = PayloadType::SOL;
196 outMessage->payload = input;
197 outMessage->isPacketEncrypted = session->isCryptAlgoEnabled();
198 outMessage->isPacketAuthenticated = session->isIntegrityAlgoEnabled();
199 outMessage->rcSessionID = session->getRCSessionID();
200 outMessage->bmcSessionID = sessionID;
Tom Joseph22596f22017-03-31 10:52:27 +0530201
202 send(outMessage);
203}
204
Vernon Mauery9e801a22018-10-12 13:20:49 -0700205void Handler::sendUnsolicitedIPMIPayload(uint8_t netfn, uint8_t cmd,
Tom Joseph63d3e492017-03-31 11:01:08 +0530206 const std::vector<uint8_t>& output)
207{
Vernon Mauery9e801a22018-10-12 13:20:49 -0700208 auto session =
Vernon Maueryae1fda42018-10-15 12:55:34 -0700209 std::get<session::Manager&>(singletonPool).getSession(sessionID);
Tom Joseph63d3e492017-03-31 11:01:08 +0530210
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700211 auto outMessage = std::make_shared<Message>();
212 outMessage->payloadType = PayloadType::IPMI;
213 outMessage->isPacketEncrypted = session->isCryptAlgoEnabled();
214 outMessage->isPacketAuthenticated = session->isIntegrityAlgoEnabled();
215 outMessage->rcSessionID = session->getRCSessionID();
216 outMessage->bmcSessionID = sessionID;
Tom Joseph63d3e492017-03-31 11:01:08 +0530217
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700218 outMessage->payload.resize(sizeof(LAN::header::Request) + output.size() +
219 sizeof(LAN::trailer::Request));
Tom Joseph63d3e492017-03-31 11:01:08 +0530220
Vernon Mauery9e801a22018-10-12 13:20:49 -0700221 auto respHeader =
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700222 reinterpret_cast<LAN::header::Request*>(outMessage->payload.data());
Tom Joseph63d3e492017-03-31 11:01:08 +0530223
224 // Add IPMI LAN Message Request Header
225 respHeader->rsaddr = LAN::requesterBMCAddress;
Vernon Mauery9e801a22018-10-12 13:20:49 -0700226 respHeader->netfn = (netfn << 0x02);
227 respHeader->cs = crc8bit(&(respHeader->rsaddr), 2);
Tom Joseph63d3e492017-03-31 11:01:08 +0530228 respHeader->rqaddr = LAN::responderBMCAddress;
Vernon Mauery9e801a22018-10-12 13:20:49 -0700229 respHeader->rqseq = 0;
230 respHeader->cmd = cmd;
Tom Joseph63d3e492017-03-31 11:01:08 +0530231
232 auto assembledSize = sizeof(LAN::header::Request);
233
234 // Copy the output by the execution of the command
Vernon Mauery9e801a22018-10-12 13:20:49 -0700235 std::copy(output.begin(), output.end(),
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700236 outMessage->payload.begin() + assembledSize);
Tom Joseph63d3e492017-03-31 11:01:08 +0530237 assembledSize += output.size();
238
239 // Add the IPMI LAN Message Trailer
Vernon Mauery9e801a22018-10-12 13:20:49 -0700240 auto trailer = reinterpret_cast<LAN::trailer::Request*>(
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700241 outMessage->payload.data() + assembledSize);
Tom Joseph63d3e492017-03-31 11:01:08 +0530242
243 // Calculate the checksum for the field rqaddr in the header to the
244 // command data, 3 corresponds to size of the fields before rqaddr( rsaddr,
245 // netfn, cs).
246 trailer->checksum = crc8bit(&respHeader->rqaddr, assembledSize - 3);
247
248 send(outMessage);
249}
250
Vernon Mauery9e801a22018-10-12 13:20:49 -0700251} // namespace message