14d49ae65SPatrick Venture /* 24d49ae65SPatrick Venture * Copyright 2018 Google Inc. 34d49ae65SPatrick Venture * 44d49ae65SPatrick Venture * Licensed under the Apache License, Version 2.0 (the "License"); 54d49ae65SPatrick Venture * you may not use this file except in compliance with the License. 64d49ae65SPatrick Venture * You may obtain a copy of the License at 74d49ae65SPatrick Venture * 84d49ae65SPatrick Venture * http://www.apache.org/licenses/LICENSE-2.0 94d49ae65SPatrick Venture * 104d49ae65SPatrick Venture * Unless required by applicable law or agreed to in writing, software 114d49ae65SPatrick Venture * distributed under the License is distributed on an "AS IS" BASIS, 124d49ae65SPatrick Venture * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 134d49ae65SPatrick Venture * See the License for the specific language governing permissions and 144d49ae65SPatrick Venture * limitations under the License. 154d49ae65SPatrick Venture */ 164d49ae65SPatrick Venture 174d49ae65SPatrick Venture #include "cpld.hpp" 184d49ae65SPatrick Venture 194d49ae65SPatrick Venture #include "main.hpp" 204d49ae65SPatrick Venture 21ce07ee0aSPatrick Venture #include <cstring> 224d49ae65SPatrick Venture #include <experimental/filesystem> 234d49ae65SPatrick Venture #include <fstream> 244d49ae65SPatrick Venture #include <sstream> 254d49ae65SPatrick Venture 264d49ae65SPatrick Venture namespace google 274d49ae65SPatrick Venture { 284d49ae65SPatrick Venture namespace ipmi 294d49ae65SPatrick Venture { 304d49ae65SPatrick Venture namespace fs = std::experimental::filesystem; 314d49ae65SPatrick Venture 324d49ae65SPatrick Venture struct CpldRequest 334d49ae65SPatrick Venture { 344d49ae65SPatrick Venture uint8_t subcommand; 354d49ae65SPatrick Venture uint8_t id; 364d49ae65SPatrick Venture } __attribute__((packed)); 374d49ae65SPatrick Venture 384d49ae65SPatrick Venture struct CpldReply 394d49ae65SPatrick Venture { 404d49ae65SPatrick Venture uint8_t subcommand; 414d49ae65SPatrick Venture uint8_t major; 424d49ae65SPatrick Venture uint8_t minor; 434d49ae65SPatrick Venture uint8_t point; 444d49ae65SPatrick Venture uint8_t subpoint; 454d49ae65SPatrick Venture } __attribute__((packed)); 464d49ae65SPatrick Venture 474d49ae65SPatrick Venture // 484d49ae65SPatrick Venture // Handle reading the cpld version from the tmpfs. 494d49ae65SPatrick Venture // 504d49ae65SPatrick Venture ipmi_ret_t CpldVersion(const uint8_t* reqBuf, uint8_t* replyBuf, 514d49ae65SPatrick Venture size_t* dataLen) 524d49ae65SPatrick Venture { 53*acd5423aSPatrick Venture struct CpldRequest request; 54*acd5423aSPatrick Venture 55*acd5423aSPatrick Venture if ((*dataLen) < sizeof(request)) 564d49ae65SPatrick Venture { 57ce07ee0aSPatrick Venture std::fprintf(stderr, "Invalid command length: %u\n", 580dede335SPatrick Venture static_cast<uint32_t>(*dataLen)); 594d49ae65SPatrick Venture return IPMI_CC_INVALID; 604d49ae65SPatrick Venture } 614d49ae65SPatrick Venture 624d49ae65SPatrick Venture // reqBuf[0] is the subcommand. 634d49ae65SPatrick Venture // reqBuf[1] is the CPLD id. "/run/cpld{id}.version" is what we read. 644d49ae65SPatrick Venture // Verified that this cast actually returns the value 255 and not something 654d49ae65SPatrick Venture // negative in the case where reqBuf[1] is 0xff. However, it looks weird 664d49ae65SPatrick Venture // since I would expect int(uint8(0xff)) to be -1. So, just cast it 674d49ae65SPatrick Venture // unsigned. we're casting to an int width to avoid it thinking it's a 684d49ae65SPatrick Venture // letter, because it does that. 69*acd5423aSPatrick Venture std::memcpy(&request, &reqBuf[0], sizeof(request)); 704d49ae65SPatrick Venture 714d49ae65SPatrick Venture std::ostringstream opath; 72*acd5423aSPatrick Venture opath << "/run/cpld" << static_cast<unsigned int>(request.id) << ".version"; 734d49ae65SPatrick Venture // Check for file 744d49ae65SPatrick Venture 754d49ae65SPatrick Venture std::error_code ec; 764d49ae65SPatrick Venture if (!fs::exists(opath.str(), ec)) 774d49ae65SPatrick Venture { 78ce07ee0aSPatrick Venture std::fprintf(stderr, "Path: '%s' doesn't exist.\n", 79ce07ee0aSPatrick Venture opath.str().c_str()); 804d49ae65SPatrick Venture return IPMI_CC_INVALID; 814d49ae65SPatrick Venture } 824d49ae65SPatrick Venture // We're uninterested in the state of ec. 834d49ae65SPatrick Venture 844d49ae65SPatrick Venture // If file exists, read. 854d49ae65SPatrick Venture std::ifstream ifs; 864d49ae65SPatrick Venture ifs.exceptions(std::ifstream::failbit); 874d49ae65SPatrick Venture std::string value; 884d49ae65SPatrick Venture try 894d49ae65SPatrick Venture { 904d49ae65SPatrick Venture ifs.open(opath.str()); 914d49ae65SPatrick Venture ifs >> value; 924d49ae65SPatrick Venture } 934d49ae65SPatrick Venture catch (std::ios_base::failure& fail) 944d49ae65SPatrick Venture { 954d49ae65SPatrick Venture return IPMI_CC_INVALID; 964d49ae65SPatrick Venture } 974d49ae65SPatrick Venture 984d49ae65SPatrick Venture // If value parses as expected, return version. 994d49ae65SPatrick Venture int major = 0; 1004d49ae65SPatrick Venture int minor = 0; 1014d49ae65SPatrick Venture int point = 0; 1024d49ae65SPatrick Venture int subpoint = 0; 1034d49ae65SPatrick Venture 1044d49ae65SPatrick Venture int num_fields = 1054d49ae65SPatrick Venture sscanf(value.c_str(), "%d.%d.%d.%d", &major, &minor, &point, &subpoint); 1064d49ae65SPatrick Venture if (num_fields == 0) 1074d49ae65SPatrick Venture { 108ce07ee0aSPatrick Venture std::fprintf(stderr, "Invalid version.\n"); 1094d49ae65SPatrick Venture return IPMI_CC_INVALID; 1104d49ae65SPatrick Venture } 1114d49ae65SPatrick Venture 1124d49ae65SPatrick Venture // Truncate if the version is too high (documented). 1134d49ae65SPatrick Venture struct CpldReply reply; 1144d49ae65SPatrick Venture reply.subcommand = SysCpldVersion; 1154d49ae65SPatrick Venture reply.major = static_cast<uint8_t>(major); 1164d49ae65SPatrick Venture reply.minor = static_cast<uint8_t>(minor); 1174d49ae65SPatrick Venture reply.point = static_cast<uint8_t>(point); 1184d49ae65SPatrick Venture reply.subpoint = static_cast<uint8_t>(subpoint); 1194d49ae65SPatrick Venture 120*acd5423aSPatrick Venture std::memcpy(&replyBuf[0], &reply, sizeof(reply)); 121*acd5423aSPatrick Venture (*dataLen) = sizeof(reply); 1224d49ae65SPatrick Venture 1234d49ae65SPatrick Venture return IPMI_CC_OK; 1244d49ae65SPatrick Venture } 1254d49ae65SPatrick Venture 1264d49ae65SPatrick Venture } // namespace ipmi 1274d49ae65SPatrick Venture } // namespace google 128