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 const uint8_t chNum = 51 convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel); 52 53 if (!isValidChannel(chNum) || reserved1 != 0 || reserved2 != 0) 54 { 55 log<level::DEBUG>("Set channel access - Invalid field in request"); 56 return responseInvalidFieldRequest(); 57 } 58 59 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none) 60 { 61 log<level::DEBUG>("Set channel access - No support on channel"); 62 return response(ccActionNotSupportedForChannel); 63 } 64 65 ChannelAccess chActData; 66 ChannelAccess chNVData; 67 uint8_t setActFlag = 0; 68 uint8_t setNVFlag = 0; 69 Cc compCode; 70 71 // cannot static cast directly from uint2_t to enum; must go via int 72 uint8_t channelAccessAction = static_cast<uint8_t>(chanAccess); 73 switch (static_cast<EChannelActionType>(channelAccessAction)) 74 { 75 case doNotSet: 76 break; 77 case nvData: 78 chNVData.accessMode = static_cast<uint8_t>(accessMode); 79 chNVData.userAuthDisabled = usrAuth; 80 chNVData.perMsgAuthDisabled = msgAuth; 81 chNVData.alertingDisabled = alertDisabled; 82 setNVFlag |= (setAccessMode | setUserAuthEnabled | 83 setMsgAuthEnabled | setAlertingEnabled); 84 break; 85 86 case activeData: 87 chActData.accessMode = static_cast<uint8_t>(accessMode); 88 chActData.userAuthDisabled = usrAuth; 89 chActData.perMsgAuthDisabled = msgAuth; 90 chActData.alertingDisabled = alertDisabled; 91 setActFlag |= (setAccessMode | setUserAuthEnabled | 92 setMsgAuthEnabled | setAlertingEnabled); 93 break; 94 95 case reserved: 96 default: 97 log<level::DEBUG>("Set channel access - Invalid access set mode"); 98 return responseInvalidFieldRequest(); 99 } 100 101 // cannot static cast directly from uint2_t to enum; must go via int 102 uint8_t channelPrivAction = static_cast<uint8_t>(channelPrivMode); 103 switch (static_cast<EChannelActionType>(channelPrivAction)) 104 { 105 case doNotSet: 106 break; 107 case nvData: 108 chNVData.privLimit = static_cast<uint8_t>(channelPrivLimit); 109 setNVFlag |= setPrivLimit; 110 break; 111 case activeData: 112 chActData.privLimit = static_cast<uint8_t>(channelPrivLimit); 113 114 setActFlag |= setPrivLimit; 115 break; 116 case reserved: 117 default: 118 log<level::DEBUG>("Set channel access - Invalid access priv mode"); 119 return responseInvalidFieldRequest(); 120 } 121 122 if (setNVFlag != 0) 123 { 124 compCode = setChannelAccessPersistData(chNum, chNVData, setNVFlag); 125 if (compCode != ccSuccess) 126 { 127 log<level::DEBUG>("Set channel access - Failed to set access data"); 128 return response(compCode); 129 } 130 } 131 132 if (setActFlag != 0) 133 { 134 compCode = setChannelAccessData(chNum, chActData, setActFlag); 135 if (compCode != ccSuccess) 136 { 137 log<level::DEBUG>("Set channel access - Failed to set access data"); 138 return response(compCode); 139 } 140 } 141 142 return responseSuccess(); 143 } 144 145 /** @brief implements the get channel access command 146 * @ param ctx - context pointer 147 * @ param channel - channel number 148 * @ param reserved1 - skip 4 bits 149 * @ param reserved2 - skip 6 bits 150 * @ param accessMode - get access mode 151 * 152 * @returns ipmi completion code plus response data 153 * - accessMode - get access mode 154 * - usrAuthDisabled - user level authentication status 155 * - msgAuthDisabled - message level authentication status 156 * - alertDisabled - alerting status 157 * - reserved - skip 2 bits 158 * - privLimit - channel privilege limit 159 * - reserved - skip 4 bits 160 * */ 161 ipmi ::RspType<uint3_t, // access mode, 162 bool, // user authentication status, 163 bool, // message authentication status, 164 bool, // alerting status, 165 uint2_t, // reserved, 166 167 uint4_t, // channel privilege, 168 uint4_t // reserved 169 > 170 ipmiGetChannelAccess(Context::ptr ctx, uint4_t channel, uint4_t reserved1, 171 uint6_t reserved2, uint2_t accessSetMode) 172 { 173 const uint8_t chNum = 174 convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel); 175 176 if (!isValidChannel(chNum) || reserved1 != 0 || reserved2 != 0) 177 { 178 log<level::DEBUG>("Get channel access - Invalid field in request"); 179 return responseInvalidFieldRequest(); 180 } 181 182 if ((accessSetMode == doNotSet) || (accessSetMode == reserved)) 183 { 184 log<level::DEBUG>("Get channel access - Invalid Access mode"); 185 return responseInvalidFieldRequest(); 186 } 187 188 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none) 189 { 190 log<level::DEBUG>("Get channel access - No support on channel"); 191 return response(ccActionNotSupportedForChannel); 192 } 193 194 ChannelAccess chAccess; 195 196 Cc compCode; 197 198 if (accessSetMode == nvData) 199 { 200 compCode = getChannelAccessPersistData(chNum, chAccess); 201 } 202 else if (accessSetMode == activeData) 203 { 204 compCode = getChannelAccessData(chNum, chAccess); 205 } 206 207 if (compCode != ccSuccess) 208 { 209 return response(compCode); 210 } 211 212 constexpr uint2_t reservedOut1 = 0; 213 constexpr uint4_t reservedOut2 = 0; 214 215 return responseSuccess( 216 static_cast<uint3_t>(chAccess.accessMode), chAccess.userAuthDisabled, 217 chAccess.perMsgAuthDisabled, chAccess.alertingDisabled, reservedOut1, 218 static_cast<uint4_t>(chAccess.privLimit), reservedOut2); 219 } 220 221 /** @brief implements the get channel info command 222 * @ param ctx - context pointer 223 * @ param channel - channel number 224 * @ param reserved - skip 4 bits 225 * 226 * @returns ipmi completion code plus response data 227 * - chNum - the channel number for this request 228 * - mediumType - see Table 6-3, Channel Medium Type Numbers 229 * - protocolType - Table 6-2, Channel Protocol Type Numbers 230 * - activeSessionCount - number of active sessions 231 * - sessionType - channel support for sessions 232 * - vendorId - vendor for this channel protocol (IPMI - 7154) 233 * - auxChInfo - auxiliary info for channel 234 * */ 235 RspType<uint4_t, // chNum 236 uint4_t, // reserved 237 uint7_t, // mediumType 238 bool, // reserved 239 uint5_t, // protocolType 240 uint3_t, // reserved 241 uint6_t, // activeSessionCount 242 uint2_t, // sessionType 243 uint24_t, // Vendor IANA 244 uint16_t // aux info 245 > 246 ipmiGetChannelInfo(Context::ptr ctx, uint4_t channel, uint4_t reserved) 247 { 248 uint8_t chNum = 249 convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel); 250 if (!isValidChannel(chNum) || reserved) 251 { 252 log<level::DEBUG>("Get channel access - Invalid field in request"); 253 return responseInvalidFieldRequest(); 254 } 255 256 ChannelInfo chInfo; 257 Cc compCode = getChannelInfo(chNum, chInfo); 258 if (compCode != ccSuccess) 259 { 260 log<level::ERR>("Failed to get channel info", 261 entry("CHANNEL=%x", chNum), 262 entry("ERRNO=%x", compCode)); 263 return response(compCode); 264 } 265 266 constexpr uint4_t reserved1 = 0; 267 constexpr bool reserved2 = false; 268 constexpr uint3_t reserved3 = 0; 269 uint8_t mediumType = chInfo.mediumType; 270 uint8_t protocolType = chInfo.protocolType; 271 uint2_t sessionType = chInfo.sessionSupported; 272 uint6_t activeSessionCount = getChannelActiveSessions(chNum); 273 // IPMI Spec: The IPMI Enterprise Number is: 7154 (decimal) 274 constexpr uint24_t vendorId = 7154; 275 constexpr uint16_t auxChInfo = 0; 276 277 return responseSuccess(chNum, reserved1, mediumType, reserved2, 278 protocolType, reserved3, activeSessionCount, 279 sessionType, vendorId, auxChInfo); 280 } 281 282 namespace 283 { 284 constexpr uint16_t standardPayloadBit(PayloadType p) 285 { 286 return (1 << static_cast<size_t>(p)); 287 } 288 289 constexpr uint16_t sessionPayloadBit(PayloadType p) 290 { 291 constexpr size_t sessionShift = 292 static_cast<size_t>(PayloadType::OPEN_SESSION_REQUEST); 293 return ((1 << static_cast<size_t>(p)) >> sessionShift); 294 } 295 } // namespace 296 297 /** @brief implements get channel payload support command 298 * @ param ctx - ipmi context pointer 299 * @ param chNum - channel number 300 * @ param reserved - skip 4 bits 301 * 302 * @ returns IPMI completion code plus response data 303 * - stdPayloadType - bitmask of supported standard payload types 304 * - sessSetupPayloadType - bitmask of supported session setup payload types 305 * - OEMPayloadType - bitmask of supported OEM payload types 306 * - reserved - 2 bytes of 0 307 **/ 308 RspType<uint16_t, // stdPayloadType 309 uint16_t, // sessSetupPayloadType 310 uint16_t, // OEMPayloadType 311 uint16_t // reserved 312 > 313 ipmiGetChannelPayloadSupport(Context::ptr ctx, uint4_t channel, 314 uint4_t reserved) 315 { 316 uint8_t chNum = 317 convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel); 318 if (!isValidChannel(chNum) || reserved) 319 { 320 log<level::DEBUG>("Get channel access - Invalid field in request"); 321 return responseInvalidFieldRequest(); 322 } 323 324 // Session support is available in active LAN channels. 325 if ((getChannelSessionSupport(chNum) == EChannelSessSupported::none) || 326 !(doesDeviceExist(chNum))) 327 { 328 log<level::DEBUG>("Get channel payload - Device not exist"); 329 return responseInvalidFieldRequest(); 330 } 331 332 constexpr uint16_t stdPayloadType = standardPayloadBit(PayloadType::IPMI) | 333 standardPayloadBit(PayloadType::SOL); 334 constexpr uint16_t sessSetupPayloadType = 335 sessionPayloadBit(PayloadType::OPEN_SESSION_REQUEST) | 336 sessionPayloadBit(PayloadType::OPEN_SESSION_RESPONSE) | 337 sessionPayloadBit(PayloadType::RAKP1) | 338 sessionPayloadBit(PayloadType::RAKP2) | 339 sessionPayloadBit(PayloadType::RAKP3) | 340 sessionPayloadBit(PayloadType::RAKP4); 341 constexpr uint16_t OEMPayloadType = 0; 342 constexpr uint16_t rspRsvd = 0; 343 return responseSuccess(stdPayloadType, sessSetupPayloadType, OEMPayloadType, 344 rspRsvd); 345 } 346 347 /** @brief implements the get channel payload version command 348 * @param ctx - IPMI context pointer (for channel) 349 * @param chNum - channel number to get info about 350 * @param reserved - skip 4 bits 351 * @param payloadTypeNum - to get payload type info 352 353 * @returns IPMI completion code plus response data 354 * - formatVersion - BCD encoded format version info 355 */ 356 357 RspType<uint8_t> // formatVersion 358 ipmiGetChannelPayloadVersion(Context::ptr ctx, uint4_t chNum, 359 uint4_t reserved, uint8_t payloadTypeNum) 360 { 361 uint8_t channel = 362 convertCurrentChannelNum(static_cast<uint8_t>(chNum), ctx->channel); 363 364 if (reserved || !isValidChannel(channel) || 365 (getChannelSessionSupport(channel)) == EChannelSessSupported::none) 366 { 367 return responseInvalidFieldRequest(); 368 } 369 370 if (!isValidPayloadType(static_cast<PayloadType>(payloadTypeNum))) 371 { 372 log<level::ERR>("Channel payload version - Payload type unavailable"); 373 374 constexpr uint8_t payloadTypeNotSupported = 0x80; 375 return response(payloadTypeNotSupported); 376 } 377 378 // BCD encoded version representation - 1.0 379 constexpr uint8_t formatVersion = 0x10; 380 381 return responseSuccess(formatVersion); 382 } 383 384 void registerChannelFunctions() __attribute__((constructor)); 385 void registerChannelFunctions() 386 { 387 ipmiChannelInit(); 388 389 registerHandler(prioOpenBmcBase, netFnApp, app::cmdSetChannelAccess, 390 Privilege::Admin, ipmiSetChannelAccess); 391 392 registerHandler(prioOpenBmcBase, netFnApp, app::cmdGetChannelAccess, 393 Privilege::User, ipmiGetChannelAccess); 394 395 registerHandler(prioOpenBmcBase, netFnApp, app::cmdGetChannelInfoCommand, 396 Privilege::User, ipmiGetChannelInfo); 397 398 registerHandler(prioOpenBmcBase, netFnApp, app::cmdGetChannelPayloadSupport, 399 Privilege::User, ipmiGetChannelPayloadSupport); 400 401 registerHandler(prioOpenBmcBase, netFnApp, app::cmdGetChannelPayloadVersion, 402 Privilege::User, ipmiGetChannelPayloadVersion); 403 } 404 405 } // namespace ipmi 406