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 #include <regex> 23 24 using namespace phosphor::logging; 25 26 namespace ipmi 27 { 28 29 /** @brief implements the set channel access command 30 * @ param ctx - context pointer 31 * @ param channel - channel number 32 * @ param reserved - skip 4 bits 33 * @ param accessMode - access mode for IPMI messaging 34 * @ param usrAuth - user level authentication (enable/disable) 35 * @ param msgAuth - per message authentication (enable/disable) 36 * @ param alertDisabled - PEF alerting (enable/disable) 37 * @ param chanAccess - channel access 38 * @ param channelPrivLimit - channel privilege limit 39 * @ param reserved - skip 3 bits 40 * @ param channelPrivMode - channel priviledge mode 41 * 42 * @ returns IPMI completion code 43 **/ 44 RspType<> ipmiSetChannelAccess(Context::ptr ctx, uint4_t channel, 45 uint4_t reserved1, uint3_t accessMode, 46 bool usrAuth, bool msgAuth, bool alertDisabled, 47 uint2_t chanAccess, uint4_t channelPrivLimit, 48 uint2_t reserved2, uint2_t channelPrivMode) 49 { 50 if (reserved1 || reserved2 || 51 !isValidPrivLimit(static_cast<uint8_t>(channelPrivLimit))) 52 { 53 log<level::DEBUG>("Set channel access - Invalid field in request"); 54 return responseInvalidFieldRequest(); 55 } 56 57 const uint8_t chNum = 58 convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel); 59 if ((getChannelSessionSupport(chNum) == EChannelSessSupported::none) || 60 (!isValidChannel(chNum))) 61 { 62 log<level::DEBUG>("Set channel access - No support on channel"); 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 log<level::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 log<level::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 log<level::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 log<level::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 log<level::DEBUG>("Get channel access - Invalid field in request"); 177 return responseInvalidFieldRequest(); 178 } 179 180 if ((accessSetMode == doNotSet) || (accessSetMode == reserved)) 181 { 182 log<level::DEBUG>("Get channel access - Invalid Access mode"); 183 return response(ccAccessModeNotSupportedForChannel); 184 } 185 186 const uint8_t chNum = 187 convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel); 188 189 if ((getChannelSessionSupport(chNum) == EChannelSessSupported::none) || 190 (!isValidChannel(chNum))) 191 { 192 log<level::DEBUG>("Get channel access - No support on channel"); 193 return response(ccActionNotSupportedForChannel); 194 } 195 196 ChannelAccess chAccess; 197 198 Cc compCode; 199 200 if (accessSetMode == nvData) 201 { 202 compCode = getChannelAccessPersistData(chNum, chAccess); 203 } 204 else if (accessSetMode == activeData) 205 { 206 compCode = getChannelAccessData(chNum, chAccess); 207 } 208 209 if (compCode != ccSuccess) 210 { 211 return response(compCode); 212 } 213 214 constexpr uint2_t reservedOut1 = 0; 215 constexpr uint4_t reservedOut2 = 0; 216 217 return responseSuccess( 218 static_cast<uint3_t>(chAccess.accessMode), chAccess.userAuthDisabled, 219 chAccess.perMsgAuthDisabled, chAccess.alertingDisabled, reservedOut1, 220 static_cast<uint4_t>(chAccess.privLimit), reservedOut2); 221 } 222 223 /** @brief implements the get channel info command 224 * @ param ctx - context pointer 225 * @ param channel - channel number 226 * @ param reserved - skip 4 bits 227 * 228 * @returns ipmi completion code plus response data 229 * - chNum - the channel number for this request 230 * - mediumType - see Table 6-3, Channel Medium Type Numbers 231 * - protocolType - Table 6-2, Channel Protocol Type Numbers 232 * - activeSessionCount - number of active sessions 233 * - sessionType - channel support for sessions 234 * - vendorId - vendor for this channel protocol (IPMI - 7154) 235 * - auxChInfo - auxiliary info for channel 236 * */ 237 RspType<uint4_t, // chNum 238 uint4_t, // reserved 239 uint7_t, // mediumType 240 bool, // reserved 241 uint5_t, // protocolType 242 uint3_t, // reserved 243 uint6_t, // activeSessionCount 244 uint2_t, // sessionType 245 uint24_t, // Vendor IANA 246 uint16_t // aux info 247 > 248 ipmiGetChannelInfo(Context::ptr ctx, uint4_t channel, uint4_t reserved) 249 { 250 if (reserved) 251 { 252 log<level::DEBUG>("Get channel access - Invalid field in request"); 253 return responseInvalidFieldRequest(); 254 } 255 256 uint8_t chNum = 257 convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel); 258 if (!isValidChannel(chNum)) 259 { 260 log<level::DEBUG>("Get channel Info - No support on channel"); 261 return response(ccActionNotSupportedForChannel); 262 } 263 264 ChannelInfo chInfo; 265 Cc compCode = getChannelInfo(chNum, chInfo); 266 if (compCode != ccSuccess) 267 { 268 log<level::ERR>("Failed to get channel info", 269 entry("CHANNEL=%x", chNum), 270 entry("ERRNO=%x", compCode)); 271 return response(compCode); 272 } 273 274 constexpr uint4_t reserved1 = 0; 275 constexpr bool reserved2 = false; 276 constexpr uint3_t reserved3 = 0; 277 uint8_t mediumType = chInfo.mediumType; 278 uint8_t protocolType = chInfo.protocolType; 279 uint2_t sessionType = chInfo.sessionSupported; 280 uint6_t activeSessionCount = getChannelActiveSessions(chNum); 281 // IPMI Spec: The IPMI Enterprise Number is: 7154 (decimal) 282 constexpr uint24_t vendorId = 7154; 283 constexpr uint16_t auxChInfo = 0; 284 285 return responseSuccess(chNum, reserved1, mediumType, reserved2, 286 protocolType, reserved3, activeSessionCount, 287 sessionType, vendorId, auxChInfo); 288 } 289 290 namespace 291 { 292 constexpr uint16_t standardPayloadBit(PayloadType p) 293 { 294 return (1 << static_cast<size_t>(p)); 295 } 296 297 constexpr uint16_t sessionPayloadBit(PayloadType p) 298 { 299 constexpr size_t sessionShift = 300 static_cast<size_t>(PayloadType::OPEN_SESSION_REQUEST); 301 return ((1 << static_cast<size_t>(p)) >> sessionShift); 302 } 303 } // namespace 304 305 /** @brief implements get channel payload support command 306 * @ param ctx - ipmi context pointer 307 * @ param chNum - channel number 308 * @ param reserved - skip 4 bits 309 * 310 * @ returns IPMI completion code plus response data 311 * - stdPayloadType - bitmask of supported standard payload types 312 * - sessSetupPayloadType - bitmask of supported session setup payload types 313 * - OEMPayloadType - bitmask of supported OEM payload types 314 * - reserved - 2 bytes of 0 315 **/ 316 RspType<uint16_t, // stdPayloadType 317 uint16_t, // sessSetupPayloadType 318 uint16_t, // OEMPayloadType 319 uint16_t // reserved 320 > 321 ipmiGetChannelPayloadSupport(Context::ptr ctx, uint4_t channel, 322 uint4_t reserved) 323 { 324 uint8_t chNum = 325 convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel); 326 327 if (!doesDeviceExist(chNum) || !isValidChannel(chNum) || reserved) 328 { 329 log<level::DEBUG>("Get channel payload - Invalid field in request"); 330 return responseInvalidFieldRequest(); 331 } 332 333 // Session support is available in active LAN channels. 334 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none) 335 { 336 log<level::DEBUG>("Get channel payload - No support on channel"); 337 return response(ccActionNotSupportedForChannel); 338 } 339 constexpr uint16_t stdPayloadType = standardPayloadBit(PayloadType::IPMI) | 340 standardPayloadBit(PayloadType::SOL); 341 constexpr uint16_t sessSetupPayloadType = 342 sessionPayloadBit(PayloadType::OPEN_SESSION_REQUEST) | 343 sessionPayloadBit(PayloadType::OPEN_SESSION_RESPONSE) | 344 sessionPayloadBit(PayloadType::RAKP1) | 345 sessionPayloadBit(PayloadType::RAKP2) | 346 sessionPayloadBit(PayloadType::RAKP3) | 347 sessionPayloadBit(PayloadType::RAKP4); 348 constexpr uint16_t OEMPayloadType = 0; 349 constexpr uint16_t rspRsvd = 0; 350 return responseSuccess(stdPayloadType, sessSetupPayloadType, OEMPayloadType, 351 rspRsvd); 352 } 353 354 /** @brief implements the get channel payload version command 355 * @param ctx - IPMI context pointer (for channel) 356 * @param chNum - channel number to get info about 357 * @param reserved - skip 4 bits 358 * @param payloadTypeNum - to get payload type info 359 360 * @returns IPMI completion code plus response data 361 * - formatVersion - BCD encoded format version info 362 */ 363 364 RspType<uint8_t> // formatVersion 365 ipmiGetChannelPayloadVersion(Context::ptr ctx, uint4_t chNum, 366 uint4_t reserved, uint8_t payloadTypeNum) 367 { 368 uint8_t channel = 369 convertCurrentChannelNum(static_cast<uint8_t>(chNum), ctx->channel); 370 371 if (reserved || !isValidChannel(channel)) 372 { 373 log<level::DEBUG>( 374 "Get channel payload version - Invalid field in request"); 375 return responseInvalidFieldRequest(); 376 } 377 378 if (getChannelSessionSupport(channel) == EChannelSessSupported::none) 379 { 380 log<level::DEBUG>( 381 "Get channel payload version - No support on channel"); 382 return response(ccActionNotSupportedForChannel); 383 } 384 385 if (!isValidPayloadType(static_cast<PayloadType>(payloadTypeNum))) 386 { 387 log<level::ERR>( 388 "Get channel payload version - Payload type unavailable"); 389 390 constexpr uint8_t payloadTypeNotSupported = 0x80; 391 return response(payloadTypeNotSupported); 392 } 393 394 // BCD encoded version representation - 1.0 395 constexpr uint8_t formatVersion = 0x10; 396 397 return responseSuccess(formatVersion); 398 } 399 400 void registerChannelFunctions() __attribute__((constructor)); 401 void registerChannelFunctions() 402 { 403 ipmiChannelInit(); 404 405 registerHandler(prioOpenBmcBase, netFnApp, app::cmdSetChannelAccess, 406 Privilege::Admin, ipmiSetChannelAccess); 407 408 registerHandler(prioOpenBmcBase, netFnApp, app::cmdGetChannelAccess, 409 Privilege::User, ipmiGetChannelAccess); 410 411 registerHandler(prioOpenBmcBase, netFnApp, app::cmdGetChannelInfoCommand, 412 Privilege::User, ipmiGetChannelInfo); 413 414 registerHandler(prioOpenBmcBase, netFnApp, app::cmdGetChannelPayloadSupport, 415 Privilege::User, ipmiGetChannelPayloadSupport); 416 417 registerHandler(prioOpenBmcBase, netFnApp, app::cmdGetChannelPayloadVersion, 418 Privilege::User, ipmiGetChannelPayloadVersion); 419 } 420 421 } // namespace ipmi 422