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/log.hpp> 22 23 #include <regex> 24 25 using namespace phosphor::logging; 26 27 namespace ipmi 28 { 29 30 /** @brief implements the set channel access command 31 * @ param ctx - context pointer 32 * @ param channel - channel number 33 * @ param reserved - skip 4 bits 34 * @ param accessMode - access mode for IPMI messaging 35 * @ param usrAuth - user level authentication (enable/disable) 36 * @ param msgAuth - per message authentication (enable/disable) 37 * @ param alertDisabled - PEF alerting (enable/disable) 38 * @ param chanAccess - channel access 39 * @ param channelPrivLimit - channel privilege limit 40 * @ param reserved - skip 3 bits 41 * @ param channelPrivMode - channel priviledge mode 42 * 43 * @ returns IPMI completion code 44 **/ 45 RspType<> ipmiSetChannelAccess(Context::ptr ctx, uint4_t channel, 46 uint4_t reserved1, uint3_t accessMode, 47 bool usrAuth, bool msgAuth, bool alertDisabled, 48 uint2_t chanAccess, uint4_t channelPrivLimit, 49 uint2_t reserved2, uint2_t channelPrivMode) 50 { 51 if (reserved1 || reserved2 || 52 !isValidPrivLimit(static_cast<uint8_t>(channelPrivLimit))) 53 { 54 log<level::DEBUG>("Set channel access - Invalid field in request"); 55 return responseInvalidFieldRequest(); 56 } 57 58 const uint8_t chNum = 59 convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel); 60 if ((getChannelSessionSupport(chNum) == EChannelSessSupported::none) || 61 (!isValidChannel(chNum))) 62 { 63 log<level::DEBUG>("Set channel access - No support on channel"); 64 return response(ccActionNotSupportedForChannel); 65 } 66 67 ChannelAccess chActData; 68 ChannelAccess chNVData; 69 uint8_t setActFlag = 0; 70 uint8_t setNVFlag = 0; 71 Cc compCode; 72 73 // cannot static cast directly from uint2_t to enum; must go via int 74 uint8_t channelAccessAction = static_cast<uint8_t>(chanAccess); 75 switch (static_cast<EChannelActionType>(channelAccessAction)) 76 { 77 case doNotSet: 78 break; 79 case nvData: 80 chNVData.accessMode = static_cast<uint8_t>(accessMode); 81 chNVData.userAuthDisabled = usrAuth; 82 chNVData.perMsgAuthDisabled = msgAuth; 83 chNVData.alertingDisabled = alertDisabled; 84 setNVFlag |= (setAccessMode | setUserAuthEnabled | 85 setMsgAuthEnabled | setAlertingEnabled); 86 break; 87 88 case activeData: 89 chActData.accessMode = static_cast<uint8_t>(accessMode); 90 chActData.userAuthDisabled = usrAuth; 91 chActData.perMsgAuthDisabled = msgAuth; 92 chActData.alertingDisabled = alertDisabled; 93 setActFlag |= (setAccessMode | setUserAuthEnabled | 94 setMsgAuthEnabled | setAlertingEnabled); 95 break; 96 97 case reserved: 98 default: 99 log<level::DEBUG>("Set channel access - Invalid access set mode"); 100 return response(ccAccessModeNotSupportedForChannel); 101 } 102 103 // cannot static cast directly from uint2_t to enum; must go via int 104 uint8_t channelPrivAction = static_cast<uint8_t>(channelPrivMode); 105 switch (static_cast<EChannelActionType>(channelPrivAction)) 106 { 107 case doNotSet: 108 break; 109 case nvData: 110 chNVData.privLimit = static_cast<uint8_t>(channelPrivLimit); 111 setNVFlag |= setPrivLimit; 112 break; 113 case activeData: 114 chActData.privLimit = static_cast<uint8_t>(channelPrivLimit); 115 116 setActFlag |= setPrivLimit; 117 break; 118 case reserved: 119 default: 120 log<level::DEBUG>("Set channel access - Invalid access priv mode"); 121 return response(ccAccessModeNotSupportedForChannel); 122 } 123 124 if (setNVFlag != 0) 125 { 126 compCode = setChannelAccessPersistData(chNum, chNVData, setNVFlag); 127 if (compCode != ccSuccess) 128 { 129 log<level::DEBUG>("Set channel access - Failed to set access data"); 130 return response(compCode); 131 } 132 } 133 134 if (setActFlag != 0) 135 { 136 compCode = setChannelAccessData(chNum, chActData, setActFlag); 137 if (compCode != ccSuccess) 138 { 139 log<level::DEBUG>("Set channel access - Failed to set access data"); 140 return response(compCode); 141 } 142 } 143 144 return responseSuccess(); 145 } 146 147 /** @brief implements the get channel access command 148 * @ param ctx - context pointer 149 * @ param channel - channel number 150 * @ param reserved1 - skip 4 bits 151 * @ param reserved2 - skip 6 bits 152 * @ param accessMode - get access mode 153 * 154 * @returns ipmi completion code plus response data 155 * - accessMode - get access mode 156 * - usrAuthDisabled - user level authentication status 157 * - msgAuthDisabled - message level authentication status 158 * - alertDisabled - alerting status 159 * - reserved - skip 2 bits 160 * - privLimit - channel privilege limit 161 * - reserved - skip 4 bits 162 * */ 163 ipmi ::RspType<uint3_t, // access mode, 164 bool, // user authentication status, 165 bool, // message authentication status, 166 bool, // alerting status, 167 uint2_t, // reserved, 168 169 uint4_t, // channel privilege, 170 uint4_t // reserved 171 > 172 ipmiGetChannelAccess(Context::ptr ctx, uint4_t channel, uint4_t reserved1, 173 uint6_t reserved2, uint2_t accessSetMode) 174 { 175 if (reserved1 || reserved2) 176 { 177 log<level::DEBUG>("Get channel access - Invalid field in request"); 178 return responseInvalidFieldRequest(); 179 } 180 181 if ((types::enum_cast<EChannelActionType>(accessSetMode) == doNotSet) || 182 (types::enum_cast<EChannelActionType>(accessSetMode) == reserved)) 183 { 184 log<level::DEBUG>("Get channel access - Invalid Access mode"); 185 return responseInvalidFieldRequest(); 186 } 187 188 const uint8_t chNum = 189 convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel); 190 191 if ((getChannelSessionSupport(chNum) == EChannelSessSupported::none) || 192 (!isValidChannel(chNum))) 193 { 194 log<level::DEBUG>("Get channel access - No support on channel"); 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 log<level::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 log<level::DEBUG>("Get channel Info - No support on channel"); 264 return responseInvalidFieldRequest(); 265 } 266 267 ChannelInfo chInfo; 268 Cc compCode = getChannelInfo(chNum, chInfo); 269 if (compCode != ccSuccess) 270 { 271 log<level::ERR>("Failed to get channel info", 272 entry("CHANNEL=%x", chNum), 273 entry("ERRNO=%x", compCode)); 274 return response(compCode); 275 } 276 277 constexpr uint4_t reserved1 = 0; 278 constexpr bool reserved2 = false; 279 constexpr uint3_t reserved3 = 0; 280 uint8_t mediumType = chInfo.mediumType; 281 uint8_t protocolType = chInfo.protocolType; 282 uint2_t sessionType = chInfo.sessionSupported; 283 uint6_t activeSessionCount = getChannelActiveSessions(chNum); 284 // IPMI Spec: The IPMI Enterprise Number is: 7154 (decimal) 285 constexpr uint24_t vendorId = 7154; 286 constexpr uint16_t auxChInfo = 0; 287 288 return responseSuccess(chNum, reserved1, mediumType, reserved2, 289 protocolType, reserved3, activeSessionCount, 290 sessionType, vendorId, auxChInfo); 291 } 292 293 namespace 294 { 295 constexpr uint16_t standardPayloadBit(PayloadType p) 296 { 297 return (1 << static_cast<size_t>(p)); 298 } 299 300 constexpr uint16_t sessionPayloadBit(PayloadType p) 301 { 302 constexpr size_t sessionShift = 303 static_cast<size_t>(PayloadType::OPEN_SESSION_REQUEST); 304 return ((1 << static_cast<size_t>(p)) >> sessionShift); 305 } 306 } // namespace 307 308 /** @brief implements get channel payload support command 309 * @ param ctx - ipmi context pointer 310 * @ param chNum - channel number 311 * @ param reserved - skip 4 bits 312 * 313 * @ returns IPMI completion code plus response data 314 * - stdPayloadType - bitmask of supported standard payload types 315 * - sessSetupPayloadType - bitmask of supported session setup payload types 316 * - OEMPayloadType - bitmask of supported OEM payload types 317 * - reserved - 2 bytes of 0 318 **/ 319 RspType<uint16_t, // stdPayloadType 320 uint16_t, // sessSetupPayloadType 321 uint16_t, // OEMPayloadType 322 uint16_t // reserved 323 > 324 ipmiGetChannelPayloadSupport(Context::ptr ctx, uint4_t channel, 325 uint4_t reserved) 326 { 327 uint8_t chNum = convertCurrentChannelNum(static_cast<uint8_t>(channel), 328 ctx->channel); 329 330 if (!doesDeviceExist(chNum) || !isValidChannel(chNum) || reserved) 331 { 332 log<level::DEBUG>("Get channel payload - Invalid field in request"); 333 return responseInvalidFieldRequest(); 334 } 335 336 // Session support is available in active LAN channels. 337 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none) 338 { 339 log<level::DEBUG>("Get channel payload - No support on channel"); 340 return response(ccActionNotSupportedForChannel); 341 } 342 constexpr uint16_t stdPayloadType = standardPayloadBit(PayloadType::IPMI) | 343 standardPayloadBit(PayloadType::SOL); 344 constexpr uint16_t sessSetupPayloadType = 345 sessionPayloadBit(PayloadType::OPEN_SESSION_REQUEST) | 346 sessionPayloadBit(PayloadType::OPEN_SESSION_RESPONSE) | 347 sessionPayloadBit(PayloadType::RAKP1) | 348 sessionPayloadBit(PayloadType::RAKP2) | 349 sessionPayloadBit(PayloadType::RAKP3) | 350 sessionPayloadBit(PayloadType::RAKP4); 351 constexpr uint16_t OEMPayloadType = 0; 352 constexpr uint16_t rspRsvd = 0; 353 return responseSuccess(stdPayloadType, sessSetupPayloadType, OEMPayloadType, 354 rspRsvd); 355 } 356 357 /** @brief implements the get channel payload version command 358 * @param ctx - IPMI context pointer (for channel) 359 * @param chNum - channel number to get info about 360 * @param reserved - skip 4 bits 361 * @param payloadTypeNum - to get payload type info 362 363 * @returns IPMI completion code plus response data 364 * - formatVersion - BCD encoded format version info 365 */ 366 367 RspType<uint8_t> // formatVersion 368 ipmiGetChannelPayloadVersion(Context::ptr ctx, uint4_t chNum, 369 uint4_t reserved, uint8_t payloadTypeNum) 370 { 371 uint8_t channel = convertCurrentChannelNum(static_cast<uint8_t>(chNum), 372 ctx->channel); 373 constexpr uint8_t payloadTypeNotSupported = 0x80; 374 375 if (reserved || !isValidChannel(channel)) 376 { 377 log<level::DEBUG>( 378 "Get channel payload version - Invalid field in request"); 379 return responseInvalidFieldRequest(); 380 } 381 382 if (getChannelSessionSupport(channel) == EChannelSessSupported::none) 383 { 384 log<level::DEBUG>( 385 "Get channel payload version - No support on channel"); 386 return response(payloadTypeNotSupported); 387 } 388 389 if (!isValidPayloadType(static_cast<PayloadType>(payloadTypeNum))) 390 { 391 log<level::ERR>( 392 "Get channel payload version - Payload type unavailable"); 393 394 return response(payloadTypeNotSupported); 395 } 396 397 // BCD encoded version representation - 1.0 398 constexpr uint8_t formatVersion = 0x10; 399 400 return responseSuccess(formatVersion); 401 } 402 403 void registerChannelFunctions() __attribute__((constructor)); 404 void registerChannelFunctions() 405 { 406 ipmiChannelInit(); 407 408 registerHandler(prioOpenBmcBase, netFnApp, app::cmdSetChannelAccess, 409 Privilege::Admin, ipmiSetChannelAccess); 410 411 registerHandler(prioOpenBmcBase, netFnApp, app::cmdGetChannelAccess, 412 Privilege::User, ipmiGetChannelAccess); 413 414 registerHandler(prioOpenBmcBase, netFnApp, app::cmdGetChannelInfoCommand, 415 Privilege::User, ipmiGetChannelInfo); 416 417 registerHandler(prioOpenBmcBase, netFnApp, app::cmdGetChannelPayloadSupport, 418 Privilege::User, ipmiGetChannelPayloadSupport); 419 420 registerHandler(prioOpenBmcBase, netFnApp, app::cmdGetChannelPayloadVersion, 421 Privilege::User, ipmiGetChannelPayloadVersion); 422 } 423 424 } // namespace ipmi 425