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