/* * 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 #include #include #include #include /* 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 using RspType = std::tuple>>; /** * @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 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 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 getIoContext(); // any client can interact with the main sdbus std::shared_ptr 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 static inline void post_work(WorkFn work) { getIoContext()->post(std::forward(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& handler);