| /* |
| // 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 <ipmid/api.hpp> |
| #include <phosphor-logging/lg2.hpp> |
| |
| #include <regex> |
| |
| namespace ipmi |
| { |
| |
| /** @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) |
| { |
| if (reserved1 || reserved2 || |
| !isValidPrivLimit(static_cast<uint8_t>(channelPrivLimit))) |
| { |
| lg2::debug("Set channel access - Invalid field in request"); |
| return responseInvalidFieldRequest(); |
| } |
| |
| const uint8_t chNum = |
| convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel); |
| if ((getChannelSessionSupport(chNum) == EChannelSessSupported::none) || |
| (!isValidChannel(chNum))) |
| { |
| lg2::debug("Set channel access - No support on channel: {CHANNEL}", |
| "CHANNEL", chNum); |
| 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<uint8_t>(chanAccess); |
| switch (static_cast<EChannelActionType>(channelAccessAction)) |
| { |
| case doNotSet: |
| break; |
| case nvData: |
| chNVData.accessMode = static_cast<uint8_t>(accessMode); |
| chNVData.userAuthDisabled = usrAuth; |
| chNVData.perMsgAuthDisabled = msgAuth; |
| chNVData.alertingDisabled = alertDisabled; |
| setNVFlag |= (setAccessMode | setUserAuthEnabled | |
| setMsgAuthEnabled | setAlertingEnabled); |
| break; |
| |
| case activeData: |
| chActData.accessMode = static_cast<uint8_t>(accessMode); |
| chActData.userAuthDisabled = usrAuth; |
| chActData.perMsgAuthDisabled = msgAuth; |
| chActData.alertingDisabled = alertDisabled; |
| setActFlag |= (setAccessMode | setUserAuthEnabled | |
| setMsgAuthEnabled | setAlertingEnabled); |
| break; |
| |
| case reserved: |
| default: |
| lg2::debug("Set channel access - Invalid access set mode"); |
| return response(ccAccessModeNotSupportedForChannel); |
| } |
| |
| // cannot static cast directly from uint2_t to enum; must go via int |
| uint8_t channelPrivAction = static_cast<uint8_t>(channelPrivMode); |
| switch (static_cast<EChannelActionType>(channelPrivAction)) |
| { |
| case doNotSet: |
| break; |
| case nvData: |
| chNVData.privLimit = static_cast<uint8_t>(channelPrivLimit); |
| setNVFlag |= setPrivLimit; |
| break; |
| case activeData: |
| chActData.privLimit = static_cast<uint8_t>(channelPrivLimit); |
| |
| setActFlag |= setPrivLimit; |
| break; |
| case reserved: |
| default: |
| lg2::debug("Set channel access - Invalid access priv mode"); |
| return response(ccAccessModeNotSupportedForChannel); |
| } |
| |
| if (setNVFlag != 0) |
| { |
| compCode = setChannelAccessPersistData(chNum, chNVData, setNVFlag); |
| if (compCode != ccSuccess) |
| { |
| lg2::debug("Set channel access - Failed to set access data"); |
| return response(compCode); |
| } |
| } |
| |
| if (setActFlag != 0) |
| { |
| compCode = setChannelAccessData(chNum, chActData, setActFlag); |
| if (compCode != ccSuccess) |
| { |
| lg2::debug("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<uint3_t, // access mode, |
| bool, // user authentication status, |
| bool, // message authentication status, |
| bool, // alerting status, |
| uint2_t, // reserved, |
| |
| uint4_t, // channel privilege, |
| uint4_t // reserved |
| > |
| ipmiGetChannelAccess(Context::ptr ctx, uint4_t channel, uint4_t reserved1, |
| uint6_t reserved2, uint2_t accessSetMode) |
| { |
| if (reserved1 || reserved2) |
| { |
| lg2::debug("Get channel access - Invalid field in request"); |
| return responseInvalidFieldRequest(); |
| } |
| |
| if ((types::enum_cast<EChannelActionType>(accessSetMode) == doNotSet) || |
| (types::enum_cast<EChannelActionType>(accessSetMode) == reserved)) |
| { |
| lg2::debug("Get channel access - Invalid Access mode"); |
| return responseInvalidFieldRequest(); |
| } |
| |
| const uint8_t chNum = |
| convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel); |
| |
| if ((getChannelSessionSupport(chNum) == EChannelSessSupported::none) || |
| (!isValidChannel(chNum))) |
| { |
| lg2::debug("Get channel access - No support on channel: {CHANNEL}", |
| "CHANNEL", chNum); |
| return response(ccActionNotSupportedForChannel); |
| } |
| |
| ChannelAccess chAccess = {}; |
| |
| Cc compCode = ipmi::ccUnspecifiedError; |
| |
| if (types::enum_cast<EChannelActionType>(accessSetMode) == nvData) |
| { |
| compCode = getChannelAccessPersistData(chNum, chAccess); |
| } |
| else if (types::enum_cast<EChannelActionType>(accessSetMode) == activeData) |
| { |
| compCode = getChannelAccessData(chNum, chAccess); |
| } |
| |
| if (compCode != ccSuccess) |
| { |
| return response(compCode); |
| } |
| |
| constexpr uint2_t reservedOut1 = 0; |
| constexpr uint4_t reservedOut2 = 0; |
| |
| return responseSuccess( |
| types::enum_cast<uint3_t>(chAccess.accessMode), |
| chAccess.userAuthDisabled, chAccess.perMsgAuthDisabled, |
| chAccess.alertingDisabled, reservedOut1, |
| types::enum_cast<uint4_t>(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<uint4_t, // chNum |
| uint4_t, // reserved |
| uint7_t, // mediumType |
| bool, // reserved |
| uint5_t, // protocolType |
| uint3_t, // reserved |
| uint6_t, // activeSessionCount |
| uint2_t, // sessionType |
| uint24_t, // Vendor IANA |
| uint16_t // aux info |
| > |
| ipmiGetChannelInfo(Context::ptr ctx, uint4_t channel, uint4_t reserved) |
| { |
| if (reserved) |
| { |
| lg2::debug("Get channel access - Invalid field in request"); |
| return responseInvalidFieldRequest(); |
| } |
| |
| uint8_t chNum = convertCurrentChannelNum(static_cast<uint8_t>(channel), |
| ctx->channel); |
| if (!isValidChannel(chNum)) |
| { |
| lg2::debug("Get channel Info - No support on channel: {CHANNEL}", |
| "CHANNEL", chNum); |
| return responseInvalidFieldRequest(); |
| } |
| |
| ChannelInfo chInfo; |
| Cc compCode = getChannelInfo(chNum, chInfo); |
| if (compCode != ccSuccess) |
| { |
| lg2::error("Failed to get channel info, channel: {CHANNEL}, " |
| "errno: {ERRNO}", |
| "CHANNEL", chNum, "ERRNO", 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<size_t>(p)); |
| } |
| |
| constexpr uint16_t sessionPayloadBit(PayloadType p) |
| { |
| constexpr size_t sessionShift = |
| static_cast<size_t>(PayloadType::OPEN_SESSION_REQUEST); |
| return ((1 << static_cast<size_t>(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<uint16_t, // stdPayloadType |
| uint16_t, // sessSetupPayloadType |
| uint16_t, // OEMPayloadType |
| uint16_t // reserved |
| > |
| ipmiGetChannelPayloadSupport(Context::ptr ctx, uint4_t channel, |
| uint4_t reserved) |
| { |
| uint8_t chNum = convertCurrentChannelNum(static_cast<uint8_t>(channel), |
| ctx->channel); |
| |
| if (!doesDeviceExist(chNum) || !isValidChannel(chNum) || reserved) |
| { |
| lg2::debug("Get channel payload - Invalid field in request"); |
| return responseInvalidFieldRequest(); |
| } |
| |
| // Session support is available in active LAN channels. |
| if (getChannelSessionSupport(chNum) == EChannelSessSupported::none) |
| { |
| lg2::debug("Get channel payload - No support on channel"); |
| return response(ccActionNotSupportedForChannel); |
| } |
| 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<uint8_t> // formatVersion |
| ipmiGetChannelPayloadVersion(Context::ptr ctx, uint4_t chNum, |
| uint4_t reserved, uint8_t payloadTypeNum) |
| { |
| uint8_t channel = convertCurrentChannelNum(static_cast<uint8_t>(chNum), |
| ctx->channel); |
| constexpr uint8_t payloadTypeNotSupported = 0x80; |
| |
| if (reserved || !isValidChannel(channel)) |
| { |
| lg2::debug("Get channel payload version - Invalid field in request"); |
| return responseInvalidFieldRequest(); |
| } |
| |
| if (getChannelSessionSupport(channel) == EChannelSessSupported::none) |
| { |
| lg2::debug("Get channel payload version - No support on channel"); |
| return response(payloadTypeNotSupported); |
| } |
| |
| if (!isValidPayloadType(static_cast<PayloadType>(payloadTypeNum))) |
| { |
| lg2::error("Get channel payload version - Payload type unavailable"); |
| |
| 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 |