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 <phosphor-logging/log.hpp> 23 #include <regex> 24 25 using namespace phosphor::logging; 26 27 namespace ipmi 28 { 29 30 /** @struct SetChannelAccessReq 31 * 32 * Structure for set channel access request command (refer spec sec 22.22) 33 */ 34 struct SetChannelAccessReq 35 { 36 #if BYTE_ORDER == LITTLE_ENDIAN 37 uint8_t chNum : 4; 38 uint8_t reserved_1 : 4; 39 uint8_t accessMode : 3; 40 uint8_t usrAuthDisabled : 1; 41 uint8_t msgAuthDisabled : 1; 42 uint8_t alertDisabled : 1; 43 uint8_t accessSetMode : 2; 44 uint8_t privLimit : 4; 45 uint8_t reserved_2 : 2; 46 uint8_t privSetMode : 2; 47 #endif 48 #if BYTE_ORDER == BIG_ENDIAN 49 uint8_t reserved_1 : 4; 50 uint8_t chNum : 4; 51 uint8_t accessSetMode : 2; 52 uint8_t alertDisabled : 1; 53 uint8_t msgAuthDisabled : 1; 54 uint8_t usrAuthDisabled : 1; 55 uint8_t accessMode : 3; 56 uint8_t privSetMode : 2; 57 uint8_t reserved_2 : 2; 58 uint8_t privLimit : 4; 59 #endif 60 61 } __attribute__((packed)); 62 63 /** @struct GetChannelAccessReq 64 * 65 * Structure for get channel access request command (refer spec sec 22.23) 66 */ 67 struct GetChannelAccessReq 68 { 69 #if BYTE_ORDER == LITTLE_ENDIAN 70 uint8_t chNum : 4; 71 uint8_t reserved_1 : 4; 72 uint8_t reserved_2 : 6; 73 uint8_t accessSetMode : 2; 74 #endif 75 #if BYTE_ORDER == BIG_ENDIAN 76 uint8_t reserved_1 : 4; 77 uint8_t chNum : 4; 78 uint8_t accessSetMode : 2; 79 uint8_t reserved_2 : 6; 80 #endif 81 } __attribute__((packed)); 82 83 /** @struct GetChannelAccessResp 84 * 85 * Structure for get channel access response command (refer spec sec 22.23) 86 */ 87 struct GetChannelAccessResp 88 { 89 #if BYTE_ORDER == LITTLE_ENDIAN 90 uint8_t accessMode : 3; 91 uint8_t usrAuthDisabled : 1; 92 uint8_t msgAuthDisabled : 1; 93 uint8_t alertDisabled : 1; 94 uint8_t reserved_1 : 2; 95 uint8_t privLimit : 4; 96 uint8_t reserved_2 : 4; 97 #endif 98 #if BYTE_ORDER == BIG_ENDIAN 99 uint8_t reserved_1 : 2; 100 uint8_t alertDisabled : 1; 101 uint8_t msgAuthDisabled : 1; 102 uint8_t usrAuthDisabled : 1; 103 uint8_t accessMode : 3; 104 uint8_t reserved_2 : 4; 105 uint8_t privLimit : 4; 106 #endif 107 } __attribute__((packed)); 108 109 /** @struct GetChannelInfoReq 110 * 111 * Structure for get channel info request command (refer spec sec 22.24) 112 */ 113 struct GetChannelInfoReq 114 { 115 #if BYTE_ORDER == LITTLE_ENDIAN 116 uint8_t chNum : 4; 117 uint8_t reserved_1 : 4; 118 #endif 119 #if BYTE_ORDER == BIG_ENDIAN 120 uint8_t reserved_1 : 4; 121 uint8_t chNum : 4; 122 #endif 123 } __attribute__((packed)); 124 125 /** @struct GetChannelInfoResp 126 * 127 * Structure for get channel info response command (refer spec sec 22.24) 128 */ 129 struct GetChannelInfoResp 130 { 131 #if BYTE_ORDER == LITTLE_ENDIAN 132 uint8_t chNum : 4; 133 uint8_t reserved_1 : 4; 134 uint8_t mediumType : 7; 135 uint8_t reserved_2 : 1; 136 uint8_t msgProtType : 5; 137 uint8_t reserved_3 : 3; 138 uint8_t actSessCount : 6; 139 uint8_t sessType : 2; 140 #endif 141 #if BYTE_ORDER == BIG_ENDIAN 142 uint8_t reserved_1 : 4; 143 uint8_t chNum : 4; 144 uint8_t reserved_2 : 1; 145 uint8_t mediumType : 7; 146 uint8_t reserved_3 : 3; 147 uint8_t msgProtType : 5; 148 uint8_t sessType : 2; 149 uint8_t actSessCount : 6; 150 #endif 151 uint8_t vendorId[3]; 152 uint8_t auxChInfo[2]; 153 } __attribute__((packed)); 154 155 /** @struct GetChannelPayloadSupportReq 156 * 157 * Structure for get channel payload support command request (refer spec 158 * sec 24.8) 159 */ 160 struct GetChannelPayloadSupportReq 161 { 162 #if BYTE_ORDER == LITTLE_ENDIAN 163 uint8_t chNum : 4; 164 uint8_t reserved : 4; 165 #endif 166 #if BYTE_ORDER == BIG_ENDIAN 167 uint8_t reserved : 4; 168 uint8_t chNum : 4; 169 #endif 170 } __attribute__((packed)); 171 172 /** @struct GetChannelPayloadSupportResp 173 * 174 * Structure for get channel payload support command response (refer spec 175 * sec 24.8) 176 */ 177 struct GetChannelPayloadSupportResp 178 { 179 uint8_t stdPayloadType[2]; 180 uint8_t sessSetupPayloadType[2]; 181 uint8_t OEMPayloadType[2]; 182 uint8_t reserved[2]; 183 } __attribute__((packed)); 184 185 ipmi_ret_t ipmiSetChannelAccess(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 186 ipmi_request_t request, 187 ipmi_response_t response, 188 ipmi_data_len_t data_len, 189 ipmi_context_t context) 190 { 191 const SetChannelAccessReq* req = static_cast<SetChannelAccessReq*>(request); 192 size_t reqLength = *data_len; 193 194 *data_len = 0; 195 196 if (reqLength != sizeof(*req)) 197 { 198 log<level::DEBUG>("Set channel access - Invalid Length"); 199 return IPMI_CC_REQ_DATA_LEN_INVALID; 200 } 201 202 uint8_t chNum = convertCurrentChannelNum(req->chNum); 203 if (!isValidChannel(chNum) || req->reserved_1 != 0 || req->reserved_2 != 0) 204 { 205 log<level::DEBUG>("Set channel access - Invalid field in request"); 206 return IPMI_CC_INVALID_FIELD_REQUEST; 207 } 208 209 if (EChannelSessSupported::none == getChannelSessionSupport(chNum)) 210 { 211 log<level::DEBUG>("Set channel access - No support on channel"); 212 return IPMI_CC_ACTION_NOT_SUPPORTED_FOR_CHANNEL; 213 } 214 215 ChannelAccess chActData; 216 ChannelAccess chNVData; 217 uint8_t setActFlag = 0; 218 uint8_t setNVFlag = 0; 219 ipmi_ret_t compCode = IPMI_CC_OK; 220 221 switch (req->accessSetMode) 222 { 223 case doNotSet: 224 // Do nothing 225 break; 226 case nvData: 227 chNVData.accessMode = req->accessMode; 228 chNVData.userAuthDisabled = req->usrAuthDisabled; 229 chNVData.perMsgAuthDisabled = req->msgAuthDisabled; 230 chNVData.alertingDisabled = req->alertDisabled; 231 setNVFlag |= (setAccessMode | setUserAuthEnabled | 232 setMsgAuthEnabled | setAlertingEnabled); 233 break; 234 case activeData: 235 chActData.accessMode = req->accessMode; 236 chActData.userAuthDisabled = req->usrAuthDisabled; 237 chActData.perMsgAuthDisabled = req->msgAuthDisabled; 238 chActData.alertingDisabled = req->alertDisabled; 239 setActFlag |= (setAccessMode | setUserAuthEnabled | 240 setMsgAuthEnabled | setAlertingEnabled); 241 break; 242 case reserved: 243 default: 244 log<level::DEBUG>("Set channel access - Invalid access set mode"); 245 return IPMI_CC_INVALID_FIELD_REQUEST; 246 } 247 248 switch (req->privSetMode) 249 { 250 case doNotSet: 251 // Do nothing 252 break; 253 case nvData: 254 chNVData.privLimit = req->privLimit; 255 setNVFlag |= setPrivLimit; 256 break; 257 case activeData: 258 chActData.privLimit = req->privLimit; 259 setActFlag |= setPrivLimit; 260 break; 261 case reserved: 262 default: 263 log<level::DEBUG>("Set channel access - Invalid access priv mode"); 264 return IPMI_CC_INVALID_FIELD_REQUEST; 265 } 266 267 if (setNVFlag != 0) 268 { 269 compCode = setChannelAccessPersistData(chNum, chNVData, setNVFlag); 270 if (compCode != IPMI_CC_OK) 271 { 272 log<level::DEBUG>("Set channel access - Failed to set access data"); 273 return compCode; 274 } 275 } 276 277 if (setActFlag != 0) 278 { 279 compCode = setChannelAccessData(chNum, chActData, setActFlag); 280 if (compCode != IPMI_CC_OK) 281 { 282 log<level::DEBUG>("Set channel access - Failed to set access data"); 283 return compCode; 284 } 285 } 286 287 return IPMI_CC_OK; 288 } 289 290 ipmi_ret_t ipmiGetChannelAccess(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 291 ipmi_request_t request, 292 ipmi_response_t response, 293 ipmi_data_len_t data_len, 294 ipmi_context_t context) 295 { 296 const GetChannelAccessReq* req = static_cast<GetChannelAccessReq*>(request); 297 size_t reqLength = *data_len; 298 299 *data_len = 0; 300 301 if (reqLength != sizeof(*req)) 302 { 303 log<level::DEBUG>("Get channel access - Invalid Length"); 304 return IPMI_CC_REQ_DATA_LEN_INVALID; 305 } 306 307 uint8_t chNum = convertCurrentChannelNum(req->chNum); 308 if (!isValidChannel(chNum) || req->reserved_1 != 0 || req->reserved_2 != 0) 309 { 310 log<level::DEBUG>("Get channel access - Invalid field in request"); 311 return IPMI_CC_INVALID_FIELD_REQUEST; 312 } 313 314 if ((req->accessSetMode == doNotSet) || (req->accessSetMode == reserved)) 315 { 316 log<level::DEBUG>("Get channel access - Invalid Access mode"); 317 return IPMI_CC_INVALID_FIELD_REQUEST; 318 } 319 320 if (EChannelSessSupported::none == getChannelSessionSupport(chNum)) 321 { 322 log<level::DEBUG>("Get channel access - No support on channel"); 323 return IPMI_CC_ACTION_NOT_SUPPORTED_FOR_CHANNEL; 324 } 325 326 GetChannelAccessResp* resp = static_cast<GetChannelAccessResp*>(response); 327 328 std::fill(reinterpret_cast<uint8_t*>(resp), 329 reinterpret_cast<uint8_t*>(resp) + sizeof(*resp), 0); 330 331 ChannelAccess chAccess; 332 ipmi_ret_t compCode = IPMI_CC_OK; 333 334 if (req->accessSetMode == nvData) 335 { 336 compCode = getChannelAccessPersistData(chNum, chAccess); 337 } 338 else if (req->accessSetMode == activeData) 339 { 340 compCode = getChannelAccessData(chNum, chAccess); 341 } 342 343 if (compCode != IPMI_CC_OK) 344 { 345 return compCode; 346 } 347 348 resp->accessMode = chAccess.accessMode; 349 resp->usrAuthDisabled = chAccess.userAuthDisabled; 350 resp->msgAuthDisabled = chAccess.perMsgAuthDisabled; 351 resp->alertDisabled = chAccess.alertingDisabled; 352 resp->privLimit = chAccess.privLimit; 353 354 *data_len = sizeof(*resp); 355 return IPMI_CC_OK; 356 } 357 358 ipmi_ret_t ipmiGetChannelInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 359 ipmi_request_t request, ipmi_response_t response, 360 ipmi_data_len_t data_len, ipmi_context_t context) 361 { 362 const GetChannelInfoReq* req = static_cast<GetChannelInfoReq*>(request); 363 size_t reqLength = *data_len; 364 365 *data_len = 0; 366 367 if (reqLength != sizeof(*req)) 368 { 369 log<level::DEBUG>("Get channel info - Invalid Length"); 370 return IPMI_CC_REQ_DATA_LEN_INVALID; 371 } 372 373 uint8_t chNum = convertCurrentChannelNum(req->chNum); 374 if (!isValidChannel(chNum) || req->reserved_1 != 0) 375 { 376 log<level::DEBUG>("Get channel info - Invalid field in request"); 377 return IPMI_CC_INVALID_FIELD_REQUEST; 378 } 379 380 // Check the existance of device for session-less channels. 381 if ((EChannelSessSupported::none != getChannelSessionSupport(chNum)) && 382 (!(doesDeviceExist(chNum)))) 383 { 384 log<level::DEBUG>("Get channel info - Device not exist"); 385 return IPMI_CC_PARM_OUT_OF_RANGE; 386 } 387 388 GetChannelInfoResp* resp = static_cast<GetChannelInfoResp*>(response); 389 390 std::fill(reinterpret_cast<uint8_t*>(resp), 391 reinterpret_cast<uint8_t*>(resp) + sizeof(*resp), 0); 392 393 ChannelInfo chInfo; 394 ipmi_ret_t compCode = getChannelInfo(chNum, chInfo); 395 if (compCode != IPMI_CC_OK) 396 { 397 return compCode; 398 } 399 400 resp->chNum = chNum; 401 resp->mediumType = chInfo.mediumType; 402 resp->msgProtType = chInfo.protocolType; 403 resp->actSessCount = getChannelActiveSessions(chNum); 404 resp->sessType = chInfo.sessionSupported; 405 406 // IPMI Spec: The IPMI Enterprise Number is: 7154 (decimal) 407 resp->vendorId[0] = 0xF2; 408 resp->vendorId[1] = 0x1B; 409 resp->vendorId[2] = 0x00; 410 411 // Auxiliary Channel info - byte 1:2 412 // TODO: For System Interface(0xF) and OEM channel types, this needs 413 // to be changed acoordingly. 414 // All other channel types, its reverved 415 resp->auxChInfo[0] = 0x00; 416 resp->auxChInfo[1] = 0x00; 417 418 *data_len = sizeof(*resp); 419 420 return IPMI_CC_OK; 421 } 422 423 ipmi_ret_t ipmiGetChannelPayloadSupport(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 424 ipmi_request_t request, 425 ipmi_response_t response, 426 ipmi_data_len_t data_len, 427 ipmi_context_t context) 428 { 429 const auto req = static_cast<GetChannelPayloadSupportReq*>(request); 430 size_t reqLength = *data_len; 431 432 *data_len = 0; 433 434 if (reqLength != sizeof(*req)) 435 { 436 log<level::DEBUG>("Get channel payload - Invalid Length"); 437 return IPMI_CC_REQ_DATA_LEN_INVALID; 438 } 439 440 uint8_t chNum = convertCurrentChannelNum(req->chNum); 441 if (!isValidChannel(chNum) || req->reserved != 0) 442 { 443 log<level::DEBUG>("Get channel payload - Invalid field in request"); 444 return IPMI_CC_INVALID_FIELD_REQUEST; 445 } 446 447 // Not supported on sessionless channels. 448 if (EChannelSessSupported::none == getChannelSessionSupport(chNum)) 449 { 450 log<level::DEBUG>("Get channel payload - Sessionless Channel"); 451 return IPMI_CC_INVALID_FIELD_REQUEST; 452 } 453 454 // Session support is available in active LAN channels. 455 if ((EChannelSessSupported::none != getChannelSessionSupport(chNum)) && 456 (!(doesDeviceExist(chNum)))) 457 { 458 log<level::DEBUG>("Get channel payload - Device not exist"); 459 return IPMI_CC_INVALID_FIELD_REQUEST; 460 } 461 462 auto resp = static_cast<GetChannelPayloadSupportResp*>(response); 463 464 std::fill(reinterpret_cast<uint8_t*>(resp), 465 reinterpret_cast<uint8_t*>(resp) + sizeof(*resp), 0); 466 467 // TODO: Hard coding for now. 468 // Mapping PayloadTypes to 'GetChannelPayloadSupportResp' fields: 469 // -------------------------------------------------------------- 470 // Mask all except least 3 significant bits to get a value in the range of 471 // 0-7. This value maps to the bit position of given payload type in 'resp' 472 // fields. 473 474 static constexpr uint8_t payloadByteMask = 0x07; 475 static constexpr uint8_t stdPayloadTypeIPMI = 476 1 << (static_cast<uint8_t>(PayloadType::IPMI) & payloadByteMask); 477 static constexpr uint8_t stdPayloadTypeSOL = 478 1 << (static_cast<uint8_t>(PayloadType::SOL) & payloadByteMask); 479 480 static constexpr uint8_t sessPayloadTypeOpenReq = 481 1 << (static_cast<uint8_t>(PayloadType::OPEN_SESSION_REQUEST) & 482 payloadByteMask); 483 static constexpr uint8_t sessPayloadTypeRAKP1 = 484 1 << (static_cast<uint8_t>(PayloadType::RAKP1) & payloadByteMask); 485 static constexpr uint8_t sessPayloadTypeRAKP3 = 486 1 << (static_cast<uint8_t>(PayloadType::RAKP3) & payloadByteMask); 487 488 resp->stdPayloadType[0] = stdPayloadTypeIPMI | stdPayloadTypeSOL; 489 // RMCP+ Open Session request, RAKP Message1 and RAKP Message3. 490 resp->sessSetupPayloadType[0] = 491 sessPayloadTypeOpenReq | sessPayloadTypeRAKP1 | sessPayloadTypeRAKP3; 492 493 *data_len = sizeof(*resp); 494 495 return IPMI_CC_OK; 496 } 497 498 void registerChannelFunctions() __attribute__((constructor)); 499 void registerChannelFunctions() 500 { 501 ipmiChannelInit(); 502 503 ipmi_register_callback(NETFUN_APP, IPMI_CMD_SET_CHANNEL_ACCESS, NULL, 504 ipmiSetChannelAccess, PRIVILEGE_ADMIN); 505 506 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CHANNEL_ACCESS, NULL, 507 ipmiGetChannelAccess, PRIVILEGE_USER); 508 509 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CHANNEL_INFO, NULL, 510 ipmiGetChannelInfo, PRIVILEGE_USER); 511 512 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CHANNEL_PAYLOAD_SUPPORT, 513 NULL, ipmiGetChannelPayloadSupport, PRIVILEGE_USER); 514 515 return; 516 } 517 518 } // namespace ipmi 519