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::unique_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::unique_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::unique_ptr<Message> 50 Handler::createResponse<PayloadType::IPMI>(std::vector<uint8_t>& output, 51 Message& inMessage) 52 { 53 auto outMessage = std::make_unique<Message>(); 54 outMessage->payloadType = PayloadType::IPMI; 55 56 outMessage->payload.resize(sizeof(LAN::header::Response) + output.size() + 57 sizeof(LAN::trailer::Response)); 58 59 auto reqHeader = 60 reinterpret_cast<LAN::header::Request*>(inMessage.payload.data()); 61 auto respHeader = 62 reinterpret_cast<LAN::header::Response*>(outMessage->payload.data()); 63 64 // Add IPMI LAN Message Response Header 65 respHeader->rqaddr = reqHeader->rqaddr; 66 respHeader->netfn = reqHeader->netfn | 0x04; 67 respHeader->cs = crc8bit(&(respHeader->rqaddr), 2); 68 respHeader->rsaddr = reqHeader->rsaddr; 69 respHeader->rqseq = reqHeader->rqseq; 70 respHeader->cmd = reqHeader->cmd; 71 72 auto assembledSize = sizeof(LAN::header::Response); 73 74 // Copy the output by the execution of the command 75 std::copy(output.begin(), output.end(), 76 outMessage->payload.begin() + assembledSize); 77 assembledSize += output.size(); 78 79 // Add the IPMI LAN Message Trailer 80 auto trailer = reinterpret_cast<LAN::trailer::Response*>( 81 outMessage->payload.data() + assembledSize); 82 trailer->checksum = crc8bit(&respHeader->rsaddr, assembledSize - 3); 83 84 return outMessage; 85 } 86 87 std::unique_ptr<Message> Handler::executeCommand(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::unique_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(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(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 Message outMessage; 192 193 auto session = 194 std::get<session::Manager&>(singletonPool).getSession(sessionID); 195 196 outMessage.payloadType = PayloadType::SOL; 197 outMessage.payload = input; 198 outMessage.isPacketEncrypted = session->isCryptAlgoEnabled(); 199 outMessage.isPacketAuthenticated = session->isIntegrityAlgoEnabled(); 200 outMessage.rcSessionID = session->getRCSessionID(); 201 outMessage.bmcSessionID = sessionID; 202 203 send(outMessage); 204 } 205 206 void Handler::sendUnsolicitedIPMIPayload(uint8_t netfn, uint8_t cmd, 207 const std::vector<uint8_t>& output) 208 { 209 Message outMessage; 210 211 auto session = 212 std::get<session::Manager&>(singletonPool).getSession(sessionID); 213 214 outMessage.payloadType = PayloadType::IPMI; 215 outMessage.isPacketEncrypted = session->isCryptAlgoEnabled(); 216 outMessage.isPacketAuthenticated = session->isIntegrityAlgoEnabled(); 217 outMessage.rcSessionID = session->getRCSessionID(); 218 outMessage.bmcSessionID = sessionID; 219 220 outMessage.payload.resize(sizeof(LAN::header::Request) + output.size() + 221 sizeof(LAN::trailer::Request)); 222 223 auto respHeader = 224 reinterpret_cast<LAN::header::Request*>(outMessage.payload.data()); 225 226 // Add IPMI LAN Message Request Header 227 respHeader->rsaddr = LAN::requesterBMCAddress; 228 respHeader->netfn = (netfn << 0x02); 229 respHeader->cs = crc8bit(&(respHeader->rsaddr), 2); 230 respHeader->rqaddr = LAN::responderBMCAddress; 231 respHeader->rqseq = 0; 232 respHeader->cmd = cmd; 233 234 auto assembledSize = sizeof(LAN::header::Request); 235 236 // Copy the output by the execution of the command 237 std::copy(output.begin(), output.end(), 238 outMessage.payload.begin() + assembledSize); 239 assembledSize += output.size(); 240 241 // Add the IPMI LAN Message Trailer 242 auto trailer = reinterpret_cast<LAN::trailer::Request*>( 243 outMessage.payload.data() + assembledSize); 244 245 // Calculate the checksum for the field rqaddr in the header to the 246 // command data, 3 corresponds to size of the fields before rqaddr( rsaddr, 247 // netfn, cs). 248 trailer->checksum = crc8bit(&respHeader->rqaddr, assembledSize - 3); 249 250 send(outMessage); 251 } 252 253 } // namespace message 254