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 <iostream> 12 #include <memory> 13 #include <string> 14 #include <vector> 15 16 namespace message 17 { 18 19 std::shared_ptr<Message> Handler::receive() 20 { 21 std::vector<uint8_t> packet; 22 auto readStatus = 0; 23 24 // Read the packet 25 std::tie(readStatus, packet) = channel->read(); 26 27 // Read of the packet failed 28 if (readStatus < 0) 29 { 30 std::cerr << "E> Error in Read : " << std::hex << readStatus << "\n"; 31 return nullptr; 32 } 33 34 // Unflatten the packet 35 std::shared_ptr<Message> message; 36 std::tie(message, sessionHeader) = parser::unflatten(packet); 37 38 auto session = std::get<session::Manager&>(singletonPool) 39 .getSession(message->bmcSessionID); 40 41 sessionID = message->bmcSessionID; 42 message->rcSessionID = session->getRCSessionID(); 43 session->updateLastTransactionTime(); 44 45 return message; 46 } 47 48 template <> 49 std::shared_ptr<Message> Handler::createResponse<PayloadType::IPMI>( 50 std::vector<uint8_t>& output, std::shared_ptr<Message> inMessage) 51 { 52 auto outMessage = std::make_shared<Message>(); 53 outMessage->payloadType = PayloadType::IPMI; 54 55 outMessage->payload.resize(sizeof(LAN::header::Response) + output.size() + 56 sizeof(LAN::trailer::Response)); 57 58 auto reqHeader = 59 reinterpret_cast<LAN::header::Request*>(inMessage->payload.data()); 60 auto respHeader = 61 reinterpret_cast<LAN::header::Response*>(outMessage->payload.data()); 62 63 // Add IPMI LAN Message Response Header 64 respHeader->rqaddr = reqHeader->rqaddr; 65 respHeader->netfn = reqHeader->netfn | 0x04; 66 respHeader->cs = crc8bit(&(respHeader->rqaddr), 2); 67 respHeader->rsaddr = reqHeader->rsaddr; 68 respHeader->rqseq = reqHeader->rqseq; 69 respHeader->cmd = reqHeader->cmd; 70 71 auto assembledSize = sizeof(LAN::header::Response); 72 73 // Copy the output by the execution of the command 74 std::copy(output.begin(), output.end(), 75 outMessage->payload.begin() + assembledSize); 76 assembledSize += output.size(); 77 78 // Add the IPMI LAN Message Trailer 79 auto trailer = reinterpret_cast<LAN::trailer::Response*>( 80 outMessage->payload.data() + assembledSize); 81 trailer->checksum = crc8bit(&respHeader->rsaddr, assembledSize - 3); 82 83 return outMessage; 84 } 85 86 std::shared_ptr<Message> 87 Handler::executeCommand(std::shared_ptr<Message> inMessage) 88 { 89 // Get the CommandID to map into the command table 90 auto command = getCommand(inMessage); 91 std::vector<uint8_t> output{}; 92 93 if (inMessage->payloadType == PayloadType::IPMI) 94 { 95 if (inMessage->payload.size() < 96 (sizeof(LAN::header::Request) + sizeof(LAN::trailer::Request))) 97 { 98 return nullptr; 99 } 100 101 auto start = inMessage->payload.begin() + sizeof(LAN::header::Request); 102 auto end = inMessage->payload.end() - sizeof(LAN::trailer::Request); 103 std::vector<uint8_t> inPayload(start, end); 104 105 output = std::get<command::Table&>(singletonPool) 106 .executeCommand(command, inPayload, *this); 107 } 108 else 109 { 110 output = std::get<command::Table&>(singletonPool) 111 .executeCommand(command, inMessage->payload, *this); 112 } 113 114 std::shared_ptr<Message> outMessage = nullptr; 115 116 switch (inMessage->payloadType) 117 { 118 case PayloadType::IPMI: 119 outMessage = createResponse<PayloadType::IPMI>(output, inMessage); 120 break; 121 case PayloadType::OPEN_SESSION_REQUEST: 122 outMessage = createResponse<PayloadType::OPEN_SESSION_RESPONSE>( 123 output, inMessage); 124 break; 125 case PayloadType::RAKP1: 126 outMessage = createResponse<PayloadType::RAKP2>(output, inMessage); 127 break; 128 case PayloadType::RAKP3: 129 outMessage = createResponse<PayloadType::RAKP4>(output, inMessage); 130 break; 131 case PayloadType::SOL: 132 return outMessage; 133 break; 134 default: 135 break; 136 } 137 138 outMessage->isPacketEncrypted = inMessage->isPacketEncrypted; 139 outMessage->isPacketAuthenticated = inMessage->isPacketAuthenticated; 140 outMessage->rcSessionID = inMessage->rcSessionID; 141 outMessage->bmcSessionID = inMessage->bmcSessionID; 142 143 return outMessage; 144 } 145 146 uint32_t Handler::getCommand(std::shared_ptr<Message> message) 147 { 148 uint32_t command = 0; 149 150 command |= (static_cast<uint8_t>(message->payloadType) << 16); 151 if (message->payloadType == PayloadType::IPMI) 152 { 153 command |= 154 ((reinterpret_cast<LAN::header::Request*>(message->payload.data())) 155 ->netfn) 156 << 8; 157 command |= 158 (reinterpret_cast<LAN::header::Request*>(message->payload.data())) 159 ->cmd; 160 } 161 162 return command; 163 } 164 165 void Handler::send(std::shared_ptr<Message> outMessage) 166 { 167 auto session = 168 std::get<session::Manager&>(singletonPool).getSession(sessionID); 169 170 // Flatten the packet 171 auto packet = parser::flatten(outMessage, sessionHeader, *session); 172 173 // Write the packet 174 auto writeStatus = channel->write(packet); 175 if (writeStatus < 0) 176 { 177 throw std::runtime_error("Error in writing to socket"); 178 } 179 } 180 181 void Handler::setChannelInSession() const 182 { 183 auto session = 184 std::get<session::Manager&>(singletonPool).getSession(sessionID); 185 186 session->channelPtr = channel; 187 } 188 189 void Handler::sendSOLPayload(const std::vector<uint8_t>& input) 190 { 191 auto session = 192 std::get<session::Manager&>(singletonPool).getSession(sessionID); 193 194 auto outMessage = std::make_shared<Message>(); 195 outMessage->payloadType = PayloadType::SOL; 196 outMessage->payload = input; 197 outMessage->isPacketEncrypted = session->isCryptAlgoEnabled(); 198 outMessage->isPacketAuthenticated = session->isIntegrityAlgoEnabled(); 199 outMessage->rcSessionID = session->getRCSessionID(); 200 outMessage->bmcSessionID = sessionID; 201 202 send(outMessage); 203 } 204 205 void Handler::sendUnsolicitedIPMIPayload(uint8_t netfn, uint8_t cmd, 206 const std::vector<uint8_t>& output) 207 { 208 auto session = 209 std::get<session::Manager&>(singletonPool).getSession(sessionID); 210 211 auto outMessage = std::make_shared<Message>(); 212 outMessage->payloadType = PayloadType::IPMI; 213 outMessage->isPacketEncrypted = session->isCryptAlgoEnabled(); 214 outMessage->isPacketAuthenticated = session->isIntegrityAlgoEnabled(); 215 outMessage->rcSessionID = session->getRCSessionID(); 216 outMessage->bmcSessionID = sessionID; 217 218 outMessage->payload.resize(sizeof(LAN::header::Request) + output.size() + 219 sizeof(LAN::trailer::Request)); 220 221 auto respHeader = 222 reinterpret_cast<LAN::header::Request*>(outMessage->payload.data()); 223 224 // Add IPMI LAN Message Request Header 225 respHeader->rsaddr = LAN::requesterBMCAddress; 226 respHeader->netfn = (netfn << 0x02); 227 respHeader->cs = crc8bit(&(respHeader->rsaddr), 2); 228 respHeader->rqaddr = LAN::responderBMCAddress; 229 respHeader->rqseq = 0; 230 respHeader->cmd = cmd; 231 232 auto assembledSize = sizeof(LAN::header::Request); 233 234 // Copy the output by the execution of the command 235 std::copy(output.begin(), output.end(), 236 outMessage->payload.begin() + assembledSize); 237 assembledSize += output.size(); 238 239 // Add the IPMI LAN Message Trailer 240 auto trailer = reinterpret_cast<LAN::trailer::Request*>( 241 outMessage->payload.data() + assembledSize); 242 243 // Calculate the checksum for the field rqaddr in the header to the 244 // command data, 3 corresponds to size of the fields before rqaddr( rsaddr, 245 // netfn, cs). 246 trailer->checksum = crc8bit(&respHeader->rqaddr, assembledSize - 3); 247 248 send(outMessage); 249 } 250 251 } // namespace message 252