summaryrefslogtreecommitdiffstats
path: root/message_handler.hpp
blob: 3c996603c2656114c7d605ed1e0c96bd0e37bcab (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#pragma once

#include "message.hpp"
#include "message_parsers.hpp"
#include "session.hpp"
#include "sol/console_buffer.hpp"

#include <iostream>
#include <memory>
#include <numeric>

namespace message
{

class Handler
{
  public:
    explicit Handler(
        std::shared_ptr<udpsocket::Channel> channel,
        uint32_t sessionID = message::Message::MESSAGE_INVALID_SESSION_ID) :
        sessionID(sessionID),
        channel(channel)
    {
    }

    Handler() = delete;
    ~Handler() = default;
    Handler(const Handler&) = default;
    Handler& operator=(const Handler&) = default;
    Handler(Handler&&) = default;
    Handler& operator=(Handler&&) = default;

    /**
     * @brief Receive the IPMI packet
     *
     * Read the data on the socket, get the parser based on the Session
     * header type and flatten the payload and generate the IPMI message
     *
     * @return IPMI Message on success and nullptr on failure
     *
     */
    std::shared_ptr<Message> receive();

    /**
     * @brief Process the incoming IPMI message
     *
     * The incoming message payload is handled and the command handler for
     * the Network function and Command is executed and the response message
     * is returned
     *
     * @param[in] inMessage - Incoming Message
     *
     * @return Outgoing message on success and nullptr on failure
     */
    std::shared_ptr<Message> executeCommand(std::shared_ptr<Message> inMessage);

    /** @brief Send the outgoing message
     *
     *  The payload in the outgoing message is flattened and sent out on the
     *  socket
     *
     *  @param[in] outMessage - Outgoing Message
     */
    void send(std::shared_ptr<Message> outMessage);

    /** @brief Set socket channel in session object */
    void setChannelInSession() const;

    /** @brief Send the SOL payload
     *
     *  The SOL payload is flattened and sent out on the socket
     *
     *  @param[in] input - SOL Payload
     */
    void sendSOLPayload(const std::vector<uint8_t>& input);

    /** @brief Send the unsolicited IPMI payload to the remote console.
     *
     *  This is used by commands like SOL activating, in which case the BMC
     *  has to notify the remote console that a SOL payload is activating
     *  on another channel.
     *
     *  @param[in] netfn - Net function.
     *  @param[in] cmd - Command.
     *  @param[in] input - Command request data.
     */
    void sendUnsolicitedIPMIPayload(uint8_t netfn, uint8_t cmd,
                                    const std::vector<uint8_t>& input);

    // BMC Session ID for the Channel
    session::SessionID sessionID;

  private:
    /** @brief Socket channel for communicating with the remote client.*/
    std::shared_ptr<udpsocket::Channel> channel;

    parser::SessionHeader sessionHeader = parser::SessionHeader::IPMI20;

    /**
     * @brief Create the response IPMI message
     *
     * The IPMI outgoing message is constructed out of payload and the
     * corresponding fields are populated.For the payload type IPMI, the
     * LAN message header and trailer are added.
     *
     * @tparam[in] T - Outgoing message payload type
     * @param[in] output - Payload for outgoing message
     * @param[in] inMessage - Incoming IPMI message
     *
     * @return Outgoing message on success and nullptr on failure
     */
    template <PayloadType T>
    std::shared_ptr<Message> createResponse(std::vector<uint8_t>& output,
                                            std::shared_ptr<Message> inMessage)
    {
        auto outMessage = std::make_shared<Message>();
        outMessage->payloadType = T;
        outMessage->payload = output;
        return outMessage;
    }

    /**
     * @brief Extract the command from the IPMI payload
     *
     * @param[in] message - Incoming message
     *
     * @return Command ID in the incoming message
     */
    uint32_t getCommand(std::shared_ptr<Message> message);

    /**
     * @brief Calculate 8 bit 2's complement checksum
     *
     * Initialize checksum to 0. For each byte, checksum = (checksum + byte)
     * modulo 256. Then checksum = - checksum. When the checksum and the
     * bytes are added together, modulo 256, the result should be 0.
     */
    uint8_t crc8bit(const uint8_t* ptr, const size_t len)
    {
        return (0x100 - std::accumulate(ptr, ptr + len, 0));
    }
};

} // namespace message
OpenPOWER on IntegriCloud