/* // Copyright (c) 2018 Intel Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ #include "apphandler.hpp" #include "channel_layer.hpp" #include #include #include using namespace phosphor::logging; namespace ipmi { static constexpr const uint8_t ccActionNotSupportedForChannel = 0x82; /** @brief implements the set channel access command * @ param ctx - context pointer * @ param channel - channel number * @ param reserved - skip 4 bits * @ param accessMode - access mode for IPMI messaging * @ param usrAuth - user level authentication (enable/disable) * @ param msgAuth - per message authentication (enable/disable) * @ param alertDisabled - PEF alerting (enable/disable) * @ param chanAccess - channel access * @ param channelPrivLimit - channel privilege limit * @ param reserved - skip 3 bits * @ param channelPrivMode - channel priviledge mode * * @ returns IPMI completion code **/ RspType<> ipmiSetChannelAccess(Context::ptr ctx, uint4_t channel, uint4_t reserved1, uint3_t accessMode, bool usrAuth, bool msgAuth, bool alertDisabled, uint2_t chanAccess, uint4_t channelPrivLimit, uint2_t reserved2, uint2_t channelPrivMode) { const uint8_t chNum = convertCurrentChannelNum(static_cast(channel), ctx->channel); if (!isValidChannel(chNum) || reserved1 != 0 || reserved2 != 0) { log("Set channel access - Invalid field in request"); return responseInvalidFieldRequest(); } if (getChannelSessionSupport(chNum) == EChannelSessSupported::none) { log("Set channel access - No support on channel"); return response(ccActionNotSupportedForChannel); } ChannelAccess chActData; ChannelAccess chNVData; uint8_t setActFlag = 0; uint8_t setNVFlag = 0; Cc compCode; // cannot static cast directly from uint2_t to enum; must go via int uint8_t channelAccessAction = static_cast(chanAccess); switch (static_cast(channelAccessAction)) { case doNotSet: break; case nvData: chNVData.accessMode = static_cast(accessMode); chNVData.userAuthDisabled = usrAuth; chNVData.perMsgAuthDisabled = msgAuth; chNVData.alertingDisabled = alertDisabled; setNVFlag |= (setAccessMode | setUserAuthEnabled | setMsgAuthEnabled | setAlertingEnabled); break; case activeData: chActData.accessMode = static_cast(accessMode); chActData.userAuthDisabled = usrAuth; chActData.perMsgAuthDisabled = msgAuth; chActData.alertingDisabled = alertDisabled; setActFlag |= (setAccessMode | setUserAuthEnabled | setMsgAuthEnabled | setAlertingEnabled); break; case reserved: default: log("Set channel access - Invalid access set mode"); return responseInvalidFieldRequest(); } // cannot static cast directly from uint2_t to enum; must go via int uint8_t channelPrivAction = static_cast(channelPrivMode); switch (static_cast(channelPrivAction)) { case doNotSet: break; case nvData: chNVData.privLimit = static_cast(channelPrivLimit); setNVFlag |= setPrivLimit; break; case activeData: chActData.privLimit = static_cast(channelPrivLimit); setActFlag |= setPrivLimit; break; case reserved: default: log("Set channel access - Invalid access priv mode"); return responseInvalidFieldRequest(); } if (setNVFlag != 0) { compCode = setChannelAccessPersistData(chNum, chNVData, setNVFlag); if (compCode != IPMI_CC_OK) { log("Set channel access - Failed to set access data"); return response(compCode); } } if (setActFlag != 0) { compCode = setChannelAccessData(chNum, chActData, setActFlag); if (compCode != IPMI_CC_OK) { log("Set channel access - Failed to set access data"); return response(compCode); } } return responseSuccess(); } /** @brief implements the get channel access command * @ param ctx - context pointer * @ param channel - channel number * @ param reserved1 - skip 4 bits * @ param reserved2 - skip 6 bits * @ param accessMode - get access mode * * @returns ipmi completion code plus response data * - accessMode - get access mode * - usrAuthDisabled - user level authentication status * - msgAuthDisabled - message level authentication status * - alertDisabled - alerting status * - reserved - skip 2 bits * - privLimit - channel privilege limit * - reserved - skip 4 bits * */ ipmi ::RspType ipmiGetChannelAccess(Context::ptr ctx, uint4_t channel, uint4_t reserved1, uint6_t reserved2, uint2_t accessSetMode) { const uint8_t chNum = convertCurrentChannelNum(static_cast(channel), ctx->channel); if (!isValidChannel(chNum) || reserved1 != 0 || reserved2 != 0) { log("Get channel access - Invalid field in request"); return responseInvalidFieldRequest(); } if ((accessSetMode == doNotSet) || (accessSetMode == reserved)) { log("Get channel access - Invalid Access mode"); return responseInvalidFieldRequest(); } if (getChannelSessionSupport(chNum) == EChannelSessSupported::none) { log("Get channel access - No support on channel"); return response(ccActionNotSupportedForChannel); } ChannelAccess chAccess; Cc compCode; if (accessSetMode == nvData) { compCode = getChannelAccessPersistData(chNum, chAccess); } else if (accessSetMode == activeData) { compCode = getChannelAccessData(chNum, chAccess); } if (compCode != IPMI_CC_OK) { return response(compCode); } constexpr uint2_t reservedOut1 = 0; constexpr uint4_t reservedOut2 = 0; return responseSuccess( static_cast(chAccess.accessMode), chAccess.userAuthDisabled, chAccess.perMsgAuthDisabled, chAccess.alertingDisabled, reservedOut1, static_cast(chAccess.privLimit), reservedOut2); } /** @brief implements the get channel info command * @ param ctx - context pointer * @ param channel - channel number * @ param reserved - skip 4 bits * * @returns ipmi completion code plus response data * - chNum - the channel number for this request * - mediumType - see Table 6-3, Channel Medium Type Numbers * - protocolType - Table 6-2, Channel Protocol Type Numbers * - activeSessionCount - number of active sessions * - sessionType - channel support for sessions * - vendorId - vendor for this channel protocol (IPMI - 7154) * - auxChInfo - auxiliary info for channel * */ RspType ipmiGetChannelInfo(Context::ptr ctx, uint4_t channel, uint4_t reserved) { uint8_t chNum = convertCurrentChannelNum(static_cast(channel), ctx->channel); if (!isValidChannel(chNum) || reserved) { log("Get channel access - Invalid field in request"); return responseInvalidFieldRequest(); } ChannelInfo chInfo; Cc compCode = getChannelInfo(chNum, chInfo); if (compCode != ccSuccess) { log("Failed to get channel info", entry("CHANNEL=%x", chNum), entry("ERRNO=%x", compCode)); return response(compCode); } constexpr uint4_t reserved1 = 0; constexpr bool reserved2 = false; constexpr uint3_t reserved3 = 0; uint8_t mediumType = chInfo.mediumType; uint8_t protocolType = chInfo.protocolType; uint2_t sessionType = chInfo.sessionSupported; uint6_t activeSessionCount = getChannelActiveSessions(chNum); // IPMI Spec: The IPMI Enterprise Number is: 7154 (decimal) constexpr uint24_t vendorId = 7154; constexpr uint16_t auxChInfo = 0; return responseSuccess(chNum, reserved1, mediumType, reserved2, protocolType, reserved3, activeSessionCount, sessionType, vendorId, auxChInfo); } namespace { constexpr uint16_t standardPayloadBit(PayloadType p) { return (1 << static_cast(p)); } constexpr uint16_t sessionPayloadBit(PayloadType p) { constexpr size_t sessionShift = static_cast(PayloadType::OPEN_SESSION_REQUEST); return ((1 << static_cast(p)) >> sessionShift); } } // namespace /** @brief implements get channel payload support command * @ param ctx - ipmi context pointer * @ param chNum - channel number * @ param reserved - skip 4 bits * * @ returns IPMI completion code plus response data * - stdPayloadType - bitmask of supported standard payload types * - sessSetupPayloadType - bitmask of supported session setup payload types * - OEMPayloadType - bitmask of supported OEM payload types * - reserved - 2 bytes of 0 **/ RspType ipmiGetChannelPayloadSupport(Context::ptr ctx, uint4_t channel, uint4_t reserved) { uint8_t chNum = convertCurrentChannelNum(static_cast(channel), ctx->channel); if (!isValidChannel(chNum) || reserved) { log("Get channel access - Invalid field in request"); return responseInvalidFieldRequest(); } // Session support is available in active LAN channels. if ((getChannelSessionSupport(chNum) == EChannelSessSupported::none) || !(doesDeviceExist(chNum))) { log("Get channel payload - Device not exist"); return responseInvalidFieldRequest(); } constexpr uint16_t stdPayloadType = standardPayloadBit(PayloadType::IPMI) | standardPayloadBit(PayloadType::SOL); constexpr uint16_t sessSetupPayloadType = sessionPayloadBit(PayloadType::OPEN_SESSION_REQUEST) | sessionPayloadBit(PayloadType::OPEN_SESSION_RESPONSE) | sessionPayloadBit(PayloadType::RAKP1) | sessionPayloadBit(PayloadType::RAKP2) | sessionPayloadBit(PayloadType::RAKP3) | sessionPayloadBit(PayloadType::RAKP4); constexpr uint16_t OEMPayloadType = 0; constexpr uint16_t rspRsvd = 0; return responseSuccess(stdPayloadType, sessSetupPayloadType, OEMPayloadType, rspRsvd); } /** @brief implements the get channel payload version command * @param ctx - IPMI context pointer (for channel) * @param chNum - channel number to get info about * @param reserved - skip 4 bits * @param payloadTypeNum - to get payload type info * @returns IPMI completion code plus response data * - formatVersion - BCD encoded format version info */ RspType // formatVersion ipmiGetChannelPayloadVersion(Context::ptr ctx, uint4_t chNum, uint4_t reserved, uint8_t payloadTypeNum) { uint8_t channel = convertCurrentChannelNum(static_cast(chNum), ctx->channel); if (reserved || !isValidChannel(channel) || (getChannelSessionSupport(channel)) == EChannelSessSupported::none) { return responseInvalidFieldRequest(); } if (!isValidPayloadType(static_cast(payloadTypeNum))) { log("Channel payload version - Payload type unavailable"); constexpr uint8_t payloadTypeNotSupported = 0x80; return response(payloadTypeNotSupported); } // BCD encoded version representation - 1.0 constexpr uint8_t formatVersion = 0x10; return responseSuccess(formatVersion); } void registerChannelFunctions() __attribute__((constructor)); void registerChannelFunctions() { ipmiChannelInit(); registerHandler(prioOpenBmcBase, netFnApp, app::cmdSetChannelAccess, Privilege::Admin, ipmiSetChannelAccess); registerHandler(prioOpenBmcBase, netFnApp, app::cmdGetChannelAccess, Privilege::User, ipmiGetChannelAccess); registerHandler(prioOpenBmcBase, netFnApp, app::cmdGetChannelInfoCommand, Privilege::User, ipmiGetChannelInfo); registerHandler(prioOpenBmcBase, netFnApp, app::cmdGetChannelPayloadSupport, Privilege::User, ipmiGetChannelPayloadSupport); registerHandler(prioOpenBmcBase, netFnApp, app::cmdGetChannelPayloadVersion, Privilege::User, ipmiGetChannelPayloadVersion); } } // namespace ipmi