xref: /openbmc/phosphor-net-ipmid/message_handler.cpp (revision 7c75c37404f41d8f4a5d03636d46279cfa949804)
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