1 // Copyright 2021 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include "cpld.hpp" 16 17 #include "commands.hpp" 18 #include "errors.hpp" 19 #include "handler.hpp" 20 21 #include <cstring> 22 23 namespace google 24 { 25 namespace ipmi 26 { 27 28 struct CpldRequest 29 { 30 uint8_t subcommand; 31 uint8_t id; 32 } __attribute__((packed)); 33 34 struct CpldReply 35 { 36 uint8_t subcommand; 37 uint8_t major; 38 uint8_t minor; 39 uint8_t point; 40 uint8_t subpoint; 41 } __attribute__((packed)); 42 43 // 44 // Handle reading the cpld version from the tmpfs. 45 // 46 ipmi_ret_t cpldVersion(const uint8_t* reqBuf, uint8_t* replyBuf, 47 size_t* dataLen, const HandlerInterface* handler) 48 { 49 struct CpldRequest request; 50 51 if ((*dataLen) < sizeof(request)) 52 { 53 std::fprintf(stderr, "Invalid command length: %u\n", 54 static_cast<uint32_t>(*dataLen)); 55 return IPMI_CC_REQ_DATA_LEN_INVALID; 56 } 57 58 // reqBuf[0] is the subcommand. 59 // reqBuf[1] is the CPLD id. "/run/cpld{id}.version" is what we read. 60 // Verified that this cast actually returns the value 255 and not something 61 // negative in the case where reqBuf[1] is 0xff. However, it looks weird 62 // since I would expect int(uint8(0xff)) to be -1. So, just cast it 63 // unsigned. we're casting to an int width to avoid it thinking it's a 64 // letter, because it does that. 65 std::memcpy(&request, &reqBuf[0], sizeof(request)); 66 67 try 68 { 69 auto values = 70 handler->getCpldVersion(static_cast<unsigned int>(request.id)); 71 72 // Truncate if the version is too high (documented). 73 struct CpldReply reply; 74 reply.subcommand = SysCpldVersion; 75 reply.major = std::get<0>(values); 76 reply.minor = std::get<1>(values); 77 reply.point = std::get<2>(values); 78 reply.subpoint = std::get<3>(values); 79 80 std::memcpy(&replyBuf[0], &reply, sizeof(reply)); 81 (*dataLen) = sizeof(reply); 82 return IPMI_CC_OK; 83 } 84 catch (const IpmiException& e) 85 { 86 return e.getIpmiError(); 87 } 88 } 89 90 } // namespace ipmi 91 } // namespace google 92