1 /* 2 // Copyright (c) 2018 Intel Corporation 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 */ 16 17 #include "apphandler.hpp" 18 #include "channel_layer.hpp" 19 20 #include <ipmid/api.hpp> 21 #include <phosphor-logging/lg2.hpp> 22 23 #include <regex> 24 25 namespace ipmi 26 { 27 28 /** @brief implements the set channel access command 29 * @ param ctx - context pointer 30 * @ param channel - channel number 31 * @ param reserved - skip 4 bits 32 * @ param accessMode - access mode for IPMI messaging 33 * @ param usrAuth - user level authentication (enable/disable) 34 * @ param msgAuth - per message authentication (enable/disable) 35 * @ param alertDisabled - PEF alerting (enable/disable) 36 * @ param chanAccess - channel access 37 * @ param channelPrivLimit - channel privilege limit 38 * @ param reserved - skip 3 bits 39 * @ param channelPrivMode - channel priviledge mode 40 * 41 * @ returns IPMI completion code 42 **/ 43 RspType<> ipmiSetChannelAccess(Context::ptr ctx, uint4_t channel, 44 uint4_t reserved1, uint3_t accessMode, 45 bool usrAuth, bool msgAuth, bool alertDisabled, 46 uint2_t chanAccess, uint4_t channelPrivLimit, 47 uint2_t reserved2, uint2_t channelPrivMode) 48 { 49 if (reserved1 || reserved2 || 50 !isValidPrivLimit(static_cast<uint8_t>(channelPrivLimit))) 51 { 52 lg2::debug("Set channel access - Invalid field in request"); 53 return responseInvalidFieldRequest(); 54 } 55 56 const uint8_t chNum = 57 convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel); 58 if ((getChannelSessionSupport(chNum) == EChannelSessSupported::none) || 59 (!isValidChannel(chNum))) 60 { 61 lg2::debug("Set channel access - No support on channel: {CHANNEL}", 62 "CHANNEL", chNum); 63 return response(ccActionNotSupportedForChannel); 64 } 65 66 ChannelAccess chActData; 67 ChannelAccess chNVData; 68 uint8_t setActFlag = 0; 69 uint8_t setNVFlag = 0; 70 Cc compCode; 71 72 // cannot static cast directly from uint2_t to enum; must go via int 73 uint8_t channelAccessAction = static_cast<uint8_t>(chanAccess); 74 switch (static_cast<EChannelActionType>(channelAccessAction)) 75 { 76 case doNotSet: 77 break; 78 case nvData: 79 chNVData.accessMode = static_cast<uint8_t>(accessMode); 80 chNVData.userAuthDisabled = usrAuth; 81 chNVData.perMsgAuthDisabled = msgAuth; 82 chNVData.alertingDisabled = alertDisabled; 83 setNVFlag |= (setAccessMode | setUserAuthEnabled | 84 setMsgAuthEnabled | setAlertingEnabled); 85 break; 86 87 case activeData: 88 chActData.accessMode = static_cast<uint8_t>(accessMode); 89 chActData.userAuthDisabled = usrAuth; 90 chActData.perMsgAuthDisabled = msgAuth; 91 chActData.alertingDisabled = alertDisabled; 92 setActFlag |= (setAccessMode | setUserAuthEnabled | 93 setMsgAuthEnabled | setAlertingEnabled); 94 break; 95 96 case reserved: 97 default: 98 lg2::debug("Set channel access - Invalid access set mode"); 99 return response(ccAccessModeNotSupportedForChannel); 100 } 101 102 // cannot static cast directly from uint2_t to enum; must go via int 103 uint8_t channelPrivAction = static_cast<uint8_t>(channelPrivMode); 104 switch (static_cast<EChannelActionType>(channelPrivAction)) 105 { 106 case doNotSet: 107 break; 108 case nvData: 109 chNVData.privLimit = static_cast<uint8_t>(channelPrivLimit); 110 setNVFlag |= setPrivLimit; 111 break; 112 case activeData: 113 chActData.privLimit = static_cast<uint8_t>(channelPrivLimit); 114 115 setActFlag |= setPrivLimit; 116 break; 117 case reserved: 118 default: 119 lg2::debug("Set channel access - Invalid access priv mode"); 120 return response(ccAccessModeNotSupportedForChannel); 121 } 122 123 if (setNVFlag != 0) 124 { 125 compCode = setChannelAccessPersistData(chNum, chNVData, setNVFlag); 126 if (compCode != ccSuccess) 127 { 128 lg2::debug("Set channel access - Failed to set access data"); 129 return response(compCode); 130 } 131 } 132 133 if (setActFlag != 0) 134 { 135 compCode = setChannelAccessData(chNum, chActData, setActFlag); 136 if (compCode != ccSuccess) 137 { 138 lg2::debug("Set channel access - Failed to set access data"); 139 return response(compCode); 140 } 141 } 142 143 return responseSuccess(); 144 } 145 146 /** @brief implements the get channel access command 147 * @ param ctx - context pointer 148 * @ param channel - channel number 149 * @ param reserved1 - skip 4 bits 150 * @ param reserved2 - skip 6 bits 151 * @ param accessMode - get access mode 152 * 153 * @returns ipmi completion code plus response data 154 * - accessMode - get access mode 155 * - usrAuthDisabled - user level authentication status 156 * - msgAuthDisabled - message level authentication status 157 * - alertDisabled - alerting status 158 * - reserved - skip 2 bits 159 * - privLimit - channel privilege limit 160 * - reserved - skip 4 bits 161 * */ 162 ipmi ::RspType<uint3_t, // access mode, 163 bool, // user authentication status, 164 bool, // message authentication status, 165 bool, // alerting status, 166 uint2_t, // reserved, 167 168 uint4_t, // channel privilege, 169 uint4_t // reserved 170 > 171 ipmiGetChannelAccess(Context::ptr ctx, uint4_t channel, uint4_t reserved1, 172 uint6_t reserved2, uint2_t accessSetMode) 173 { 174 if (reserved1 || reserved2) 175 { 176 lg2::debug("Get channel access - Invalid field in request"); 177 return responseInvalidFieldRequest(); 178 } 179 180 if ((types::enum_cast<EChannelActionType>(accessSetMode) == doNotSet) || 181 (types::enum_cast<EChannelActionType>(accessSetMode) == reserved)) 182 { 183 lg2::debug("Get channel access - Invalid Access mode"); 184 return responseInvalidFieldRequest(); 185 } 186 187 const uint8_t chNum = 188 convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel); 189 190 if ((getChannelSessionSupport(chNum) == EChannelSessSupported::none) || 191 (!isValidChannel(chNum))) 192 { 193 lg2::debug("Get channel access - No support on channel: {CHANNEL}", 194 "CHANNEL", chNum); 195 return response(ccActionNotSupportedForChannel); 196 } 197 198 ChannelAccess chAccess = {}; 199 200 Cc compCode = ipmi::ccUnspecifiedError; 201 202 if (types::enum_cast<EChannelActionType>(accessSetMode) == nvData) 203 { 204 compCode = getChannelAccessPersistData(chNum, chAccess); 205 } 206 else if (types::enum_cast<EChannelActionType>(accessSetMode) == activeData) 207 { 208 compCode = getChannelAccessData(chNum, chAccess); 209 } 210 211 if (compCode != ccSuccess) 212 { 213 return response(compCode); 214 } 215 216 constexpr uint2_t reservedOut1 = 0; 217 constexpr uint4_t reservedOut2 = 0; 218 219 return responseSuccess( 220 types::enum_cast<uint3_t>(chAccess.accessMode), 221 chAccess.userAuthDisabled, chAccess.perMsgAuthDisabled, 222 chAccess.alertingDisabled, reservedOut1, 223 types::enum_cast<uint4_t>(chAccess.privLimit), reservedOut2); 224 } 225 226 /** @brief implements the get channel info command 227 * @ param ctx - context pointer 228 * @ param channel - channel number 229 * @ param reserved - skip 4 bits 230 * 231 * @returns ipmi completion code plus response data 232 * - chNum - the channel number for this request 233 * - mediumType - see Table 6-3, Channel Medium Type Numbers 234 * - protocolType - Table 6-2, Channel Protocol Type Numbers 235 * - activeSessionCount - number of active sessions 236 * - sessionType - channel support for sessions 237 * - vendorId - vendor for this channel protocol (IPMI - 7154) 238 * - auxChInfo - auxiliary info for channel 239 * */ 240 RspType<uint4_t, // chNum 241 uint4_t, // reserved 242 uint7_t, // mediumType 243 bool, // reserved 244 uint5_t, // protocolType 245 uint3_t, // reserved 246 uint6_t, // activeSessionCount 247 uint2_t, // sessionType 248 uint24_t, // Vendor IANA 249 uint16_t // aux info 250 > 251 ipmiGetChannelInfo(Context::ptr ctx, uint4_t channel, uint4_t reserved) 252 { 253 if (reserved) 254 { 255 lg2::debug("Get channel access - Invalid field in request"); 256 return responseInvalidFieldRequest(); 257 } 258 259 uint8_t chNum = convertCurrentChannelNum(static_cast<uint8_t>(channel), 260 ctx->channel); 261 if (!isValidChannel(chNum)) 262 { 263 lg2::debug("Get channel Info - No support on channel: {CHANNEL}", 264 "CHANNEL", chNum); 265 return responseInvalidFieldRequest(); 266 } 267 268 ChannelInfo chInfo; 269 Cc compCode = getChannelInfo(chNum, chInfo); 270 if (compCode != ccSuccess) 271 { 272 lg2::error("Failed to get channel info, channel: {CHANNEL}, " 273 "errno: {ERRNO}", 274 "CHANNEL", chNum, "ERRNO", compCode); 275 return response(compCode); 276 } 277 278 constexpr uint4_t reserved1 = 0; 279 constexpr bool reserved2 = false; 280 constexpr uint3_t reserved3 = 0; 281 uint8_t mediumType = chInfo.mediumType; 282 uint8_t protocolType = chInfo.protocolType; 283 uint2_t sessionType = chInfo.sessionSupported; 284 uint6_t activeSessionCount = getChannelActiveSessions(chNum); 285 // IPMI Spec: The IPMI Enterprise Number is: 7154 (decimal) 286 constexpr uint24_t vendorId = 7154; 287 constexpr uint16_t auxChInfo = 0; 288 289 return responseSuccess(chNum, reserved1, mediumType, reserved2, 290 protocolType, reserved3, activeSessionCount, 291 sessionType, vendorId, auxChInfo); 292 } 293 294 namespace 295 { 296 constexpr uint16_t standardPayloadBit(PayloadType p) 297 { 298 return (1 << static_cast<size_t>(p)); 299 } 300 301 constexpr uint16_t sessionPayloadBit(PayloadType p) 302 { 303 constexpr size_t sessionShift = 304 static_cast<size_t>(PayloadType::OPEN_SESSION_REQUEST); 305 return ((1 << static_cast<size_t>(p)) >> sessionShift); 306 } 307 } // namespace 308 309 /** @brief implements get channel payload support command 310 * @ param ctx - ipmi context pointer 311 * @ param chNum - channel number 312 * @ param reserved - skip 4 bits 313 * 314 * @ returns IPMI completion code plus response data 315 * - stdPayloadType - bitmask of supported standard payload types 316 * - sessSetupPayloadType - bitmask of supported session setup payload types 317 * - OEMPayloadType - bitmask of supported OEM payload types 318 * - reserved - 2 bytes of 0 319 **/ 320 RspType<uint16_t, // stdPayloadType 321 uint16_t, // sessSetupPayloadType 322 uint16_t, // OEMPayloadType 323 uint16_t // reserved 324 > 325 ipmiGetChannelPayloadSupport(Context::ptr ctx, uint4_t channel, 326 uint4_t reserved) 327 { 328 uint8_t chNum = convertCurrentChannelNum(static_cast<uint8_t>(channel), 329 ctx->channel); 330 331 if (!doesDeviceExist(chNum) || !isValidChannel(chNum) || reserved) 332 { 333 lg2::debug("Get channel payload - Invalid field in request"); 334 return responseInvalidFieldRequest(); 335 } 336 337 // Session support is available in active LAN channels. 338 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none) 339 { 340 lg2::debug("Get channel payload - No support on channel"); 341 return response(ccActionNotSupportedForChannel); 342 } 343 constexpr uint16_t stdPayloadType = standardPayloadBit(PayloadType::IPMI) | 344 standardPayloadBit(PayloadType::SOL); 345 constexpr uint16_t sessSetupPayloadType = 346 sessionPayloadBit(PayloadType::OPEN_SESSION_REQUEST) | 347 sessionPayloadBit(PayloadType::OPEN_SESSION_RESPONSE) | 348 sessionPayloadBit(PayloadType::RAKP1) | 349 sessionPayloadBit(PayloadType::RAKP2) | 350 sessionPayloadBit(PayloadType::RAKP3) | 351 sessionPayloadBit(PayloadType::RAKP4); 352 constexpr uint16_t OEMPayloadType = 0; 353 constexpr uint16_t rspRsvd = 0; 354 return responseSuccess(stdPayloadType, sessSetupPayloadType, OEMPayloadType, 355 rspRsvd); 356 } 357 358 /** @brief implements the get channel payload version command 359 * @param ctx - IPMI context pointer (for channel) 360 * @param chNum - channel number to get info about 361 * @param reserved - skip 4 bits 362 * @param payloadTypeNum - to get payload type info 363 364 * @returns IPMI completion code plus response data 365 * - formatVersion - BCD encoded format version info 366 */ 367 368 RspType<uint8_t> // formatVersion 369 ipmiGetChannelPayloadVersion(Context::ptr ctx, uint4_t chNum, 370 uint4_t reserved, uint8_t payloadTypeNum) 371 { 372 uint8_t channel = convertCurrentChannelNum(static_cast<uint8_t>(chNum), 373 ctx->channel); 374 constexpr uint8_t payloadTypeNotSupported = 0x80; 375 376 if (reserved || !isValidChannel(channel)) 377 { 378 lg2::debug("Get channel payload version - Invalid field in request"); 379 return responseInvalidFieldRequest(); 380 } 381 382 if (getChannelSessionSupport(channel) == EChannelSessSupported::none) 383 { 384 lg2::debug("Get channel payload version - No support on channel"); 385 return response(payloadTypeNotSupported); 386 } 387 388 if (!isValidPayloadType(static_cast<PayloadType>(payloadTypeNum))) 389 { 390 lg2::error("Get channel payload version - Payload type unavailable"); 391 392 return response(payloadTypeNotSupported); 393 } 394 395 // BCD encoded version representation - 1.0 396 constexpr uint8_t formatVersion = 0x10; 397 398 return responseSuccess(formatVersion); 399 } 400 401 void registerChannelFunctions() __attribute__((constructor)); 402 void registerChannelFunctions() 403 { 404 ipmiChannelInit(); 405 406 registerHandler(prioOpenBmcBase, netFnApp, app::cmdSetChannelAccess, 407 Privilege::Admin, ipmiSetChannelAccess); 408 409 registerHandler(prioOpenBmcBase, netFnApp, app::cmdGetChannelAccess, 410 Privilege::User, ipmiGetChannelAccess); 411 412 registerHandler(prioOpenBmcBase, netFnApp, app::cmdGetChannelInfoCommand, 413 Privilege::User, ipmiGetChannelInfo); 414 415 registerHandler(prioOpenBmcBase, netFnApp, app::cmdGetChannelPayloadSupport, 416 Privilege::User, ipmiGetChannelPayloadSupport); 417 418 registerHandler(prioOpenBmcBase, netFnApp, app::cmdGetChannelPayloadVersion, 419 Privilege::User, ipmiGetChannelPayloadVersion); 420 } 421 422 } // namespace ipmi 423