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 Stop all the active SOL payload instances */ 196 void stopAllPayloadInstance(); 197 198 /** @brief Get SOL Context by Payload Instance. 199 * 200 * @param[in] payloadInstance - SOL payload instance. 201 * 202 * @return reference to the SOL payload context. 203 */ 204 Context& getContext(uint8_t payloadInstance) 205 { 206 auto iter = payloadMap.find(payloadInstance); 207 208 if (iter != payloadMap.end()) 209 { 210 return *(iter->second); 211 } 212 213 std::string msg = "Invalid SOL payload instance " + payloadInstance; 214 throw std::runtime_error(msg.c_str()); 215 } 216 217 /** @brief Get SOL Context by Session ID. 218 * 219 * @param[in] sessionID - IPMI Session ID. 220 * 221 * @return reference to the SOL payload context. 222 */ 223 Context& getContext(session::SessionID sessionID) 224 { 225 for (const auto& kv : payloadMap) 226 { 227 if (kv.second->sessionID == sessionID) 228 { 229 return *kv.second; 230 } 231 } 232 233 std::string msg = "Invalid SOL SessionID " + sessionID; 234 throw std::runtime_error(msg.c_str()); 235 } 236 237 /** @brief Check if SOL payload is active. 238 * 239 * @param[in] payloadInstance - SOL payload instance. 240 * 241 * @return true if the instance is active and false it is not active. 242 */ 243 auto isPayloadActive(uint8_t payloadInstance) const 244 { 245 return (0 != payloadMap.count(payloadInstance)); 246 } 247 248 /** @brief Write data to the host console unix socket. 249 * 250 * @param[in] input - Data from the remote console. 251 * 252 * @return 0 on success and errno on failure. 253 */ 254 int writeConsoleSocket(const std::vector<uint8_t>& input) const; 255 void updateSOLParameter(uint8_t channelNum); 256 257 private: 258 SOLPayloadMap payloadMap; 259 260 /** @brief Local stream socket for the host console. */ 261 std::unique_ptr<boost::asio::local::stream_protocol::socket> consoleSocket = 262 nullptr; 263 264 /** @brief Initialize the host console file descriptor. */ 265 void initConsoleSocket(); 266 267 /** @brief Handle incoming console data on the console socket */ 268 void consoleInputHandler(); 269 }; 270 271 /** @brief Callback method to close SOL sessions for SOL service change */ 272 void registerSOLServiceChangeCallback(); 273 274 } // namespace sol 275