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 "channelcommands.hpp" 18 19 #include "apphandler.hpp" 20 #include "channel_layer.hpp" 21 22 #include <ipmid/api.hpp> 23 #include <phosphor-logging/log.hpp> 24 #include <regex> 25 26 using namespace phosphor::logging; 27 28 namespace ipmi 29 { 30 31 /** @struct GetChannelPayloadSupportReq 32 * 33 * Structure for get channel payload support command request (refer spec 34 * sec 24.8) 35 */ 36 struct GetChannelPayloadSupportReq 37 { 38 #if BYTE_ORDER == LITTLE_ENDIAN 39 uint8_t chNum : 4; 40 uint8_t reserved : 4; 41 #endif 42 #if BYTE_ORDER == BIG_ENDIAN 43 uint8_t reserved : 4; 44 uint8_t chNum : 4; 45 #endif 46 } __attribute__((packed)); 47 48 /** @struct GetChannelPayloadSupportResp 49 * 50 * Structure for get channel payload support command response (refer spec 51 * sec 24.8) 52 */ 53 struct GetChannelPayloadSupportResp 54 { 55 uint8_t stdPayloadType[2]; 56 uint8_t sessSetupPayloadType[2]; 57 uint8_t OEMPayloadType[2]; 58 uint8_t reserved[2]; 59 } __attribute__((packed)); 60 61 /** @brief implements the set channel access command 62 * @ param ctx - context pointer 63 * @ param channel - channel number 64 * @ param reserved - skip 4 bits 65 * @ param accessMode - access mode for IPMI messaging 66 * @ param usrAuth - user level authentication (enable/disable) 67 * @ param msgAuth - per message authentication (enable/disable) 68 * @ param alertDisabled - PEF alerting (enable/disable) 69 * @ param chanAccess - channel access 70 * @ param channelPrivLimit - channel privilege limit 71 * @ param reserved - skip 3 bits 72 * @ param channelPrivMode - channel priviledge mode 73 * 74 * @ returns IPMI completion code 75 **/ 76 RspType<> ipmiSetChannelAccess(Context::ptr ctx, uint4_t channel, 77 uint4_t reserved1, uint3_t accessMode, 78 bool usrAuth, bool msgAuth, bool alertDisabled, 79 uint2_t chanAccess, uint4_t channelPrivLimit, 80 uint2_t reserved2, uint2_t channelPrivMode) 81 { 82 const uint8_t chNum = 83 convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel); 84 85 if (!isValidChannel(chNum) || reserved1 != 0 || reserved2 != 0) 86 { 87 log<level::DEBUG>("Set channel access - Invalid field in request"); 88 return responseInvalidFieldRequest(); 89 } 90 91 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none) 92 { 93 log<level::DEBUG>("Set channel access - No support on channel"); 94 return responseInvalidFieldRequest(); 95 } 96 97 ChannelAccess chActData; 98 ChannelAccess chNVData; 99 uint8_t setActFlag = 0; 100 uint8_t setNVFlag = 0; 101 Cc compCode; 102 103 // cannot static cast directly from uint2_t to enum; must go via int 104 uint8_t channelAccessAction = static_cast<uint8_t>(chanAccess); 105 switch (static_cast<EChannelActionType>(channelAccessAction)) 106 { 107 case doNotSet: 108 break; 109 case nvData: 110 chNVData.accessMode = static_cast<uint8_t>(accessMode); 111 chNVData.userAuthDisabled = usrAuth; 112 chNVData.perMsgAuthDisabled = msgAuth; 113 chNVData.alertingDisabled = alertDisabled; 114 setNVFlag |= (setAccessMode | setUserAuthEnabled | 115 setMsgAuthEnabled | setAlertingEnabled); 116 break; 117 118 case activeData: 119 chActData.accessMode = static_cast<uint8_t>(accessMode); 120 chActData.userAuthDisabled = usrAuth; 121 chActData.perMsgAuthDisabled = msgAuth; 122 chActData.alertingDisabled = alertDisabled; 123 setActFlag |= (setAccessMode | setUserAuthEnabled | 124 setMsgAuthEnabled | setAlertingEnabled); 125 break; 126 127 case reserved: 128 default: 129 log<level::DEBUG>("Set channel access - Invalid access set mode"); 130 return responseInvalidFieldRequest(); 131 } 132 133 // cannot static cast directly from uint2_t to enum; must go via int 134 uint8_t channelPrivAction = static_cast<uint8_t>(channelPrivMode); 135 switch (static_cast<EChannelActionType>(channelPrivAction)) 136 { 137 case doNotSet: 138 break; 139 case nvData: 140 chNVData.privLimit = static_cast<uint8_t>(channelPrivLimit); 141 setNVFlag |= setPrivLimit; 142 break; 143 case activeData: 144 chActData.privLimit = static_cast<uint8_t>(channelPrivLimit); 145 146 setActFlag |= setPrivLimit; 147 break; 148 case reserved: 149 default: 150 log<level::DEBUG>("Set channel access - Invalid access priv mode"); 151 return responseInvalidFieldRequest(); 152 } 153 154 if (setNVFlag != 0) 155 { 156 compCode = setChannelAccessPersistData(chNum, chNVData, setNVFlag); 157 if (compCode != IPMI_CC_OK) 158 { 159 log<level::DEBUG>("Set channel access - Failed to set access data"); 160 return response(compCode); 161 } 162 } 163 164 if (setActFlag != 0) 165 { 166 compCode = setChannelAccessData(chNum, chActData, setActFlag); 167 if (compCode != IPMI_CC_OK) 168 { 169 log<level::DEBUG>("Set channel access - Failed to set access data"); 170 return response(compCode); 171 } 172 } 173 174 return responseSuccess(); 175 } 176 177 /** @brief implements the get channel access command 178 * @ param ctx - context pointer 179 * @ param channel - channel number 180 * @ param reserved1 - skip 4 bits 181 * @ param reserved2 - skip 6 bits 182 * @ param accessMode - get access mode 183 * 184 * @returns ipmi completion code plus response data 185 * - accessMode - get access mode 186 * - usrAuthDisabled - user level authentication status 187 * - msgAuthDisabled - message level authentication status 188 * - alertDisabled - alerting status 189 * - reserved - skip 2 bits 190 * - privLimit - channel privilege limit 191 * - reserved - skip 4 bits 192 * */ 193 ipmi ::RspType<uint3_t, // access mode, 194 bool, // user authentication status, 195 bool, // message authentication status, 196 bool, // alerting status, 197 uint2_t, // reserved, 198 199 uint4_t, // channel privilege, 200 uint4_t // reserved 201 > 202 ipmiGetChannelAccess(Context::ptr ctx, uint4_t channel, uint4_t reserved1, 203 uint6_t reserved2, uint2_t accessSetMode) 204 { 205 const uint8_t chNum = 206 convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel); 207 208 if (!isValidChannel(chNum) || reserved1 != 0 || reserved2 != 0) 209 { 210 log<level::DEBUG>("Get channel access - Invalid field in request"); 211 return responseInvalidFieldRequest(); 212 } 213 214 if ((accessSetMode == doNotSet) || (accessSetMode == reserved)) 215 { 216 log<level::DEBUG>("Get channel access - Invalid Access mode"); 217 return responseInvalidFieldRequest(); 218 } 219 220 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none) 221 { 222 log<level::DEBUG>("Get channel access - No support on channel"); 223 return response(IPMI_CC_ACTION_NOT_SUPPORTED_FOR_CHANNEL); 224 } 225 226 ChannelAccess chAccess; 227 228 Cc compCode; 229 230 if (accessSetMode == nvData) 231 { 232 compCode = getChannelAccessPersistData(chNum, chAccess); 233 } 234 else if (accessSetMode == activeData) 235 { 236 compCode = getChannelAccessData(chNum, chAccess); 237 } 238 239 if (compCode != IPMI_CC_OK) 240 { 241 return response(compCode); 242 } 243 244 constexpr uint2_t reservedOut1 = 0; 245 constexpr uint4_t reservedOut2 = 0; 246 247 return responseSuccess( 248 static_cast<uint3_t>(chAccess.accessMode), chAccess.userAuthDisabled, 249 chAccess.perMsgAuthDisabled, chAccess.alertingDisabled, reservedOut1, 250 static_cast<uint4_t>(chAccess.privLimit), reservedOut2); 251 } 252 253 /** @brief implements the get channel info command 254 * @ param ctx - context pointer 255 * @ param channel - channel number 256 * @ param reserved - skip 4 bits 257 * 258 * @returns ipmi completion code plus response data 259 * - chNum - the channel number for this request 260 * - mediumType - see Table 6-3, Channel Medium Type Numbers 261 * - protocolType - Table 6-2, Channel Protocol Type Numbers 262 * - activeSessionCount - number of active sessions 263 * - sessionType - channel support for sessions 264 * - vendorId - vendor for this channel protocol (IPMI - 7154) 265 * - auxChInfo - auxiliary info for channel 266 * */ 267 RspType<uint4_t, // chNum 268 uint4_t, // reserved 269 uint7_t, // mediumType 270 bool, // reserved 271 uint5_t, // protocolType 272 uint3_t, // reserved 273 uint6_t, // activeSessionCount 274 uint2_t, // sessionType 275 uint24_t, // Vendor IANA 276 uint16_t // aux info 277 > 278 ipmiGetChannelInfo(Context::ptr ctx, uint4_t channel, uint4_t reserved) 279 { 280 uint8_t chNum = 281 convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel); 282 if (!isValidChannel(chNum) || reserved) 283 { 284 log<level::DEBUG>("Get channel access - Invalid field in request"); 285 return responseInvalidFieldRequest(); 286 } 287 288 ChannelInfo chInfo; 289 Cc compCode = getChannelInfo(chNum, chInfo); 290 if (compCode != ccSuccess) 291 { 292 log<level::ERR>("Failed to get channel info", 293 entry("CHANNEL=%x", chNum), 294 entry("ERRNO=%x", compCode)); 295 return response(compCode); 296 } 297 298 constexpr uint4_t reserved1 = 0; 299 constexpr bool reserved2 = false; 300 constexpr uint3_t reserved3 = 0; 301 uint8_t mediumType = chInfo.mediumType; 302 uint8_t protocolType = chInfo.protocolType; 303 uint2_t sessionType = chInfo.sessionSupported; 304 uint6_t activeSessionCount = getChannelActiveSessions(chNum); 305 // IPMI Spec: The IPMI Enterprise Number is: 7154 (decimal) 306 constexpr uint24_t vendorId = 7154; 307 constexpr uint16_t auxChInfo = 0; 308 309 return responseSuccess(chNum, reserved1, mediumType, reserved2, 310 protocolType, reserved3, activeSessionCount, 311 sessionType, vendorId, auxChInfo); 312 } 313 314 ipmi_ret_t ipmiGetChannelPayloadSupport(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 315 ipmi_request_t request, 316 ipmi_response_t response, 317 ipmi_data_len_t data_len, 318 ipmi_context_t context) 319 { 320 const auto req = static_cast<GetChannelPayloadSupportReq*>(request); 321 size_t reqLength = *data_len; 322 323 *data_len = 0; 324 325 if (reqLength != sizeof(*req)) 326 { 327 log<level::DEBUG>("Get channel payload - Invalid Length"); 328 return IPMI_CC_REQ_DATA_LEN_INVALID; 329 } 330 331 uint8_t chNum = convertCurrentChannelNum(req->chNum); 332 if (!isValidChannel(chNum) || req->reserved != 0) 333 { 334 log<level::DEBUG>("Get channel payload - Invalid field in request"); 335 return IPMI_CC_INVALID_FIELD_REQUEST; 336 } 337 338 // Not supported on sessionless channels. 339 if (EChannelSessSupported::none == getChannelSessionSupport(chNum)) 340 { 341 log<level::DEBUG>("Get channel payload - Sessionless Channel"); 342 return IPMI_CC_INVALID_FIELD_REQUEST; 343 } 344 345 // Session support is available in active LAN channels. 346 if ((EChannelSessSupported::none != getChannelSessionSupport(chNum)) && 347 (!(doesDeviceExist(chNum)))) 348 { 349 log<level::DEBUG>("Get channel payload - Device not exist"); 350 return IPMI_CC_INVALID_FIELD_REQUEST; 351 } 352 353 auto resp = static_cast<GetChannelPayloadSupportResp*>(response); 354 355 std::fill(reinterpret_cast<uint8_t*>(resp), 356 reinterpret_cast<uint8_t*>(resp) + sizeof(*resp), 0); 357 358 // TODO: Hard coding for now. 359 // Mapping PayloadTypes to 'GetChannelPayloadSupportResp' fields: 360 // -------------------------------------------------------------- 361 // Mask all except least 3 significant bits to get a value in the range of 362 // 0-7. This value maps to the bit position of given payload type in 'resp' 363 // fields. 364 365 static constexpr uint8_t payloadByteMask = 0x07; 366 static constexpr uint8_t stdPayloadTypeIPMI = 367 1 << (static_cast<uint8_t>(PayloadType::IPMI) & payloadByteMask); 368 static constexpr uint8_t stdPayloadTypeSOL = 369 1 << (static_cast<uint8_t>(PayloadType::SOL) & payloadByteMask); 370 371 static constexpr uint8_t sessPayloadTypeOpenReq = 372 1 << (static_cast<uint8_t>(PayloadType::OPEN_SESSION_REQUEST) & 373 payloadByteMask); 374 static constexpr uint8_t sessPayloadTypeRAKP1 = 375 1 << (static_cast<uint8_t>(PayloadType::RAKP1) & payloadByteMask); 376 static constexpr uint8_t sessPayloadTypeRAKP3 = 377 1 << (static_cast<uint8_t>(PayloadType::RAKP3) & payloadByteMask); 378 379 resp->stdPayloadType[0] = stdPayloadTypeIPMI | stdPayloadTypeSOL; 380 // RMCP+ Open Session request, RAKP Message1 and RAKP Message3. 381 resp->sessSetupPayloadType[0] = 382 sessPayloadTypeOpenReq | sessPayloadTypeRAKP1 | sessPayloadTypeRAKP3; 383 384 *data_len = sizeof(*resp); 385 386 return IPMI_CC_OK; 387 } 388 389 void registerChannelFunctions() __attribute__((constructor)); 390 void registerChannelFunctions() 391 { 392 ipmiChannelInit(); 393 394 registerHandler(prioOpenBmcBase, netFnApp, app::cmdSetChannelAccess, 395 Privilege::Admin, ipmiSetChannelAccess); 396 397 registerHandler(prioOpenBmcBase, netFnApp, app::cmdGetChannelAccess, 398 Privilege::User, ipmiGetChannelAccess); 399 400 registerHandler(prioOpenBmcBase, netFnApp, app::cmdGetChannelInfoCommand, 401 Privilege::User, ipmiGetChannelInfo); 402 403 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CHANNEL_PAYLOAD_SUPPORT, 404 NULL, ipmiGetChannelPayloadSupport, PRIVILEGE_USER); 405 406 return; 407 } 408 409 } // namespace ipmi 410