blob: 33bb1953a2d0d3164f88219154da2e4ec1fb6b0a [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
Kirill Pakhomovde7dd5c2021-02-27 18:45:22 +030040 return true;
41}
42
43void Handler::updSessionData(std::shared_ptr<Message>& inMessage)
44{
Vernon Mauery2085ae02021-06-10 11:51:00 -070045 auto session = session::Manager::get().getSession(inMessage->bmcSessionID);
Tom Josephe6361a22016-08-10 06:56:25 -050046
Vernon Mauery8d6f2002018-11-07 09:55:53 -080047 sessionID = inMessage->bmcSessionID;
48 inMessage->rcSessionID = session->getRCSessionID();
Tom Josephe6361a22016-08-10 06:56:25 -050049 session->updateLastTransactionTime();
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +053050 session->channelPtr = channel;
51 session->remotePort(channel->getPort());
Rajashekar Gade Reddy9979e992020-02-07 19:18:34 +053052 uint32_t ipAddr = 0;
53 channel->getRemoteAddress(ipAddr);
54 session->remoteIPAddr(ipAddr);
Tom Josephe6361a22016-08-10 06:56:25 -050055}
56
Vernon Mauery8d6f2002018-11-07 09:55:53 -080057Handler::~Handler()
58{
Kirill Pakhomovde7dd5c2021-02-27 18:45:22 +030059 try
Vernon Mauery8d6f2002018-11-07 09:55:53 -080060 {
Kirill Pakhomovde7dd5c2021-02-27 18:45:22 +030061#ifdef RMCP_PING
62 if (ClassOfMsg::ASF == inMessage->rmcpMsgClass)
Vernon Mauery8d6f2002018-11-07 09:55:53 -080063 {
Kirill Pakhomovde7dd5c2021-02-27 18:45:22 +030064 sendASF();
Vernon Mauery8d6f2002018-11-07 09:55:53 -080065 }
Kirill Pakhomovde7dd5c2021-02-27 18:45:22 +030066 else
67#endif // RMCP_PING
Vernon Mauery8d6f2002018-11-07 09:55:53 -080068 {
Kirill Pakhomovde7dd5c2021-02-27 18:45:22 +030069 if (outPayload)
70 {
71 std::shared_ptr<Message> outMessage =
72 inMessage->createResponse(*outPayload);
73 if (!outMessage)
74 {
75 return;
76 }
77 send(outMessage);
78 }
Vernon Mauery8d6f2002018-11-07 09:55:53 -080079 }
Kirill Pakhomovde7dd5c2021-02-27 18:45:22 +030080 }
81 catch (const std::exception& e)
82 {
83 // send failed, most likely due to a session closure
84 log<level::INFO>("Async RMCP+ reply failed",
85 entry("EXCEPTION=%s", e.what()));
Vernon Mauery8d6f2002018-11-07 09:55:53 -080086 }
87}
88
89void Handler::processIncoming()
90{
91 // Read the incoming IPMI packet
92 if (!receive())
93 {
94 return;
95 }
96
Kirill Pakhomovde7dd5c2021-02-27 18:45:22 +030097#ifdef RMCP_PING
Vernon Mauery8d6f2002018-11-07 09:55:53 -080098 // Execute the Command, possibly asynchronously
Kirill Pakhomovde7dd5c2021-02-27 18:45:22 +030099 if (ClassOfMsg::ASF != inMessage->rmcpMsgClass)
100#endif // RMCP_PING
101 {
102 updSessionData(inMessage);
103 executeCommand();
104 }
Vernon Mauery8d6f2002018-11-07 09:55:53 -0800105
106 // send happens during the destructor if a payload was set
107}
108
109void Handler::executeCommand()
Tom Josephe6361a22016-08-10 06:56:25 -0500110{
Kirill Pakhomovde7dd5c2021-02-27 18:45:22 +0300111
Tom Josephe6361a22016-08-10 06:56:25 -0500112 // Get the CommandID to map into the command table
Vernon Mauery7f268e42018-10-26 10:26:01 -0700113 auto command = inMessage->getCommand();
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700114 if (inMessage->payloadType == PayloadType::IPMI)
Tom Josephe6361a22016-08-10 06:56:25 -0500115 {
Vernon Mauery2085ae02021-06-10 11:51:00 -0700116 auto session = session::Manager::get().getSession(sessionID);
Richard Marian Thomaiyar8af90eb2019-03-03 15:13:33 +0530117 // Process PayloadType::IPMI only if ipmi is enabled or for sessionless
118 // or for session establisbment command
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +0530119 if (this->sessionID == session::sessionZero ||
Richard Marian Thomaiyar8af90eb2019-03-03 15:13:33 +0530120 session->sessionUserPrivAccess.ipmiEnabled)
Tom Josephe6361a22016-08-10 06:56:25 -0500121 {
Richard Marian Thomaiyar8af90eb2019-03-03 15:13:33 +0530122 if (inMessage->payload.size() <
123 (sizeof(LAN::header::Request) + sizeof(LAN::trailer::Request)))
124 {
125 return;
126 }
Tom Josephe6361a22016-08-10 06:56:25 -0500127
Richard Marian Thomaiyar8af90eb2019-03-03 15:13:33 +0530128 auto start =
129 inMessage->payload.begin() + sizeof(LAN::header::Request);
130 auto end = inMessage->payload.end() - sizeof(LAN::trailer::Request);
131 std::vector<uint8_t> inPayload(start, end);
Vernon Mauery2085ae02021-06-10 11:51:00 -0700132 command::Table::get().executeCommand(command, inPayload,
133 shared_from_this());
Richard Marian Thomaiyar8af90eb2019-03-03 15:13:33 +0530134 }
135 else
136 {
137 std::vector<uint8_t> payload{IPMI_CC_INSUFFICIENT_PRIVILEGE};
138 outPayload = std::move(payload);
139 }
Tom Josephe6361a22016-08-10 06:56:25 -0500140 }
141 else
142 {
Vernon Mauery2085ae02021-06-10 11:51:00 -0700143 command::Table::get().executeCommand(command, inMessage->payload,
144 shared_from_this());
Tom Josephe6361a22016-08-10 06:56:25 -0500145 }
Tom Josephe6361a22016-08-10 06:56:25 -0500146}
147
Kirill Pakhomovde7dd5c2021-02-27 18:45:22 +0300148void Handler::writeData(const std::vector<uint8_t>& packet)
149{
150 auto writeStatus = channel->write(packet);
151 if (writeStatus < 0)
152 {
153 throw std::runtime_error("Error in writing to socket");
154 }
155}
156
157#ifdef RMCP_PING
158void Handler::sendASF()
159{
160 // Flatten the packet
161 auto packet = asfparser::flatten(inMessage->asfMsgTag);
162
163 // Write the packet
164 writeData(packet);
165}
166#endif // RMCP_PING
167
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700168void Handler::send(std::shared_ptr<Message> outMessage)
Tom Josephe6361a22016-08-10 06:56:25 -0500169{
Vernon Mauery2085ae02021-06-10 11:51:00 -0700170 auto session = session::Manager::get().getSession(sessionID);
Tom Josephe6361a22016-08-10 06:56:25 -0500171
172 // Flatten the packet
Vernon Mauery224f36a2018-10-25 08:52:23 -0700173 auto packet = parser::flatten(outMessage, sessionHeader, session);
Tom Josephe6361a22016-08-10 06:56:25 -0500174
Tom Joseph04b30382017-04-03 01:06:51 +0530175 // Write the packet
Kirill Pakhomovde7dd5c2021-02-27 18:45:22 +0300176 writeData(packet);
Tom Josephe6361a22016-08-10 06:56:25 -0500177}
178
Tom Josephff848492017-03-31 10:43:48 +0530179void Handler::setChannelInSession() const
180{
Vernon Mauery2085ae02021-06-10 11:51:00 -0700181 auto session = session::Manager::get().getSession(sessionID);
Tom Josephff848492017-03-31 10:43:48 +0530182
183 session->channelPtr = channel;
184}
185
Vernon Mauery70fd29c2017-11-30 13:11:43 -0800186void Handler::sendSOLPayload(const std::vector<uint8_t>& input)
Tom Joseph22596f22017-03-31 10:52:27 +0530187{
Vernon Mauery2085ae02021-06-10 11:51:00 -0700188 auto session = session::Manager::get().getSession(sessionID);
Tom Joseph22596f22017-03-31 10:52:27 +0530189
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700190 auto outMessage = std::make_shared<Message>();
191 outMessage->payloadType = PayloadType::SOL;
192 outMessage->payload = input;
193 outMessage->isPacketEncrypted = session->isCryptAlgoEnabled();
194 outMessage->isPacketAuthenticated = session->isIntegrityAlgoEnabled();
195 outMessage->rcSessionID = session->getRCSessionID();
196 outMessage->bmcSessionID = sessionID;
Tom Joseph22596f22017-03-31 10:52:27 +0530197
198 send(outMessage);
199}
200
Vernon Mauery9e801a22018-10-12 13:20:49 -0700201void Handler::sendUnsolicitedIPMIPayload(uint8_t netfn, uint8_t cmd,
Tom Joseph63d3e492017-03-31 11:01:08 +0530202 const std::vector<uint8_t>& output)
203{
Vernon Mauery2085ae02021-06-10 11:51:00 -0700204 auto session = session::Manager::get().getSession(sessionID);
Tom Joseph63d3e492017-03-31 11:01:08 +0530205
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700206 auto outMessage = std::make_shared<Message>();
207 outMessage->payloadType = PayloadType::IPMI;
208 outMessage->isPacketEncrypted = session->isCryptAlgoEnabled();
209 outMessage->isPacketAuthenticated = session->isIntegrityAlgoEnabled();
210 outMessage->rcSessionID = session->getRCSessionID();
211 outMessage->bmcSessionID = sessionID;
Tom Joseph63d3e492017-03-31 11:01:08 +0530212
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700213 outMessage->payload.resize(sizeof(LAN::header::Request) + output.size() +
214 sizeof(LAN::trailer::Request));
Tom Joseph63d3e492017-03-31 11:01:08 +0530215
Vernon Mauery9e801a22018-10-12 13:20:49 -0700216 auto respHeader =
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700217 reinterpret_cast<LAN::header::Request*>(outMessage->payload.data());
Tom Joseph63d3e492017-03-31 11:01:08 +0530218
219 // Add IPMI LAN Message Request Header
220 respHeader->rsaddr = LAN::requesterBMCAddress;
Vernon Mauery9e801a22018-10-12 13:20:49 -0700221 respHeader->netfn = (netfn << 0x02);
222 respHeader->cs = crc8bit(&(respHeader->rsaddr), 2);
Tom Joseph63d3e492017-03-31 11:01:08 +0530223 respHeader->rqaddr = LAN::responderBMCAddress;
Vernon Mauery9e801a22018-10-12 13:20:49 -0700224 respHeader->rqseq = 0;
225 respHeader->cmd = cmd;
Tom Joseph63d3e492017-03-31 11:01:08 +0530226
227 auto assembledSize = sizeof(LAN::header::Request);
228
229 // Copy the output by the execution of the command
Vernon Mauery9e801a22018-10-12 13:20:49 -0700230 std::copy(output.begin(), output.end(),
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700231 outMessage->payload.begin() + assembledSize);
Tom Joseph63d3e492017-03-31 11:01:08 +0530232 assembledSize += output.size();
233
234 // Add the IPMI LAN Message Trailer
Vernon Mauery9e801a22018-10-12 13:20:49 -0700235 auto trailer = reinterpret_cast<LAN::trailer::Request*>(
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700236 outMessage->payload.data() + assembledSize);
Tom Joseph63d3e492017-03-31 11:01:08 +0530237
238 // Calculate the checksum for the field rqaddr in the header to the
239 // command data, 3 corresponds to size of the fields before rqaddr( rsaddr,
240 // netfn, cs).
241 trailer->checksum = crc8bit(&respHeader->rqaddr, assembledSize - 3);
242
243 send(outMessage);
244}
245
Vernon Mauery9e801a22018-10-12 13:20:49 -0700246} // namespace message