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 static constexpr const uint8_t ccActionNotSupportedForChannel = 0x82; 30 31 /** @brief implements the set channel access command 32 * @ param ctx - context pointer 33 * @ param channel - channel number 34 * @ param reserved - skip 4 bits 35 * @ param accessMode - access mode for IPMI messaging 36 * @ param usrAuth - user level authentication (enable/disable) 37 * @ param msgAuth - per message authentication (enable/disable) 38 * @ param alertDisabled - PEF alerting (enable/disable) 39 * @ param chanAccess - channel access 40 * @ param channelPrivLimit - channel privilege limit 41 * @ param reserved - skip 3 bits 42 * @ param channelPrivMode - channel priviledge mode 43 * 44 * @ returns IPMI completion code 45 **/ 46 RspType<> ipmiSetChannelAccess(Context::ptr ctx, uint4_t channel, 47 uint4_t reserved1, uint3_t accessMode, 48 bool usrAuth, bool msgAuth, bool alertDisabled, 49 uint2_t chanAccess, uint4_t channelPrivLimit, 50 uint2_t reserved2, uint2_t channelPrivMode) 51 { 52 const uint8_t chNum = 53 convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel); 54 55 if (!isValidChannel(chNum) || reserved1 != 0 || reserved2 != 0) 56 { 57 log<level::DEBUG>("Set channel access - Invalid field in request"); 58 return responseInvalidFieldRequest(); 59 } 60 61 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none) 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 responseInvalidFieldRequest(); 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 responseInvalidFieldRequest(); 122 } 123 124 if (setNVFlag != 0) 125 { 126 compCode = setChannelAccessPersistData(chNum, chNVData, setNVFlag); 127 if (compCode != IPMI_CC_OK) 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 != IPMI_CC_OK) 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 const uint8_t chNum = 176 convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel); 177 178 if (!isValidChannel(chNum) || reserved1 != 0 || reserved2 != 0) 179 { 180 log<level::DEBUG>("Get channel access - Invalid field in request"); 181 return responseInvalidFieldRequest(); 182 } 183 184 if ((accessSetMode == doNotSet) || (accessSetMode == reserved)) 185 { 186 log<level::DEBUG>("Get channel access - Invalid Access mode"); 187 return responseInvalidFieldRequest(); 188 } 189 190 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none) 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 != IPMI_CC_OK) 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 uint8_t chNum = 251 convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel); 252 if (!isValidChannel(chNum) || reserved) 253 { 254 log<level::DEBUG>("Get channel access - Invalid field in request"); 255 return responseInvalidFieldRequest(); 256 } 257 258 ChannelInfo chInfo; 259 Cc compCode = getChannelInfo(chNum, chInfo); 260 if (compCode != ccSuccess) 261 { 262 log<level::ERR>("Failed to get channel info", 263 entry("CHANNEL=%x", chNum), 264 entry("ERRNO=%x", compCode)); 265 return response(compCode); 266 } 267 268 constexpr uint4_t reserved1 = 0; 269 constexpr bool reserved2 = false; 270 constexpr uint3_t reserved3 = 0; 271 uint8_t mediumType = chInfo.mediumType; 272 uint8_t protocolType = chInfo.protocolType; 273 uint2_t sessionType = chInfo.sessionSupported; 274 uint6_t activeSessionCount = getChannelActiveSessions(chNum); 275 // IPMI Spec: The IPMI Enterprise Number is: 7154 (decimal) 276 constexpr uint24_t vendorId = 7154; 277 constexpr uint16_t auxChInfo = 0; 278 279 return responseSuccess(chNum, reserved1, mediumType, reserved2, 280 protocolType, reserved3, activeSessionCount, 281 sessionType, vendorId, auxChInfo); 282 } 283 284 namespace 285 { 286 constexpr uint16_t standardPayloadBit(PayloadType p) 287 { 288 return (1 << static_cast<size_t>(p)); 289 } 290 291 constexpr uint16_t sessionPayloadBit(PayloadType p) 292 { 293 constexpr size_t sessionShift = 294 static_cast<size_t>(PayloadType::OPEN_SESSION_REQUEST); 295 return ((1 << static_cast<size_t>(p)) >> sessionShift); 296 } 297 } // namespace 298 299 /** @brief implements get channel payload support command 300 * @ param ctx - ipmi context pointer 301 * @ param chNum - channel number 302 * @ param reserved - skip 4 bits 303 * 304 * @ returns IPMI completion code plus response data 305 * - stdPayloadType - bitmask of supported standard payload types 306 * - sessSetupPayloadType - bitmask of supported session setup payload types 307 * - OEMPayloadType - bitmask of supported OEM payload types 308 * - reserved - 2 bytes of 0 309 **/ 310 RspType<uint16_t, // stdPayloadType 311 uint16_t, // sessSetupPayloadType 312 uint16_t, // OEMPayloadType 313 uint16_t // reserved 314 > 315 ipmiGetChannelPayloadSupport(Context::ptr ctx, uint4_t channel, 316 uint4_t reserved) 317 { 318 uint8_t chNum = 319 convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel); 320 if (!isValidChannel(chNum) || reserved) 321 { 322 log<level::DEBUG>("Get channel access - Invalid field in request"); 323 return responseInvalidFieldRequest(); 324 } 325 326 // Session support is available in active LAN channels. 327 if ((getChannelSessionSupport(chNum) == EChannelSessSupported::none) || 328 !(doesDeviceExist(chNum))) 329 { 330 log<level::DEBUG>("Get channel payload - Device not exist"); 331 return responseInvalidFieldRequest(); 332 } 333 334 constexpr uint16_t stdPayloadType = standardPayloadBit(PayloadType::IPMI) | 335 standardPayloadBit(PayloadType::SOL); 336 constexpr uint16_t sessSetupPayloadType = 337 sessionPayloadBit(PayloadType::OPEN_SESSION_REQUEST) | 338 sessionPayloadBit(PayloadType::OPEN_SESSION_RESPONSE) | 339 sessionPayloadBit(PayloadType::RAKP1) | 340 sessionPayloadBit(PayloadType::RAKP2) | 341 sessionPayloadBit(PayloadType::RAKP3) | 342 sessionPayloadBit(PayloadType::RAKP4); 343 constexpr uint16_t OEMPayloadType = 0; 344 constexpr uint16_t rspRsvd = 0; 345 return responseSuccess(stdPayloadType, sessSetupPayloadType, OEMPayloadType, 346 rspRsvd); 347 } 348 349 /** @brief implements the get channel payload version command 350 * @param ctx - IPMI context pointer (for channel) 351 * @param chNum - channel number to get info about 352 * @param reserved - skip 4 bits 353 * @param payloadTypeNum - to get payload type info 354 355 * @returns IPMI completion code plus response data 356 * - formatVersion - BCD encoded format version info 357 */ 358 359 RspType<uint8_t> // formatVersion 360 ipmiGetChannelPayloadVersion(Context::ptr ctx, uint4_t chNum, 361 uint4_t reserved, uint8_t payloadTypeNum) 362 { 363 uint8_t channel = 364 convertCurrentChannelNum(static_cast<uint8_t>(chNum), ctx->channel); 365 366 if (reserved || !isValidChannel(channel) || 367 (getChannelSessionSupport(channel)) == EChannelSessSupported::none) 368 { 369 return responseInvalidFieldRequest(); 370 } 371 372 if (!isValidPayloadType(static_cast<PayloadType>(payloadTypeNum))) 373 { 374 log<level::ERR>("Channel payload version - Payload type unavailable"); 375 376 constexpr uint8_t payloadTypeNotSupported = 0x80; 377 return response(payloadTypeNotSupported); 378 } 379 380 // BCD encoded version representation - 1.0 381 constexpr uint8_t formatVersion = 0x10; 382 383 return responseSuccess(formatVersion); 384 } 385 386 void registerChannelFunctions() __attribute__((constructor)); 387 void registerChannelFunctions() 388 { 389 ipmiChannelInit(); 390 391 registerHandler(prioOpenBmcBase, netFnApp, app::cmdSetChannelAccess, 392 Privilege::Admin, ipmiSetChannelAccess); 393 394 registerHandler(prioOpenBmcBase, netFnApp, app::cmdGetChannelAccess, 395 Privilege::User, ipmiGetChannelAccess); 396 397 registerHandler(prioOpenBmcBase, netFnApp, app::cmdGetChannelInfoCommand, 398 Privilege::User, ipmiGetChannelInfo); 399 400 registerHandler(prioOpenBmcBase, netFnApp, app::cmdGetChannelPayloadSupport, 401 Privilege::User, ipmiGetChannelPayloadSupport); 402 403 registerHandler(prioOpenBmcBase, netFnApp, app::cmdGetChannelPayloadVersion, 404 Privilege::User, ipmiGetChannelPayloadVersion); 405 } 406 407 } // namespace ipmi 408