blob: cd0a33bc4040c4279a717f5b2091ddf89baf35de [file] [log] [blame]
/*
// 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/log.hpp>
#include <regex>
using namespace phosphor::logging;
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)))
{
log<level::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)))
{
log<level::DEBUG>("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<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:
log<level::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:
log<level::DEBUG>("Set channel access - Invalid access priv mode");
return response(ccAccessModeNotSupportedForChannel);
}
if (setNVFlag != 0)
{
compCode = setChannelAccessPersistData(chNum, chNVData, setNVFlag);
if (compCode != ccSuccess)
{
log<level::DEBUG>("Set channel access - Failed to set access data");
return response(compCode);
}
}
if (setActFlag != 0)
{
compCode = setChannelAccessData(chNum, chActData, setActFlag);
if (compCode != ccSuccess)
{
log<level::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)
{
log<level::DEBUG>("Get channel access - Invalid field in request");
return responseInvalidFieldRequest();
}
if ((types::enum_cast<EChannelActionType>(accessSetMode) == doNotSet) ||
(types::enum_cast<EChannelActionType>(accessSetMode) == reserved))
{
log<level::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)))
{
log<level::DEBUG>("Get channel access - No support on channel");
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)
{
log<level::DEBUG>("Get channel access - Invalid field in request");
return responseInvalidFieldRequest();
}
uint8_t chNum = convertCurrentChannelNum(static_cast<uint8_t>(channel),
ctx->channel);
if (!isValidChannel(chNum))
{
log<level::DEBUG>("Get channel Info - No support on channel");
return responseInvalidFieldRequest();
}
ChannelInfo chInfo;
Cc compCode = getChannelInfo(chNum, chInfo);
if (compCode != ccSuccess)
{
log<level::ERR>("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<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)
{
log<level::DEBUG>("Get channel payload - Invalid field in request");
return responseInvalidFieldRequest();
}
// Session support is available in active LAN channels.
if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
{
log<level::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))
{
log<level::DEBUG>(
"Get channel payload version - Invalid field in request");
return responseInvalidFieldRequest();
}
if (getChannelSessionSupport(channel) == EChannelSessSupported::none)
{
log<level::DEBUG>(
"Get channel payload version - No support on channel");
return response(payloadTypeNotSupported);
}
if (!isValidPayloadType(static_cast<PayloadType>(payloadTypeNum)))
{
log<level::ERR>(
"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