blob: f845228d16d12495654262be0aff0b150fe0a0c3 [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
Vernon Maueryfc37e592018-12-19 14:55:15 -080011#include <phosphor-logging/log.hpp>
George Liubc8958f2022-07-04 09:29:49 +080012
13#include <memory>
Tom Josephe6361a22016-08-10 06:56:25 -050014#include <string>
15#include <vector>
16
Vernon Maueryfc37e592018-12-19 14:55:15 -080017using namespace phosphor::logging;
18
Tom Josephe6361a22016-08-10 06:56:25 -050019namespace message
20{
Vernon Mauery8d6f2002018-11-07 09:55:53 -080021using namespace phosphor::logging;
Tom Josephe6361a22016-08-10 06:56:25 -050022
Vernon Mauery8d6f2002018-11-07 09:55:53 -080023bool Handler::receive()
Tom Josephe6361a22016-08-10 06:56:25 -050024{
25 std::vector<uint8_t> packet;
26 auto readStatus = 0;
27
28 // Read the packet
29 std::tie(readStatus, packet) = channel->read();
30
31 // Read of the packet failed
32 if (readStatus < 0)
33 {
Vernon Maueryfc37e592018-12-19 14:55:15 -080034 log<level::ERR>("Error in Read", entry("STATUS=%x", readStatus));
Vernon Mauery8d6f2002018-11-07 09:55:53 -080035 return false;
Tom Josephe6361a22016-08-10 06:56:25 -050036 }
37
38 // Unflatten the packet
Vernon Mauery8d6f2002018-11-07 09:55:53 -080039 std::tie(inMessage, sessionHeader) = parser::unflatten(packet);
Tom Josephe6361a22016-08-10 06:56:25 -050040
Kirill Pakhomovde7dd5c2021-02-27 18:45:22 +030041 return true;
42}
43
44void Handler::updSessionData(std::shared_ptr<Message>& inMessage)
45{
Lei YU0a4dde42022-07-12 19:42:15 +080046 session = session::Manager::get().getSession(inMessage->bmcSessionID);
Tom Josephe6361a22016-08-10 06:56:25 -050047
Vernon Mauery8d6f2002018-11-07 09:55:53 -080048 sessionID = inMessage->bmcSessionID;
49 inMessage->rcSessionID = session->getRCSessionID();
Tom Josephe6361a22016-08-10 06:56:25 -050050 session->updateLastTransactionTime();
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +053051 session->channelPtr = channel;
52 session->remotePort(channel->getPort());
Rajashekar Gade Reddy9979e992020-02-07 19:18:34 +053053 uint32_t ipAddr = 0;
54 channel->getRemoteAddress(ipAddr);
55 session->remoteIPAddr(ipAddr);
Tom Josephe6361a22016-08-10 06:56:25 -050056}
57
Vernon Mauery8d6f2002018-11-07 09:55:53 -080058Handler::~Handler()
59{
Kirill Pakhomovde7dd5c2021-02-27 18:45:22 +030060 try
Vernon Mauery8d6f2002018-11-07 09:55:53 -080061 {
Kirill Pakhomovde7dd5c2021-02-27 18:45:22 +030062#ifdef RMCP_PING
63 if (ClassOfMsg::ASF == inMessage->rmcpMsgClass)
Vernon Mauery8d6f2002018-11-07 09:55:53 -080064 {
Kirill Pakhomovde7dd5c2021-02-27 18:45:22 +030065 sendASF();
Vernon Mauery8d6f2002018-11-07 09:55:53 -080066 }
Kirill Pakhomovde7dd5c2021-02-27 18:45:22 +030067 else
68#endif // RMCP_PING
Vernon Mauery8d6f2002018-11-07 09:55:53 -080069 {
Kirill Pakhomovde7dd5c2021-02-27 18:45:22 +030070 if (outPayload)
71 {
72 std::shared_ptr<Message> outMessage =
73 inMessage->createResponse(*outPayload);
74 if (!outMessage)
75 {
76 return;
77 }
78 send(outMessage);
79 }
Vernon Mauery8d6f2002018-11-07 09:55:53 -080080 }
Kirill Pakhomovde7dd5c2021-02-27 18:45:22 +030081 }
82 catch (const std::exception& e)
83 {
84 // send failed, most likely due to a session closure
85 log<level::INFO>("Async RMCP+ reply failed",
86 entry("EXCEPTION=%s", e.what()));
Vernon Mauery8d6f2002018-11-07 09:55:53 -080087 }
88}
89
90void Handler::processIncoming()
91{
92 // Read the incoming IPMI packet
93 if (!receive())
94 {
95 return;
96 }
97
Kirill Pakhomovde7dd5c2021-02-27 18:45:22 +030098#ifdef RMCP_PING
Vernon Mauery8d6f2002018-11-07 09:55:53 -080099 // Execute the Command, possibly asynchronously
Kirill Pakhomovde7dd5c2021-02-27 18:45:22 +0300100 if (ClassOfMsg::ASF != inMessage->rmcpMsgClass)
101#endif // RMCP_PING
102 {
103 updSessionData(inMessage);
104 executeCommand();
105 }
Vernon Mauery8d6f2002018-11-07 09:55:53 -0800106
107 // send happens during the destructor if a payload was set
108}
109
110void Handler::executeCommand()
Tom Josephe6361a22016-08-10 06:56:25 -0500111{
112 // 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 {
Richard Marian Thomaiyar8af90eb2019-03-03 15:13:33 +0530116 // Process PayloadType::IPMI only if ipmi is enabled or for sessionless
117 // or for session establisbment command
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +0530118 if (this->sessionID == session::sessionZero ||
Richard Marian Thomaiyar8af90eb2019-03-03 15:13:33 +0530119 session->sessionUserPrivAccess.ipmiEnabled)
Tom Josephe6361a22016-08-10 06:56:25 -0500120 {
Richard Marian Thomaiyar8af90eb2019-03-03 15:13:33 +0530121 if (inMessage->payload.size() <
122 (sizeof(LAN::header::Request) + sizeof(LAN::trailer::Request)))
123 {
124 return;
125 }
Tom Josephe6361a22016-08-10 06:56:25 -0500126
Richard Marian Thomaiyar8af90eb2019-03-03 15:13:33 +0530127 auto start =
128 inMessage->payload.begin() + sizeof(LAN::header::Request);
129 auto end = inMessage->payload.end() - sizeof(LAN::trailer::Request);
130 std::vector<uint8_t> inPayload(start, end);
Vernon Mauery2085ae02021-06-10 11:51:00 -0700131 command::Table::get().executeCommand(command, inPayload,
132 shared_from_this());
Richard Marian Thomaiyar8af90eb2019-03-03 15:13:33 +0530133 }
134 else
135 {
136 std::vector<uint8_t> payload{IPMI_CC_INSUFFICIENT_PRIVILEGE};
137 outPayload = std::move(payload);
138 }
Tom Josephe6361a22016-08-10 06:56:25 -0500139 }
140 else
141 {
Vernon Mauery2085ae02021-06-10 11:51:00 -0700142 command::Table::get().executeCommand(command, inMessage->payload,
143 shared_from_this());
Tom Josephe6361a22016-08-10 06:56:25 -0500144 }
Tom Josephe6361a22016-08-10 06:56:25 -0500145}
146
Kirill Pakhomovde7dd5c2021-02-27 18:45:22 +0300147void Handler::writeData(const std::vector<uint8_t>& packet)
148{
149 auto writeStatus = channel->write(packet);
150 if (writeStatus < 0)
151 {
152 throw std::runtime_error("Error in writing to socket");
153 }
154}
155
156#ifdef RMCP_PING
157void Handler::sendASF()
158{
159 // Flatten the packet
160 auto packet = asfparser::flatten(inMessage->asfMsgTag);
161
162 // Write the packet
163 writeData(packet);
164}
165#endif // RMCP_PING
166
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700167void Handler::send(std::shared_ptr<Message> outMessage)
Tom Josephe6361a22016-08-10 06:56:25 -0500168{
Tom Josephe6361a22016-08-10 06:56:25 -0500169 // Flatten the packet
Vernon Mauery224f36a2018-10-25 08:52:23 -0700170 auto packet = parser::flatten(outMessage, sessionHeader, session);
Tom Josephe6361a22016-08-10 06:56:25 -0500171
Tom Joseph04b30382017-04-03 01:06:51 +0530172 // Write the packet
Kirill Pakhomovde7dd5c2021-02-27 18:45:22 +0300173 writeData(packet);
Tom Josephe6361a22016-08-10 06:56:25 -0500174}
175
Tom Josephff848492017-03-31 10:43:48 +0530176void Handler::setChannelInSession() const
177{
Tom Josephff848492017-03-31 10:43:48 +0530178 session->channelPtr = channel;
179}
180
Vernon Mauery70fd29c2017-11-30 13:11:43 -0800181void Handler::sendSOLPayload(const std::vector<uint8_t>& input)
Tom Joseph22596f22017-03-31 10:52:27 +0530182{
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700183 auto outMessage = std::make_shared<Message>();
184 outMessage->payloadType = PayloadType::SOL;
185 outMessage->payload = input;
186 outMessage->isPacketEncrypted = session->isCryptAlgoEnabled();
187 outMessage->isPacketAuthenticated = session->isIntegrityAlgoEnabled();
188 outMessage->rcSessionID = session->getRCSessionID();
189 outMessage->bmcSessionID = sessionID;
Tom Joseph22596f22017-03-31 10:52:27 +0530190
191 send(outMessage);
192}
193
Vernon Mauery9e801a22018-10-12 13:20:49 -0700194void Handler::sendUnsolicitedIPMIPayload(uint8_t netfn, uint8_t cmd,
Tom Joseph63d3e492017-03-31 11:01:08 +0530195 const std::vector<uint8_t>& output)
196{
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700197 auto outMessage = std::make_shared<Message>();
198 outMessage->payloadType = PayloadType::IPMI;
199 outMessage->isPacketEncrypted = session->isCryptAlgoEnabled();
200 outMessage->isPacketAuthenticated = session->isIntegrityAlgoEnabled();
201 outMessage->rcSessionID = session->getRCSessionID();
202 outMessage->bmcSessionID = sessionID;
Tom Joseph63d3e492017-03-31 11:01:08 +0530203
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700204 outMessage->payload.resize(sizeof(LAN::header::Request) + output.size() +
205 sizeof(LAN::trailer::Request));
Tom Joseph63d3e492017-03-31 11:01:08 +0530206
Vernon Mauery9e801a22018-10-12 13:20:49 -0700207 auto respHeader =
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700208 reinterpret_cast<LAN::header::Request*>(outMessage->payload.data());
Tom Joseph63d3e492017-03-31 11:01:08 +0530209
210 // Add IPMI LAN Message Request Header
211 respHeader->rsaddr = LAN::requesterBMCAddress;
Vernon Mauery9e801a22018-10-12 13:20:49 -0700212 respHeader->netfn = (netfn << 0x02);
213 respHeader->cs = crc8bit(&(respHeader->rsaddr), 2);
Tom Joseph63d3e492017-03-31 11:01:08 +0530214 respHeader->rqaddr = LAN::responderBMCAddress;
Vernon Mauery9e801a22018-10-12 13:20:49 -0700215 respHeader->rqseq = 0;
216 respHeader->cmd = cmd;
Tom Joseph63d3e492017-03-31 11:01:08 +0530217
218 auto assembledSize = sizeof(LAN::header::Request);
219
220 // Copy the output by the execution of the command
Vernon Mauery9e801a22018-10-12 13:20:49 -0700221 std::copy(output.begin(), output.end(),
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700222 outMessage->payload.begin() + assembledSize);
Tom Joseph63d3e492017-03-31 11:01:08 +0530223 assembledSize += output.size();
224
225 // Add the IPMI LAN Message Trailer
Vernon Mauery9e801a22018-10-12 13:20:49 -0700226 auto trailer = reinterpret_cast<LAN::trailer::Request*>(
Vernon Maueryd999ffc2018-10-25 09:16:05 -0700227 outMessage->payload.data() + assembledSize);
Tom Joseph63d3e492017-03-31 11:01:08 +0530228
229 // Calculate the checksum for the field rqaddr in the header to the
230 // command data, 3 corresponds to size of the fields before rqaddr( rsaddr,
231 // netfn, cs).
232 trailer->checksum = crc8bit(&respHeader->rqaddr, assembledSize - 3);
233
234 send(outMessage);
235}
236
Vernon Mauery9e801a22018-10-12 13:20:49 -0700237} // namespace message