blob: f0c653d269c4c578f6a33fc7a5fdf828c28417f9 [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
Tom Josephe6361a22016-08-10 06:56:25 -050011#include <memory>
Vernon Maueryfc37e592018-12-19 14:55:15 -080012#include <phosphor-logging/log.hpp>
Tom Josephe6361a22016-08-10 06:56:25 -050013#include <string>
14#include <vector>
15
Vernon Maueryfc37e592018-12-19 14:55:15 -080016using namespace phosphor::logging;
17
Tom Josephe6361a22016-08-10 06:56:25 -050018namespace message
19{
Vernon Mauery8d6f2002018-11-07 09:55:53 -080020using namespace phosphor::logging;
Tom Josephe6361a22016-08-10 06:56:25 -050021
Vernon Mauery8d6f2002018-11-07 09:55:53 -080022bool Handler::receive()
Tom Josephe6361a22016-08-10 06:56:25 -050023{
24 std::vector<uint8_t> packet;
25 auto readStatus = 0;
26
27 // Read the packet
28 std::tie(readStatus, packet) = channel->read();
29
30 // Read of the packet failed
31 if (readStatus < 0)
32 {
Vernon Maueryfc37e592018-12-19 14:55:15 -080033 log<level::ERR>("Error in Read", entry("STATUS=%x", readStatus));
Vernon Mauery8d6f2002018-11-07 09:55:53 -080034 return false;
Tom Josephe6361a22016-08-10 06:56:25 -050035 }
36
37 // Unflatten the packet
Vernon Mauery8d6f2002018-11-07 09:55:53 -080038 std::tie(inMessage, sessionHeader) = parser::unflatten(packet);
Tom Josephe6361a22016-08-10 06:56:25 -050039
Vernon Maueryae1fda42018-10-15 12:55:34 -070040 auto session = std::get<session::Manager&>(singletonPool)
Vernon Mauery8d6f2002018-11-07 09:55:53 -080041 .getSession(inMessage->bmcSessionID);
Tom Josephe6361a22016-08-10 06:56:25 -050042
Vernon Mauery8d6f2002018-11-07 09:55:53 -080043 sessionID = inMessage->bmcSessionID;
44 inMessage->rcSessionID = session->getRCSessionID();
Tom Josephe6361a22016-08-10 06:56:25 -050045 session->updateLastTransactionTime();
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +053046 session->channelPtr = channel;
47 session->remotePort(channel->getPort());
Tom Josephe6361a22016-08-10 06:56:25 -050048
Vernon Mauery8d6f2002018-11-07 09:55:53 -080049 return true;
Tom Josephe6361a22016-08-10 06:56:25 -050050}
51
Vernon Mauery8d6f2002018-11-07 09:55:53 -080052Handler::~Handler()
53{
54 if (outPayload)
55 {
56 std::shared_ptr<Message> outMessage =
57 inMessage->createResponse(*outPayload);
58 if (!outMessage)
59 {
60 return;
61 }
62 try
63 {
64 send(outMessage);
65 }
66 catch (const std::exception& e)
67 {
68 // send failed, most likely due to a session closure
69 log<level::INFO>("Async RMCP+ reply failed",
70 entry("EXCEPTION=%s", e.what()));
71 }
72 }
73}
74
75void Handler::processIncoming()
76{
77 // Read the incoming IPMI packet
78 if (!receive())
79 {
80 return;
81 }
82
83 // Execute the Command, possibly asynchronously
84 executeCommand();
85
86 // send happens during the destructor if a payload was set
87}
88
89void Handler::executeCommand()
Tom Josephe6361a22016-08-10 06:56:25 -050090{
91 // Get the CommandID to map into the command table
Vernon Mauery7f268e42018-10-26 10:26:01 -070092 auto command = inMessage->getCommand();
Vernon Maueryd999ffc2018-10-25 09:16:05 -070093 if (inMessage->payloadType == PayloadType::IPMI)
Tom Josephe6361a22016-08-10 06:56:25 -050094 {
Richard Marian Thomaiyar8af90eb2019-03-03 15:13:33 +053095 auto session =
96 std::get<session::Manager&>(singletonPool).getSession(sessionID);
97 // Process PayloadType::IPMI only if ipmi is enabled or for sessionless
98 // or for session establisbment command
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +053099 if (this->sessionID == session::sessionZero ||
Richard Marian Thomaiyar8af90eb2019-03-03 15:13:33 +0530100 session->sessionUserPrivAccess.ipmiEnabled)
Tom Josephe6361a22016-08-10 06:56:25 -0500101 {
Richard Marian Thomaiyar8af90eb2019-03-03 15:13:33 +0530102 if (inMessage->payload.size() <
103 (sizeof(LAN::header::Request) + sizeof(LAN::trailer::Request)))
104 {
105 return;
106 }
Tom Josephe6361a22016-08-10 06:56:25 -0500107
Richard Marian Thomaiyar8af90eb2019-03-03 15:13:33 +0530108 auto start =
109 inMessage->payload.begin() + sizeof(LAN::header::Request);
110 auto end = inMessage->payload.end() - sizeof(LAN::trailer::Request);
111 std::vector<uint8_t> inPayload(start, end);
112 std::get<command::Table&>(singletonPool)
113 .executeCommand(command, inPayload, shared_from_this());
114 }
115 else
116 {
117 std::vector<uint8_t> payload{IPMI_CC_INSUFFICIENT_PRIVILEGE};
118 outPayload = std::move(payload);
119 }
Tom Josephe6361a22016-08-10 06:56:25 -0500120 }
121 else
122 {
Vernon Mauery8d6f2002018-11-07 09:55:53 -0800123 std::get<command::Table&>(singletonPool)
124 .executeCommand(command, inMessage->payload, shared_from_this());
Tom Josephe6361a22016-08-10 06:56:25 -0500125 }
Tom Josephe6361a22016-08-10 06:56:25 -0500126}
127
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700128void Handler::send(std::shared_ptr<Message> outMessage)
Tom Josephe6361a22016-08-10 06:56:25 -0500129{
Vernon Mauery9e801a22018-10-12 13:20:49 -0700130 auto session =
Vernon Maueryae1fda42018-10-15 12:55:34 -0700131 std::get<session::Manager&>(singletonPool).getSession(sessionID);
Tom Josephe6361a22016-08-10 06:56:25 -0500132
133 // Flatten the packet
Vernon Mauery224f36a2018-10-25 08:52:23 -0700134 auto packet = parser::flatten(outMessage, sessionHeader, session);
Tom Josephe6361a22016-08-10 06:56:25 -0500135
Tom Joseph04b30382017-04-03 01:06:51 +0530136 // Write the packet
Tom Josephe6361a22016-08-10 06:56:25 -0500137 auto writeStatus = channel->write(packet);
138 if (writeStatus < 0)
139 {
Tom Joseph04b30382017-04-03 01:06:51 +0530140 throw std::runtime_error("Error in writing to socket");
Tom Josephe6361a22016-08-10 06:56:25 -0500141 }
Tom Josephe6361a22016-08-10 06:56:25 -0500142}
143
Tom Josephff848492017-03-31 10:43:48 +0530144void Handler::setChannelInSession() const
145{
Vernon Mauery9e801a22018-10-12 13:20:49 -0700146 auto session =
Vernon Maueryae1fda42018-10-15 12:55:34 -0700147 std::get<session::Manager&>(singletonPool).getSession(sessionID);
Tom Josephff848492017-03-31 10:43:48 +0530148
149 session->channelPtr = channel;
150}
151
Vernon Mauery70fd29c2017-11-30 13:11:43 -0800152void Handler::sendSOLPayload(const std::vector<uint8_t>& input)
Tom Joseph22596f22017-03-31 10:52:27 +0530153{
Vernon Mauery9e801a22018-10-12 13:20:49 -0700154 auto session =
Vernon Maueryae1fda42018-10-15 12:55:34 -0700155 std::get<session::Manager&>(singletonPool).getSession(sessionID);
Tom Joseph22596f22017-03-31 10:52:27 +0530156
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700157 auto outMessage = std::make_shared<Message>();
158 outMessage->payloadType = PayloadType::SOL;
159 outMessage->payload = input;
160 outMessage->isPacketEncrypted = session->isCryptAlgoEnabled();
161 outMessage->isPacketAuthenticated = session->isIntegrityAlgoEnabled();
162 outMessage->rcSessionID = session->getRCSessionID();
163 outMessage->bmcSessionID = sessionID;
Tom Joseph22596f22017-03-31 10:52:27 +0530164
165 send(outMessage);
166}
167
Vernon Mauery9e801a22018-10-12 13:20:49 -0700168void Handler::sendUnsolicitedIPMIPayload(uint8_t netfn, uint8_t cmd,
Tom Joseph63d3e492017-03-31 11:01:08 +0530169 const std::vector<uint8_t>& output)
170{
Vernon Mauery9e801a22018-10-12 13:20:49 -0700171 auto session =
Vernon Maueryae1fda42018-10-15 12:55:34 -0700172 std::get<session::Manager&>(singletonPool).getSession(sessionID);
Tom Joseph63d3e492017-03-31 11:01:08 +0530173
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700174 auto outMessage = std::make_shared<Message>();
175 outMessage->payloadType = PayloadType::IPMI;
176 outMessage->isPacketEncrypted = session->isCryptAlgoEnabled();
177 outMessage->isPacketAuthenticated = session->isIntegrityAlgoEnabled();
178 outMessage->rcSessionID = session->getRCSessionID();
179 outMessage->bmcSessionID = sessionID;
Tom Joseph63d3e492017-03-31 11:01:08 +0530180
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700181 outMessage->payload.resize(sizeof(LAN::header::Request) + output.size() +
182 sizeof(LAN::trailer::Request));
Tom Joseph63d3e492017-03-31 11:01:08 +0530183
Vernon Mauery9e801a22018-10-12 13:20:49 -0700184 auto respHeader =
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700185 reinterpret_cast<LAN::header::Request*>(outMessage->payload.data());
Tom Joseph63d3e492017-03-31 11:01:08 +0530186
187 // Add IPMI LAN Message Request Header
188 respHeader->rsaddr = LAN::requesterBMCAddress;
Vernon Mauery9e801a22018-10-12 13:20:49 -0700189 respHeader->netfn = (netfn << 0x02);
190 respHeader->cs = crc8bit(&(respHeader->rsaddr), 2);
Tom Joseph63d3e492017-03-31 11:01:08 +0530191 respHeader->rqaddr = LAN::responderBMCAddress;
Vernon Mauery9e801a22018-10-12 13:20:49 -0700192 respHeader->rqseq = 0;
193 respHeader->cmd = cmd;
Tom Joseph63d3e492017-03-31 11:01:08 +0530194
195 auto assembledSize = sizeof(LAN::header::Request);
196
197 // Copy the output by the execution of the command
Vernon Mauery9e801a22018-10-12 13:20:49 -0700198 std::copy(output.begin(), output.end(),
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700199 outMessage->payload.begin() + assembledSize);
Tom Joseph63d3e492017-03-31 11:01:08 +0530200 assembledSize += output.size();
201
202 // Add the IPMI LAN Message Trailer
Vernon Mauery9e801a22018-10-12 13:20:49 -0700203 auto trailer = reinterpret_cast<LAN::trailer::Request*>(
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700204 outMessage->payload.data() + assembledSize);
Tom Joseph63d3e492017-03-31 11:01:08 +0530205
206 // Calculate the checksum for the field rqaddr in the header to the
207 // command data, 3 corresponds to size of the fields before rqaddr( rsaddr,
208 // netfn, cs).
209 trailer->checksum = crc8bit(&respHeader->rqaddr, assembledSize - 3);
210
211 send(outMessage);
212}
213
Vernon Mauery9e801a22018-10-12 13:20:49 -0700214} // namespace message