1e6361a21STom Joseph #include "message_handler.hpp"
2e6361a21STom Joseph
39e801a2bSVernon Mauery #include "command_table.hpp"
49e801a2bSVernon Mauery #include "main.hpp"
59e801a2bSVernon Mauery #include "message.hpp"
69e801a2bSVernon Mauery #include "message_parsers.hpp"
79e801a2bSVernon Mauery #include "sessions_manager.hpp"
89e801a2bSVernon Mauery
9e6361a21STom Joseph #include <sys/socket.h>
10e6361a21STom Joseph
117b7f25f7SGeorge Liu #include <phosphor-logging/lg2.hpp>
12bc8958feSGeorge Liu
13bc8958feSGeorge Liu #include <memory>
14e6361a21STom Joseph #include <string>
15e6361a21STom Joseph #include <vector>
16e6361a21STom Joseph
17e6361a21STom Joseph namespace message
18e6361a21STom Joseph {
19e6361a21STom Joseph
receive()208d6f200cSVernon Mauery bool Handler::receive()
21e6361a21STom Joseph {
22e6361a21STom Joseph std::vector<uint8_t> packet;
23e6361a21STom Joseph auto readStatus = 0;
24e6361a21STom Joseph
25e6361a21STom Joseph // Read the packet
26e6361a21STom Joseph std::tie(readStatus, packet) = channel->read();
27e6361a21STom Joseph
28e6361a21STom Joseph // Read of the packet failed
29e6361a21STom Joseph if (readStatus < 0)
30e6361a21STom Joseph {
317b7f25f7SGeorge Liu lg2::error("Error in Read status: {STATUS}", "STATUS", readStatus);
328d6f200cSVernon Mauery return false;
33e6361a21STom Joseph }
34e6361a21STom Joseph
35e6361a21STom Joseph // Unflatten the packet
368d6f200cSVernon Mauery std::tie(inMessage, sessionHeader) = parser::unflatten(packet);
37e6361a21STom Joseph
38de7dd5ceSKirill Pakhomov return true;
39de7dd5ceSKirill Pakhomov }
40de7dd5ceSKirill Pakhomov
updSessionData(std::shared_ptr<Message> & inMessage)41de7dd5ceSKirill Pakhomov void Handler::updSessionData(std::shared_ptr<Message>& inMessage)
42de7dd5ceSKirill Pakhomov {
430a4dde44SLei YU session = session::Manager::get().getSession(inMessage->bmcSessionID);
44e6361a21STom Joseph
458d6f200cSVernon Mauery sessionID = inMessage->bmcSessionID;
468d6f200cSVernon Mauery inMessage->rcSessionID = session->getRCSessionID();
47e6361a21STom Joseph session->updateLastTransactionTime();
48f8a34fc4SSuryakanth Sekar session->channelPtr = channel;
49f8a34fc4SSuryakanth Sekar session->remotePort(channel->getPort());
509979e997SRajashekar Gade Reddy uint32_t ipAddr = 0;
519979e997SRajashekar Gade Reddy channel->getRemoteAddress(ipAddr);
529979e997SRajashekar Gade Reddy session->remoteIPAddr(ipAddr);
53e6361a21STom Joseph }
54e6361a21STom Joseph
~Handler()558d6f200cSVernon Mauery Handler::~Handler()
568d6f200cSVernon Mauery {
57de7dd5ceSKirill Pakhomov try
58de7dd5ceSKirill Pakhomov {
59de7dd5ceSKirill Pakhomov #ifdef RMCP_PING
60*7c75c374SJayaprakash Mutyala if (inMessage && (ClassOfMsg::ASF == inMessage->rmcpMsgClass))
61de7dd5ceSKirill Pakhomov {
62de7dd5ceSKirill Pakhomov sendASF();
63de7dd5ceSKirill Pakhomov }
64de7dd5ceSKirill Pakhomov else
65de7dd5ceSKirill Pakhomov #endif // RMCP_PING
66de7dd5ceSKirill Pakhomov {
678d6f200cSVernon Mauery if (outPayload)
688d6f200cSVernon Mauery {
698d6f200cSVernon Mauery std::shared_ptr<Message> outMessage =
708d6f200cSVernon Mauery inMessage->createResponse(*outPayload);
718d6f200cSVernon Mauery if (!outMessage)
728d6f200cSVernon Mauery {
738d6f200cSVernon Mauery return;
748d6f200cSVernon Mauery }
758d6f200cSVernon Mauery send(outMessage);
768d6f200cSVernon Mauery }
77de7dd5ceSKirill Pakhomov }
78de7dd5ceSKirill Pakhomov }
798d6f200cSVernon Mauery catch (const std::exception& e)
808d6f200cSVernon Mauery {
818d6f200cSVernon Mauery // send failed, most likely due to a session closure
827b7f25f7SGeorge Liu lg2::info("Async RMCP+ reply failed: {ERROR}", "ERROR", e);
838d6f200cSVernon Mauery }
848d6f200cSVernon Mauery }
858d6f200cSVernon Mauery
processIncoming()868d6f200cSVernon Mauery void Handler::processIncoming()
878d6f200cSVernon Mauery {
888d6f200cSVernon Mauery // Read the incoming IPMI packet
898d6f200cSVernon Mauery if (!receive())
908d6f200cSVernon Mauery {
918d6f200cSVernon Mauery return;
928d6f200cSVernon Mauery }
938d6f200cSVernon Mauery
94de7dd5ceSKirill Pakhomov #ifdef RMCP_PING
958d6f200cSVernon Mauery // Execute the Command, possibly asynchronously
96*7c75c374SJayaprakash Mutyala if (inMessage && (ClassOfMsg::ASF != inMessage->rmcpMsgClass))
97de7dd5ceSKirill Pakhomov #endif // RMCP_PING
98de7dd5ceSKirill Pakhomov {
99de7dd5ceSKirill Pakhomov updSessionData(inMessage);
1008d6f200cSVernon Mauery executeCommand();
101de7dd5ceSKirill Pakhomov }
1028d6f200cSVernon Mauery
1038d6f200cSVernon Mauery // send happens during the destructor if a payload was set
1048d6f200cSVernon Mauery }
1058d6f200cSVernon Mauery
executeCommand()1068d6f200cSVernon Mauery void Handler::executeCommand()
107e6361a21STom Joseph {
108e6361a21STom Joseph // Get the CommandID to map into the command table
1097f268e4dSVernon Mauery auto command = inMessage->getCommand();
110d999ffc1SVernon Mauery if (inMessage->payloadType == PayloadType::IPMI)
111e6361a21STom Joseph {
1128af90ebcSRichard Marian Thomaiyar // Process PayloadType::IPMI only if ipmi is enabled or for sessionless
1138af90ebcSRichard Marian Thomaiyar // or for session establisbment command
114f8a34fc4SSuryakanth Sekar if (this->sessionID == session::sessionZero ||
1158af90ebcSRichard Marian Thomaiyar session->sessionUserPrivAccess.ipmiEnabled)
1168af90ebcSRichard Marian Thomaiyar {
117d999ffc1SVernon Mauery if (inMessage->payload.size() <
1189e801a2bSVernon Mauery (sizeof(LAN::header::Request) + sizeof(LAN::trailer::Request)))
119e6361a21STom Joseph {
1208d6f200cSVernon Mauery return;
121e6361a21STom Joseph }
122e6361a21STom Joseph
123099fb097SPatrick Williams auto start = inMessage->payload.begin() +
124099fb097SPatrick Williams sizeof(LAN::header::Request);
125d999ffc1SVernon Mauery auto end = inMessage->payload.end() - sizeof(LAN::trailer::Request);
126e6361a21STom Joseph std::vector<uint8_t> inPayload(start, end);
1272085ae07SVernon Mauery command::Table::get().executeCommand(command, inPayload,
1282085ae07SVernon Mauery shared_from_this());
129e6361a21STom Joseph }
130e6361a21STom Joseph else
131e6361a21STom Joseph {
1328af90ebcSRichard Marian Thomaiyar std::vector<uint8_t> payload{IPMI_CC_INSUFFICIENT_PRIVILEGE};
1338af90ebcSRichard Marian Thomaiyar outPayload = std::move(payload);
1348af90ebcSRichard Marian Thomaiyar }
1358af90ebcSRichard Marian Thomaiyar }
1368af90ebcSRichard Marian Thomaiyar else
1378af90ebcSRichard Marian Thomaiyar {
1382085ae07SVernon Mauery command::Table::get().executeCommand(command, inMessage->payload,
1392085ae07SVernon Mauery shared_from_this());
140e6361a21STom Joseph }
141e6361a21STom Joseph }
142e6361a21STom Joseph
writeData(const std::vector<uint8_t> & packet)143de7dd5ceSKirill Pakhomov void Handler::writeData(const std::vector<uint8_t>& packet)
144de7dd5ceSKirill Pakhomov {
145de7dd5ceSKirill Pakhomov auto writeStatus = channel->write(packet);
146de7dd5ceSKirill Pakhomov if (writeStatus < 0)
147de7dd5ceSKirill Pakhomov {
148de7dd5ceSKirill Pakhomov throw std::runtime_error("Error in writing to socket");
149de7dd5ceSKirill Pakhomov }
150de7dd5ceSKirill Pakhomov }
151de7dd5ceSKirill Pakhomov
152de7dd5ceSKirill Pakhomov #ifdef RMCP_PING
sendASF()153de7dd5ceSKirill Pakhomov void Handler::sendASF()
154de7dd5ceSKirill Pakhomov {
155de7dd5ceSKirill Pakhomov // Flatten the packet
156de7dd5ceSKirill Pakhomov auto packet = asfparser::flatten(inMessage->asfMsgTag);
157de7dd5ceSKirill Pakhomov
158de7dd5ceSKirill Pakhomov // Write the packet
159de7dd5ceSKirill Pakhomov writeData(packet);
160de7dd5ceSKirill Pakhomov }
161de7dd5ceSKirill Pakhomov #endif // RMCP_PING
162de7dd5ceSKirill Pakhomov
send(std::shared_ptr<Message> outMessage)163d999ffc1SVernon Mauery void Handler::send(std::shared_ptr<Message> outMessage)
164e6361a21STom Joseph {
165e6361a21STom Joseph // Flatten the packet
166224f36a4SVernon Mauery auto packet = parser::flatten(outMessage, sessionHeader, session);
167e6361a21STom Joseph
16804b30381STom Joseph // Write the packet
169de7dd5ceSKirill Pakhomov writeData(packet);
170e6361a21STom Joseph }
171e6361a21STom Joseph
setChannelInSession() const172ff848494STom Joseph void Handler::setChannelInSession() const
173ff848494STom Joseph {
174ff848494STom Joseph session->channelPtr = channel;
175ff848494STom Joseph }
176ff848494STom Joseph
sendSOLPayload(const std::vector<uint8_t> & input)17770fd29cfSVernon Mauery void Handler::sendSOLPayload(const std::vector<uint8_t>& input)
17822596f21STom Joseph {
179d999ffc1SVernon Mauery auto outMessage = std::make_shared<Message>();
180d999ffc1SVernon Mauery outMessage->payloadType = PayloadType::SOL;
181d999ffc1SVernon Mauery outMessage->payload = input;
182d999ffc1SVernon Mauery outMessage->isPacketEncrypted = session->isCryptAlgoEnabled();
183d999ffc1SVernon Mauery outMessage->isPacketAuthenticated = session->isIntegrityAlgoEnabled();
184d999ffc1SVernon Mauery outMessage->rcSessionID = session->getRCSessionID();
185d999ffc1SVernon Mauery outMessage->bmcSessionID = sessionID;
18622596f21STom Joseph
18722596f21STom Joseph send(outMessage);
18822596f21STom Joseph }
18922596f21STom Joseph
sendUnsolicitedIPMIPayload(uint8_t netfn,uint8_t cmd,const std::vector<uint8_t> & output)1909e801a2bSVernon Mauery void Handler::sendUnsolicitedIPMIPayload(uint8_t netfn, uint8_t cmd,
19163d3e49cSTom Joseph const std::vector<uint8_t>& output)
19263d3e49cSTom Joseph {
193d999ffc1SVernon Mauery auto outMessage = std::make_shared<Message>();
194d999ffc1SVernon Mauery outMessage->payloadType = PayloadType::IPMI;
195d999ffc1SVernon Mauery outMessage->isPacketEncrypted = session->isCryptAlgoEnabled();
196d999ffc1SVernon Mauery outMessage->isPacketAuthenticated = session->isIntegrityAlgoEnabled();
197d999ffc1SVernon Mauery outMessage->rcSessionID = session->getRCSessionID();
198d999ffc1SVernon Mauery outMessage->bmcSessionID = sessionID;
19963d3e49cSTom Joseph
200d999ffc1SVernon Mauery outMessage->payload.resize(sizeof(LAN::header::Request) + output.size() +
20163d3e49cSTom Joseph sizeof(LAN::trailer::Request));
20263d3e49cSTom Joseph
2039e801a2bSVernon Mauery auto respHeader =
204d999ffc1SVernon Mauery reinterpret_cast<LAN::header::Request*>(outMessage->payload.data());
20563d3e49cSTom Joseph
20663d3e49cSTom Joseph // Add IPMI LAN Message Request Header
20763d3e49cSTom Joseph respHeader->rsaddr = LAN::requesterBMCAddress;
20863d3e49cSTom Joseph respHeader->netfn = (netfn << 0x02);
20963d3e49cSTom Joseph respHeader->cs = crc8bit(&(respHeader->rsaddr), 2);
21063d3e49cSTom Joseph respHeader->rqaddr = LAN::responderBMCAddress;
21163d3e49cSTom Joseph respHeader->rqseq = 0;
21263d3e49cSTom Joseph respHeader->cmd = cmd;
21363d3e49cSTom Joseph
21463d3e49cSTom Joseph auto assembledSize = sizeof(LAN::header::Request);
21563d3e49cSTom Joseph
21663d3e49cSTom Joseph // Copy the output by the execution of the command
2179e801a2bSVernon Mauery std::copy(output.begin(), output.end(),
218d999ffc1SVernon Mauery outMessage->payload.begin() + assembledSize);
21963d3e49cSTom Joseph assembledSize += output.size();
22063d3e49cSTom Joseph
22163d3e49cSTom Joseph // Add the IPMI LAN Message Trailer
2229e801a2bSVernon Mauery auto trailer = reinterpret_cast<LAN::trailer::Request*>(
223d999ffc1SVernon Mauery outMessage->payload.data() + assembledSize);
22463d3e49cSTom Joseph
22563d3e49cSTom Joseph // Calculate the checksum for the field rqaddr in the header to the
22663d3e49cSTom Joseph // command data, 3 corresponds to size of the fields before rqaddr( rsaddr,
22763d3e49cSTom Joseph // netfn, cs).
22863d3e49cSTom Joseph trailer->checksum = crc8bit(&respHeader->rqaddr, assembledSize - 3);
22963d3e49cSTom Joseph
23063d3e49cSTom Joseph send(outMessage);
23163d3e49cSTom Joseph }
23263d3e49cSTom Joseph
233e6361a21STom Joseph } // namespace message
234