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