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