blob: 83325175cfb9b630392049e482e91ed39c52cb6d [file] [log] [blame]
Tom Josephe6361a22016-08-10 06:56:25 -05001#include "message_handler.hpp"
2
3#include <sys/socket.h>
4
5#include <iostream>
6#include <memory>
7#include <string>
8#include <vector>
9
10#include "command_table.hpp"
11#include "main.hpp"
12#include "message.hpp"
13#include "message_parsers.hpp"
14#include "sessions_manager.hpp"
15
16namespace message
17{
18
19std::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
Tom Josephe6361a22016-08-10 06:56:25 -050038 auto session = (std::get<session::Manager&>(singletonPool).getSession(
39 message->bmcSessionID)).lock();
40
41 sessionID = message->bmcSessionID;
42 message->rcSessionID = session->getRCSessionID();
43 session->updateLastTransactionTime();
44
45 return message;
46}
47
48template<>
49std::unique_ptr<Message> Handler::createResponse<PayloadType::IPMI>(
50 std::vector<uint8_t>& output, Message& inMessage)
51{
52 auto outMessage = std::make_unique<Message>();
Tom Josephe6361a22016-08-10 06:56:25 -050053 outMessage->payloadType = PayloadType::IPMI;
54
55 outMessage->payload.resize(sizeof(LAN::header::Response) +
56 output.size() +
57 sizeof(LAN::trailer::Response));
58
59 auto reqHeader = reinterpret_cast<LAN::header::Request*>
60 (inMessage.payload.data());
61 auto respHeader = reinterpret_cast<LAN::header::Response*>
62 (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
87std::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() < (sizeof(LAN::header::Request) +
96 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).executeCommand(
106 command,
107 inPayload,
108 *this);
109 }
110 else
111 {
112 output = std::get<command::Table&>(singletonPool).executeCommand(
113 command,
114 inMessage.payload,
115 *this);
116 }
117
118 std::unique_ptr<Message> outMessage = nullptr;
119
120 switch (inMessage.payloadType)
121 {
122 case PayloadType::IPMI:
123 outMessage = createResponse<PayloadType::IPMI>(output, inMessage);
124 break;
125 case PayloadType::OPEN_SESSION_REQUEST:
126 outMessage = createResponse<PayloadType::OPEN_SESSION_RESPONSE>(
127 output, inMessage);
128 break;
129 case PayloadType::RAKP1:
130 outMessage = createResponse<PayloadType::RAKP2>(output, inMessage);
131 break;
132 case PayloadType::RAKP3:
133 outMessage = createResponse<PayloadType::RAKP4>(output, inMessage);
134 break;
135 default:
136 break;
Tom Josephe6361a22016-08-10 06:56:25 -0500137 }
138
Tom Joseph8dfa0f02017-01-10 15:38:20 +0530139 outMessage->isPacketEncrypted = inMessage.isPacketEncrypted;
140 outMessage->isPacketAuthenticated = inMessage.isPacketAuthenticated;
141 outMessage->rcSessionID = inMessage.rcSessionID;
142 outMessage->bmcSessionID = inMessage.bmcSessionID;
143
Tom Josephe6361a22016-08-10 06:56:25 -0500144 return outMessage;
145}
146
147uint32_t Handler::getCommand(Message& message)
148{
149 uint32_t command = 0 ;
150
151 command |= (static_cast<uint8_t>(message.payloadType) << 16);
152 if (message.payloadType == PayloadType::IPMI)
153 {
154 command |= ((reinterpret_cast<LAN::header::Request*>
155 (message.payload.data()))->netfn) << 8;
156 command |= (reinterpret_cast<LAN::header::Request*>
157 (message.payload.data()))->cmd;
158 }
159
160 return command;
161}
162
163int Handler::send(Message& outMessage)
164{
165 auto session = (std::get<session::Manager&>(singletonPool).getSession(
166 sessionID)).lock();
167
168 // Flatten the packet
169 auto packet = parser::flatten(outMessage, sessionHeader, *session);
170
171 // Read the packet
172 auto writeStatus = channel->write(packet);
173 if (writeStatus < 0)
174 {
175 std::cerr << "E> Error in writing : " << std::hex << writeStatus
176 << "\n";
177 }
178
179 return writeStatus;
180}
181
182} //namespace message
183