1 #pragma once
2 
3 #include "message.hpp"
4 #include "message_parsers.hpp"
5 #include "session.hpp"
6 #include "sol/console_buffer.hpp"
7 
8 #include <memory>
9 #include <numeric>
10 
11 namespace message
12 {
13 
14 class Handler
15 {
16   public:
17     explicit Handler(
18         std::shared_ptr<udpsocket::Channel> channel,
19         uint32_t sessionID = message::Message::MESSAGE_INVALID_SESSION_ID) :
20         sessionID(sessionID),
21         channel(channel)
22     {
23     }
24 
25     Handler() = delete;
26     ~Handler() = default;
27     Handler(const Handler&) = default;
28     Handler& operator=(const Handler&) = default;
29     Handler(Handler&&) = default;
30     Handler& operator=(Handler&&) = default;
31 
32     /**
33      * @brief Receive the IPMI packet
34      *
35      * Read the data on the socket, get the parser based on the Session
36      * header type and flatten the payload and generate the IPMI message
37      *
38      * @return IPMI Message on success and nullptr on failure
39      *
40      */
41     std::shared_ptr<Message> receive();
42 
43     /**
44      * @brief Process the incoming IPMI message
45      *
46      * The incoming message payload is handled and the command handler for
47      * the Network function and Command is executed and the response message
48      * is returned
49      *
50      * @param[in] inMessage - Incoming Message
51      *
52      * @return Outgoing message on success and nullptr on failure
53      */
54     std::shared_ptr<Message> executeCommand(std::shared_ptr<Message> inMessage);
55 
56     /** @brief Send the outgoing message
57      *
58      *  The payload in the outgoing message is flattened and sent out on the
59      *  socket
60      *
61      *  @param[in] outMessage - Outgoing Message
62      */
63     void send(std::shared_ptr<Message> outMessage);
64 
65     /** @brief Set socket channel in session object */
66     void setChannelInSession() const;
67 
68     /** @brief Send the SOL payload
69      *
70      *  The SOL payload is flattened and sent out on the socket
71      *
72      *  @param[in] input - SOL Payload
73      */
74     void sendSOLPayload(const std::vector<uint8_t>& input);
75 
76     /** @brief Send the unsolicited IPMI payload to the remote console.
77      *
78      *  This is used by commands like SOL activating, in which case the BMC
79      *  has to notify the remote console that a SOL payload is activating
80      *  on another channel.
81      *
82      *  @param[in] netfn - Net function.
83      *  @param[in] cmd - Command.
84      *  @param[in] input - Command request data.
85      */
86     void sendUnsolicitedIPMIPayload(uint8_t netfn, uint8_t cmd,
87                                     const std::vector<uint8_t>& input);
88 
89     // BMC Session ID for the Channel
90     session::SessionID sessionID;
91 
92   private:
93     /** @brief Socket channel for communicating with the remote client.*/
94     std::shared_ptr<udpsocket::Channel> channel;
95 
96     parser::SessionHeader sessionHeader = parser::SessionHeader::IPMI20;
97 
98     /**
99      * @brief Create the response IPMI message
100      *
101      * The IPMI outgoing message is constructed out of payload and the
102      * corresponding fields are populated.For the payload type IPMI, the
103      * LAN message header and trailer are added.
104      *
105      * @tparam[in] T - Outgoing message payload type
106      * @param[in] output - Payload for outgoing message
107      * @param[in] inMessage - Incoming IPMI message
108      *
109      * @return Outgoing message on success and nullptr on failure
110      */
111     template <PayloadType T>
112     std::shared_ptr<Message> createResponse(std::vector<uint8_t>& output,
113                                             std::shared_ptr<Message> inMessage)
114     {
115         auto outMessage = std::make_shared<Message>();
116         outMessage->payloadType = T;
117         outMessage->payload = output;
118         return outMessage;
119     }
120 
121     /**
122      * @brief Extract the command from the IPMI payload
123      *
124      * @param[in] message - Incoming message
125      *
126      * @return Command ID in the incoming message
127      */
128     uint32_t getCommand(std::shared_ptr<Message> message);
129 
130     /**
131      * @brief Calculate 8 bit 2's complement checksum
132      *
133      * Initialize checksum to 0. For each byte, checksum = (checksum + byte)
134      * modulo 256. Then checksum = - checksum. When the checksum and the
135      * bytes are added together, modulo 256, the result should be 0.
136      */
137     uint8_t crc8bit(const uint8_t* ptr, const size_t len)
138     {
139         return (0x100 - std::accumulate(ptr, ptr + len, 0));
140     }
141 };
142 
143 } // namespace message
144