1 #pragma once 2 3 #include <map> 4 #include <memory> 5 #include "console_buffer.hpp" 6 #include "session.hpp" 7 #include "sol_context.hpp" 8 9 namespace sol 10 { 11 12 constexpr size_t MAX_PAYLOAD_INSTANCES = 16; 13 constexpr size_t MAX_PAYLOAD_SIZE = 255; 14 constexpr uint8_t MAJOR_VERSION = 0x01; 15 constexpr uint8_t MINOR_VERSION = 0x00; 16 17 constexpr char CONSOLE_SOCKET_PATH[] = "\0obmc-console"; 18 constexpr size_t CONSOLE_SOCKET_PATH_LEN = sizeof(CONSOLE_SOCKET_PATH) - 1; 19 20 constexpr uint8_t accIntervalFactor = 5; 21 constexpr uint8_t retryIntervalFactor = 10; 22 23 using Instance = uint8_t; 24 25 /** @struct CustomFD 26 * 27 * RAII wrapper for file descriptor. 28 */ 29 struct CustomFD 30 { 31 CustomFD(const CustomFD&) = delete; 32 CustomFD& operator=(const CustomFD&) = delete; 33 CustomFD(CustomFD&&) = delete; 34 CustomFD& operator=(CustomFD&&) = delete; 35 36 CustomFD(int fd) : 37 fd(fd) {} 38 39 ~CustomFD(); 40 41 int operator()() const 42 { 43 return fd; 44 } 45 46 private: 47 int fd = -1; 48 }; 49 50 using namespace std::chrono_literals; 51 52 /** @class Manager 53 * 54 * Manager class acts a manager for the SOL payload instances and provides 55 * interfaces to start a payload instance, stop a payload instance and get 56 * reference to the context object. 57 */ 58 class Manager 59 { 60 public: 61 62 /** @brief SOL Payload Instance is the key for the map, the value is the 63 * SOL context. 64 */ 65 using SOLPayloadMap = std::map<Instance, std::unique_ptr<Context>>; 66 67 Manager() = default; 68 ~Manager() = default; 69 Manager(const Manager&) = delete; 70 Manager& operator=(const Manager&) = delete; 71 Manager(Manager&&) = default; 72 Manager& operator=(Manager&&) = default; 73 74 /** @brief Host Console Buffer. */ 75 ConsoleData dataBuffer; 76 77 /** @brief Set in Progress. 78 * 79 * This parameter is used to indicate when any of the SOL parameters 80 * are being updated, and when the changes are completed. The bit is 81 * primarily provided to alert software than some other software or 82 * utility is in the process of making changes to the data. This field 83 * is initialized to set complete. 84 */ 85 uint8_t progress = 0; 86 87 /** @brief SOL enable 88 * 89 * This controls whether the SOL payload can be activated. By default 90 * the SOL is enabled. 91 */ 92 bool enable = true; 93 94 /** @brief SOL payload encryption. 95 * 96 * Force encryption: if the cipher suite for the session supports 97 * encryption, then this setting will force the use of encryption for 98 * all SOL payload data. Encryption controlled by remote console: 99 * Whether SOL packets are encrypted or not is selectable by the remote 100 * console at the time the payload is activated. The default is force 101 * encryption. 102 */ 103 bool forceEncrypt = true; 104 105 /** @brief SOL payload authentication. 106 * 107 * Force authentication: if the cipher suite for the session supports 108 * authentication, then this setting will force the use of for 109 * authentication for all SOL payload data. Authentication controlled 110 * by remote console: Note that for the standard Cipher Suites, 111 * if encryption is used authentication must also be used. Therefore, 112 * while encryption is being used software will not be able to select 113 * using unauthenticated payloads. 114 */ 115 bool forceAuth = true; 116 117 /** @brief SOL privilege level. 118 * 119 * Sets the minimum operating privilege level that is required to be 120 * able to activate SOL using the Activate Payload command. 121 */ 122 session::Privilege solMinPrivilege = session::Privilege::USER; 123 124 /** @brief Character Accumulate Interval 125 * 126 * This sets the typical amount of time that the BMC will wait before 127 * transmitting a partial SOL character data packet. (Where a partial 128 * packet is defined as a packet that has fewer characters to transmit 129 * than the number of characters specified by the character send 130 * threshold. This parameter can be modified by the set SOL 131 * configuration parameters command. The SOL configuration parameter, 132 * Character Accumulate Interval is 5 ms increments, 1-based value. The 133 * parameter value is accumulateInterval/5. The accumulateInterval 134 * needs to be a multiple of 5. 135 */ 136 std::chrono::milliseconds accumulateInterval = 100ms; 137 138 /** @brief Character Send Threshold 139 * 140 * The BMC will automatically send an SOL character data packet 141 * containing this number of characters as soon as this number of 142 * characters (or greater) has been accepted from the baseboard serial 143 * controller into the BMC. This provides a mechanism to tune the 144 * buffer to reduce latency to when the first characters are received 145 * after an idle interval. In the degenerate case, setting this value 146 * to a ‘1’ would cause the BMC to send a packet as soon as the first 147 * character was received. This parameter can be modified by the set 148 * SOL configuration parameters command. 149 */ 150 uint8_t sendThreshold = 1; 151 152 /** @brief Retry Count 153 * 154 * 1-based. 0 = no retries after packet is transmitted. Packet will be 155 * dropped if no ACK/NACK received by time retries expire. The maximum 156 * value for retry count is 7. This parameter can be modified by the 157 * set SOL configuration parameters command. 158 */ 159 uint8_t retryCount = 7; 160 161 /** @brief Retry Interval 162 * 163 * Sets the time that the BMC will wait before the first retry and the 164 * time between retries when sending SOL packets to the remote console. 165 * This parameter can be modified by the set SOL configuration 166 * parameters command. The SOL configuration parameter Retry Interval 167 * is 10 ms increments, 1-based value. The parameter value is 168 * retryInterval/10. The retryInterval needs to be a multiple of 10. 169 */ 170 std::chrono::milliseconds retryInterval = 100ms; 171 172 /** @brief Channel Number 173 * 174 * This parameter indicates which IPMI channel is being used for the 175 * communication parameters (e.g. IP address, MAC address) for the SOL 176 * Payload. Typically, these parameters will come from the same channel 177 * that the Activate Payload command for SOL was accepted over. The 178 * network channel number is defaulted to 1. 179 */ 180 uint8_t channel = 1; 181 182 /** @brief Start a SOL payload instance. 183 * 184 * Starting a payload instance involves creating the context object, 185 * add the accumulate interval timer and retry interval timer to the 186 * event loop. 187 * 188 * @param[in] payloadInstance - SOL payload instance. 189 * @param[in] sessionID - BMC session ID. 190 */ 191 void startPayloadInstance(uint8_t payloadInstance, 192 session::SessionID sessionID); 193 194 /** @brief Stop SOL payload instance. 195 * 196 * Stopping a payload instance involves stopping and removing the 197 * accumulate interval timer and retry interval timer from the event 198 * loop, delete the context object. 199 * 200 * @param[in] payloadInstance - SOL payload instance 201 */ 202 void stopPayloadInstance(uint8_t payloadInstance); 203 204 /** @brief Get SOL Context by Payload Instance. 205 * 206 * @param[in] payloadInstance - SOL payload instance. 207 * 208 * @return reference to the SOL payload context. 209 */ 210 Context& getContext(uint8_t payloadInstance) 211 { 212 auto iter = payloadMap.find(payloadInstance); 213 214 if (iter != payloadMap.end()) 215 { 216 return *(iter->second); 217 } 218 219 std::string msg = "Invalid SOL payload instance " + payloadInstance; 220 throw std::runtime_error(msg.c_str()); 221 } 222 223 /** @brief Get SOL Context by Session ID. 224 * 225 * @param[in] sessionID - IPMI Session ID. 226 * 227 * @return reference to the SOL payload context. 228 */ 229 Context& getContext(session::SessionID sessionID) 230 { 231 for (const auto& kv : payloadMap) 232 { 233 if (kv.second->sessionID == sessionID) 234 { 235 return *kv.second; 236 } 237 } 238 239 std::string msg = "Invalid SOL SessionID " + sessionID; 240 throw std::runtime_error(msg.c_str()); 241 } 242 243 /** @brief Check if SOL payload is active. 244 * 245 * @param[in] payloadInstance - SOL payload instance. 246 * 247 * @return true if the instance is active and false it is not active. 248 */ 249 auto isPayloadActive(uint8_t payloadInstance) const 250 { 251 return (0 != payloadMap.count(payloadInstance)); 252 } 253 254 /** @brief Write data to the host console unix socket. 255 * 256 * @param[in] input - Data from the remote console. 257 * 258 * @return 0 on success and errno on failure. 259 */ 260 int writeConsoleSocket(const std::vector<uint8_t>& input) const; 261 262 private: 263 SOLPayloadMap payloadMap; 264 265 /** @brief File descriptor for the host console. */ 266 std::unique_ptr<CustomFD> consoleFD = nullptr; 267 268 /** @brief Initialize the host console file descriptor. */ 269 void initHostConsoleFd(); 270 }; 271 272 } //namespace sol 273