summaryrefslogtreecommitdiffstats
path: root/include/ipmid/api.hpp
blob: b825796a695b2197b95f705ad932cc052d900037 (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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
/*
 * Copyright © 2018 Intel Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
#pragma once

#define ALLOW_DEPRECATED_API 1

#include <ipmid/iana.hpp>
#include <ipmid/message/types.hpp>
#include <optional>
#include <sdbusplus/asio/connection.hpp>
#include <sdbusplus/asio/object_server.hpp>

/* NOTE:
 *
 * This is intended for native C++ use. For the legacy C api, include
 * ipmid-api.h for a reduced functionality. Note that the C api is now marked
 * as deprecated and will be removed once all the internal users of it have
 * been updated to use the new C++ api.
 */

namespace ipmi
{

using Iana = oem::Number;

using Group = uint8_t;
constexpr Group groupPICMG = 0x00;
constexpr Group groupDMTG = 0x01;
constexpr Group groupSSI = 0x02;
constexpr Group groupVSO = 0x03;
constexpr Group groupDCMI = 0xDC;

/*
 * Set the priority as the lowest number that is necessary so
 * it is possible that others can override it if desired.
 * This may be linked to what level of integration the handler
 * is being created at.
 */
constexpr int prioOpenBmcBase = 10;
constexpr int prioOemBase = 20;
constexpr int prioOdmBase = 30;
constexpr int prioCustomBase = 40;
constexpr int prioMax = 50;

/*
 * Channel IDs pulled from the IPMI 2.0 specification
 */
constexpr int channelPrimaryIpmb = 0x00;
// 0x01-0x0B Implementation specific
// Implementation specific channel numbers are specified
// by a configuration file external to ipmid
// 0x0C-0x0D reserved
constexpr int channelCurrentIface = 0x0E; // 'Present I/F'
constexpr int channelSystemIface = 0x0F;

/*
 * Specifies the minimum privilege level required to execute the command
 * This means the command can be executed at a given privilege level or higher
 * privilege level. Those commands which can be executed via system interface
 * only should use SYSTEM_INTERFACE
 */
enum class Privilege : uint8_t
{
    None = 0x00,
    Callback,
    User,
    Operator,
    Admin,
    Oem,
};

// IPMI Net Function number as specified by IPMI V2.0 spec.
using NetFn = uint8_t;

// IPMI Command for a Net Function number as specified by IPMI V2.0 spec.
using Cmd = uint8_t;

// ipmi function return the status code
using Cc = uint8_t;

// These are the command network functions, the response
// network functions are the function + 1. So to determine
// the proper network function which issued the command
// associated with a response, subtract 1.
// Note: these will be left shifted when combined with the LUN
constexpr NetFn netFnChassis = 0x00;
constexpr NetFn netFnBridge = 0x02;
constexpr NetFn netFnSensor = 0x04;
constexpr NetFn netFnApp = 0x06;
constexpr NetFn netFnFirmware = 0x08;
constexpr NetFn netFnStorage = 0x0A;
constexpr NetFn netFnTransport = 0x0C;
// reserved 0Eh..28h
constexpr NetFn netFnGroup = 0x2C;
constexpr NetFn netFnOem = 0x2E;
constexpr NetFn netFnOemOne = 0x30;
constexpr NetFn netFnOemTwo = 0x32;
constexpr NetFn netFnOemThree = 0x34;
constexpr NetFn netFnOemFour = 0x36;
constexpr NetFn netFnOemFive = 0x38;
constexpr NetFn netFnOemSix = 0x3A;
constexpr NetFn netFnOemSeven = 0x3C;
constexpr NetFn netFnOemEight = 0x3E;

// IPMI commands for net functions. Callbacks using this should be careful to
// parse arguments to the sub-functions and can take advantage of the built-in
// message handling mechanism to create custom routing
constexpr Cmd cmdWildcard = 0xFF;

// IPMI standard completion codes specified by the IPMI V2.0 spec.
//
// This might have been an enum class, but that would make it hard for
// OEM- and command-specific completion codes to be added elsewhere.
//
// Custom completion codes can be defined in individual modules for
// command specific errors in the 0x80-0xBE range
//
// Alternately, OEM completion codes are in the 0x01-0x7E range
constexpr Cc ccSuccess = 0x00;
constexpr Cc ccBusy = 0xC0;
constexpr Cc ccInvalidCommand = 0xC1;
constexpr Cc ccInvalidCommandOnLun = 0xC2;
constexpr Cc ccTimeout = 0xC2;
constexpr Cc ccOutOfSpace = 0xC2;
constexpr Cc ccInvalidReservationId = 0xC5;
constexpr Cc ccReqDataTruncated = 0xC6;
constexpr Cc ccReqDataLenInvalid = 0xC7;
constexpr Cc ccReqDataLenExceeded = 0xC8;
constexpr Cc ccParmOutOfRange = 0xC9;
constexpr Cc ccRetBytesUnavailable = 0xCA;
constexpr Cc ccSensorInvalid = 0xCB;
constexpr Cc ccInvalidFieldRequest = 0xCC;
constexpr Cc ccIllegalCommand = 0xCD;
constexpr Cc ccResponseError = 0xCE;
constexpr Cc ccDuplicateRequest = 0xCF;
constexpr Cc ccCmdFailSdrMode = 0xD0;
constexpr Cc ccCmdFailFwUpdMode = 0xD1;
constexpr Cc ccCmdFailInitAgent = 0xD2;
constexpr Cc ccDestinationUnavailable = 0xD3;
constexpr Cc ccInsufficientPrivilege = 0xD4;
constexpr Cc ccCommandNotAvailable = 0xD5;
constexpr Cc ccCommandDisabled = 0xD6;
constexpr Cc ccUnspecifiedError = 0xFF;

/* ipmi often has two return types:
 * 1. Failure: CC is non-zero; no trailing data
 * 2. Success: CC is zero; trailing data (usually a fixed type)
 *
 * using ipmi::response(cc, ...), it will automatically always pack
 * the correct type for the response without having to explicitly type out all
 * the parameters that the function would return.
 *
 * To enable this feature, you just define the ipmi function as returning an
 * ipmi::RspType which has the optional trailing data built in, with your types
 * defined as parameters.
 */

template <typename... RetTypes>
using RspType = std::tuple<ipmi::Cc, std::optional<std::tuple<RetTypes...>>>;

/**
 * @brief helper function to create an IPMI response tuple
 *
 * IPMI handlers all return a tuple with two parts: a completion code and an
 * optional tuple containing the rest of the data to return. This helper
 * function makes it easier by constructing that out of an arbitrary number of
 * arguments.
 *
 * @param cc - the completion code for the response
 * @param args... - the optional list of values to return
 *
 * @return a standard IPMI return type (as described above)
 */
template <typename... Args>
static inline auto response(ipmi::Cc cc, Args&&... args)
{
    return std::make_tuple(cc, std::make_optional(std::make_tuple(args...)));
}
static inline auto response(ipmi::Cc cc)
{
    return std::make_tuple(cc, std::nullopt);
}

/**
 * @brief helper function to create an IPMI success response tuple
 *
 * IPMI handlers all return a tuple with two parts: a completion code and an
 * optional tuple containing the rest of the data to return. This helper
 * function makes it easier by constructing that out of an arbitrary number of
 * arguments. Because it is a success response, this automatically packs
 * the completion code, without needing to explicitly pass it in.
 *
 * @param args... - the optional list of values to return
 *
 * @return a standard IPMI return type (as described above)
 */
template <typename... Args>
static inline auto responseSuccess(Args&&... args)
{
    return std::make_tuple(ipmi::ccSuccess,
                           std::make_optional(std::make_tuple(args...)));
}
static inline auto responseSuccess()
{
    return std::make_tuple(ipmi::ccSuccess, std::nullopt);
}

} // namespace ipmi

// any client can interact with the main asio context
std::shared_ptr<boost::asio::io_context> getIoContext();

// any client can interact with the main sdbus
std::shared_ptr<sdbusplus::asio::connection> getSdBus();

/**
 * @brief post some work to the async exection queue
 *
 * The IPMI daemon runs an async exection queue; this allows any function to
 * pass in work to be executed in that context
 *
 * @tparam WorkFn - a function of type void(void)
 * @param work - the callback function to be executed
 */
template <typename WorkFn>
static inline void post_work(WorkFn work)
{
    getIoContext()->post(std::forward<WorkFn>(work));
}

enum class SignalResponse : int
{
    breakExecution,
    continueExecution,
};

/**
 * @brief add a signal handler
 *
 * This registers a handler to be called asynchronously via the execution
 * queue when the specified signal is received.
 *
 * Priority allows a signal handler to specify what order in the handler
 * chain it gets called. Lower priority numbers will cause the handler to
 * be executed later in the chain, while the highest priority numbers will cause
 * the handler to be executed first.
 *
 * In order to facilitate a chain of handlers, each handler in the chain will be
 * able to return breakExecution or continueExecution. Returning breakExecution
 * will break the chain and no further handlers will execute for that signal.
 * Returning continueExecution will allow lower-priority handlers to execute.
 *
 * By default, the main asio execution loop will register a low priority
 * (prioOpenBmcBase) handler for SIGINT and SIGTERM to cause the process to stop
 * on either of those signals. To prevent one of those signals from causing the
 * process to stop, simply register a higher priority handler that returns
 * breakExecution.
 *
 * @param int - priority of handler
 * @param int - signal number to wait for
 * @param handler - the callback function to be executed
 */
void registerSignalHandler(int priority, int signalNumber,
                           const std::function<SignalResponse(int)>& handler);
OpenPOWER on IntegriCloud