blob: bfc861eaca39fbbc46bfb8a156f16da4197978f5 [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
38
39 auto session = (std::get<session::Manager&>(singletonPool).getSession(
40 message->bmcSessionID)).lock();
41
42 sessionID = message->bmcSessionID;
43 message->rcSessionID = session->getRCSessionID();
44 session->updateLastTransactionTime();
45
46 return message;
47}
48
49template<>
50std::unique_ptr<Message> Handler::createResponse<PayloadType::IPMI>(
51 std::vector<uint8_t>& output, Message& inMessage)
52{
53 auto outMessage = std::make_unique<Message>();
54 outMessage->rcSessionID = inMessage.rcSessionID;
55
56 outMessage->payloadType = PayloadType::IPMI;
57
58 outMessage->payload.resize(sizeof(LAN::header::Response) +
59 output.size() +
60 sizeof(LAN::trailer::Response));
61
62 auto reqHeader = reinterpret_cast<LAN::header::Request*>
63 (inMessage.payload.data());
64 auto respHeader = reinterpret_cast<LAN::header::Response*>
65 (outMessage->payload.data());
66
67 // Add IPMI LAN Message Response Header
68 respHeader->rqaddr = reqHeader->rqaddr;
69 respHeader->netfn = reqHeader->netfn | 0x04;
70 respHeader->cs = crc8bit(&(respHeader->rqaddr), 2);
71 respHeader->rsaddr = reqHeader->rsaddr;
72 respHeader->rqseq = reqHeader->rqseq;
73 respHeader->cmd = reqHeader->cmd;
74
75 auto assembledSize = sizeof(LAN::header::Response);
76
77 // Copy the output by the execution of the command
78 std::copy(output.begin(), output.end(),
79 outMessage->payload.begin() + assembledSize);
80 assembledSize += output.size();
81
82 // Add the IPMI LAN Message Trailer
83 auto trailer = reinterpret_cast<LAN::trailer::Response*>
84 (outMessage->payload.data() + assembledSize);
85 trailer->checksum = crc8bit(&respHeader->rsaddr, assembledSize - 3);
86
87 return outMessage;
88}
89
90std::unique_ptr<Message> Handler::executeCommand(Message& inMessage)
91{
92 // Get the CommandID to map into the command table
93 auto command = getCommand(inMessage);
94 std::vector<uint8_t> output{};
95
96 if (inMessage.payloadType == PayloadType::IPMI)
97 {
98 if (inMessage.payload.size() < (sizeof(LAN::header::Request) +
99 sizeof(LAN::trailer::Request)))
100 {
101 return nullptr;
102 }
103
104 auto start = inMessage.payload.begin() + sizeof(LAN::header::Request);
105 auto end = inMessage.payload.end() - sizeof(LAN::trailer::Request);
106 std::vector<uint8_t> inPayload(start, end);
107
108 output = std::get<command::Table&>(singletonPool).executeCommand(
109 command,
110 inPayload,
111 *this);
112 }
113 else
114 {
115 output = std::get<command::Table&>(singletonPool).executeCommand(
116 command,
117 inMessage.payload,
118 *this);
119 }
120
121 std::unique_ptr<Message> outMessage = nullptr;
122
123 switch (inMessage.payloadType)
124 {
125 case PayloadType::IPMI:
126 outMessage = createResponse<PayloadType::IPMI>(output, inMessage);
127 break;
128 case PayloadType::OPEN_SESSION_REQUEST:
129 outMessage = createResponse<PayloadType::OPEN_SESSION_RESPONSE>(
130 output, inMessage);
131 break;
132 case PayloadType::RAKP1:
133 outMessage = createResponse<PayloadType::RAKP2>(output, inMessage);
134 break;
135 case PayloadType::RAKP3:
136 outMessage = createResponse<PayloadType::RAKP4>(output, inMessage);
137 break;
138 default:
139 break;
140
141 }
142
143 return outMessage;
144}
145
146uint32_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 |= ((reinterpret_cast<LAN::header::Request*>
154 (message.payload.data()))->netfn) << 8;
155 command |= (reinterpret_cast<LAN::header::Request*>
156 (message.payload.data()))->cmd;
157 }
158
159 return command;
160}
161
162int Handler::send(Message& outMessage)
163{
164 auto session = (std::get<session::Manager&>(singletonPool).getSession(
165 sessionID)).lock();
166
167 // Flatten the packet
168 auto packet = parser::flatten(outMessage, sessionHeader, *session);
169
170 // Read the packet
171 auto writeStatus = channel->write(packet);
172 if (writeStatus < 0)
173 {
174 std::cerr << "E> Error in writing : " << std::hex << writeStatus
175 << "\n";
176 }
177
178 return writeStatus;
179}
180
181} //namespace message
182