xref: /openbmc/phosphor-net-ipmid/message_handler.cpp (revision 7f268e4daa41598610fbd0926b44a3584f527479)
1 #include "message_handler.hpp"
2 
3 #include "command_table.hpp"
4 #include "main.hpp"
5 #include "message.hpp"
6 #include "message_parsers.hpp"
7 #include "sessions_manager.hpp"
8 
9 #include <sys/socket.h>
10 
11 #include <memory>
12 #include <phosphor-logging/log.hpp>
13 #include <string>
14 #include <vector>
15 
16 using namespace phosphor::logging;
17 
18 namespace message
19 {
20 
21 std::shared_ptr<Message> Handler::receive()
22 {
23     std::vector<uint8_t> packet;
24     auto readStatus = 0;
25 
26     // Read the packet
27     std::tie(readStatus, packet) = channel->read();
28 
29     // Read of the packet failed
30     if (readStatus < 0)
31     {
32         log<level::ERR>("Error in Read", entry("STATUS=%x", readStatus));
33         return nullptr;
34     }
35 
36     // Unflatten the packet
37     std::shared_ptr<Message> message;
38     std::tie(message, sessionHeader) = parser::unflatten(packet);
39 
40     auto session = std::get<session::Manager&>(singletonPool)
41                        .getSession(message->bmcSessionID);
42 
43     sessionID = message->bmcSessionID;
44     message->rcSessionID = session->getRCSessionID();
45     session->updateLastTransactionTime();
46 
47     return message;
48 }
49 
50 std::shared_ptr<Message>
51     Handler::executeCommand(std::shared_ptr<Message> inMessage)
52 {
53     // Get the CommandID to map into the command table
54     auto command = inMessage->getCommand();
55     std::vector<uint8_t> output{};
56 
57     if (inMessage->payloadType == PayloadType::IPMI)
58     {
59         if (inMessage->payload.size() <
60             (sizeof(LAN::header::Request) + sizeof(LAN::trailer::Request)))
61         {
62             return nullptr;
63         }
64 
65         auto start = inMessage->payload.begin() + sizeof(LAN::header::Request);
66         auto end = inMessage->payload.end() - sizeof(LAN::trailer::Request);
67         std::vector<uint8_t> inPayload(start, end);
68 
69         output = std::get<command::Table&>(singletonPool)
70                      .executeCommand(command, inPayload, *this);
71     }
72     else
73     {
74         output = std::get<command::Table&>(singletonPool)
75                      .executeCommand(command, inMessage->payload, *this);
76     }
77     return inMessage->createResponse(output);
78 }
79 
80 void Handler::send(std::shared_ptr<Message> outMessage)
81 {
82     auto session =
83         std::get<session::Manager&>(singletonPool).getSession(sessionID);
84 
85     // Flatten the packet
86     auto packet = parser::flatten(outMessage, sessionHeader, session);
87 
88     // Write the packet
89     auto writeStatus = channel->write(packet);
90     if (writeStatus < 0)
91     {
92         throw std::runtime_error("Error in writing to socket");
93     }
94 }
95 
96 void Handler::setChannelInSession() const
97 {
98     auto session =
99         std::get<session::Manager&>(singletonPool).getSession(sessionID);
100 
101     session->channelPtr = channel;
102 }
103 
104 void Handler::sendSOLPayload(const std::vector<uint8_t>& input)
105 {
106     auto session =
107         std::get<session::Manager&>(singletonPool).getSession(sessionID);
108 
109     auto outMessage = std::make_shared<Message>();
110     outMessage->payloadType = PayloadType::SOL;
111     outMessage->payload = input;
112     outMessage->isPacketEncrypted = session->isCryptAlgoEnabled();
113     outMessage->isPacketAuthenticated = session->isIntegrityAlgoEnabled();
114     outMessage->rcSessionID = session->getRCSessionID();
115     outMessage->bmcSessionID = sessionID;
116 
117     send(outMessage);
118 }
119 
120 void Handler::sendUnsolicitedIPMIPayload(uint8_t netfn, uint8_t cmd,
121                                          const std::vector<uint8_t>& output)
122 {
123     auto session =
124         std::get<session::Manager&>(singletonPool).getSession(sessionID);
125 
126     auto outMessage = std::make_shared<Message>();
127     outMessage->payloadType = PayloadType::IPMI;
128     outMessage->isPacketEncrypted = session->isCryptAlgoEnabled();
129     outMessage->isPacketAuthenticated = session->isIntegrityAlgoEnabled();
130     outMessage->rcSessionID = session->getRCSessionID();
131     outMessage->bmcSessionID = sessionID;
132 
133     outMessage->payload.resize(sizeof(LAN::header::Request) + output.size() +
134                                sizeof(LAN::trailer::Request));
135 
136     auto respHeader =
137         reinterpret_cast<LAN::header::Request*>(outMessage->payload.data());
138 
139     // Add IPMI LAN Message Request Header
140     respHeader->rsaddr = LAN::requesterBMCAddress;
141     respHeader->netfn = (netfn << 0x02);
142     respHeader->cs = crc8bit(&(respHeader->rsaddr), 2);
143     respHeader->rqaddr = LAN::responderBMCAddress;
144     respHeader->rqseq = 0;
145     respHeader->cmd = cmd;
146 
147     auto assembledSize = sizeof(LAN::header::Request);
148 
149     // Copy the output by the execution of the command
150     std::copy(output.begin(), output.end(),
151               outMessage->payload.begin() + assembledSize);
152     assembledSize += output.size();
153 
154     // Add the IPMI LAN Message Trailer
155     auto trailer = reinterpret_cast<LAN::trailer::Request*>(
156         outMessage->payload.data() + assembledSize);
157 
158     // Calculate the checksum for the field rqaddr in the header to the
159     // command data, 3 corresponds to size of the fields before rqaddr( rsaddr,
160     // netfn, cs).
161     trailer->checksum = crc8bit(&respHeader->rqaddr, assembledSize - 3);
162 
163     send(outMessage);
164 }
165 
166 } // namespace message
167