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 "cable.hpp" 184d49ae65SPatrick Venture 194d49ae65SPatrick Venture #include "main.hpp" 204d49ae65SPatrick Venture 214d49ae65SPatrick Venture #include <cstdint> 22ce07ee0aSPatrick Venture #include <cstring> 234d49ae65SPatrick Venture #include <experimental/filesystem> 244d49ae65SPatrick Venture #include <fstream> 254d49ae65SPatrick Venture #include <sstream> 264d49ae65SPatrick Venture #include <string> 274d49ae65SPatrick Venture #include <system_error> 284d49ae65SPatrick Venture 294d49ae65SPatrick Venture namespace google 304d49ae65SPatrick Venture { 314d49ae65SPatrick Venture namespace ipmi 324d49ae65SPatrick Venture { 334d49ae65SPatrick Venture namespace fs = std::experimental::filesystem; 344d49ae65SPatrick Venture 354d49ae65SPatrick Venture struct CableRequest 364d49ae65SPatrick Venture { 374d49ae65SPatrick Venture uint8_t subcommand; 384d49ae65SPatrick Venture uint8_t if_name_len; 394d49ae65SPatrick Venture uint8_t if_name[0]; 404d49ae65SPatrick Venture } __attribute__((packed)); 414d49ae65SPatrick Venture 424d49ae65SPatrick Venture struct CableReply 434d49ae65SPatrick Venture { 444d49ae65SPatrick Venture uint8_t subcommand; 454d49ae65SPatrick Venture uint8_t value; 464d49ae65SPatrick Venture } __attribute__((packed)); 474d49ae65SPatrick Venture 484d49ae65SPatrick Venture ipmi_ret_t CableCheck(const uint8_t* reqBuf, uint8_t* replyBuf, size_t* dataLen) 494d49ae65SPatrick Venture { 504d49ae65SPatrick Venture // There is an IPMI LAN channel statistics command which could be used for 514d49ae65SPatrick Venture // this type of check, however, we're not able to wait for the OpenBMC 524d49ae65SPatrick Venture // implementation to stabilize related to the network management. 534d49ae65SPatrick Venture // 544d49ae65SPatrick Venture // There is a link status file, but it is "unknown" to start with... 554d49ae65SPatrick Venture // The path we're checking: /sys/class/net/eth1/statistics/rx_packets 564d49ae65SPatrick Venture 574d49ae65SPatrick Venture // This command is expecting: [0x00][len][if_name] 584d49ae65SPatrick Venture if ((*dataLen) < sizeof(struct CableRequest) + sizeof(uint8_t)) 594d49ae65SPatrick Venture { 60ce07ee0aSPatrick Venture std::fprintf(stderr, "Invalid command length: %u\n", 610dede335SPatrick Venture static_cast<uint32_t>(*dataLen)); 62*fff98617SPatrick Venture return IPMI_CC_REQ_DATA_LEN_INVALID; 634d49ae65SPatrick Venture } 644d49ae65SPatrick Venture 654d49ae65SPatrick Venture const auto request = 664d49ae65SPatrick Venture reinterpret_cast<const struct CableRequest*>(&reqBuf[0]); 674d49ae65SPatrick Venture 684d49ae65SPatrick Venture // Sanity check the object contents. 694d49ae65SPatrick Venture if (request->if_name_len == 0) 704d49ae65SPatrick Venture { 71ce07ee0aSPatrick Venture std::fprintf(stderr, "Invalid string length: %d\n", 72ce07ee0aSPatrick Venture request->if_name_len); 73*fff98617SPatrick Venture return IPMI_CC_REQ_DATA_LEN_INVALID; 744d49ae65SPatrick Venture } 754d49ae65SPatrick Venture 764d49ae65SPatrick Venture // Verify the request buffer contains the object and the string. 774d49ae65SPatrick Venture if ((*dataLen) < (sizeof(struct CableRequest) + request->if_name_len)) 784d49ae65SPatrick Venture { 79ce07ee0aSPatrick Venture std::fprintf(stderr, "*dataLen too small: %u\n", 800dede335SPatrick Venture static_cast<uint32_t>(*dataLen)); 81*fff98617SPatrick Venture return IPMI_CC_REQ_DATA_LEN_INVALID; 824d49ae65SPatrick Venture } 834d49ae65SPatrick Venture 844d49ae65SPatrick Venture // Maximum length one can specify, plus null terminator. 854d49ae65SPatrick Venture char nameBuf[256] = {}; 864d49ae65SPatrick Venture std::ostringstream opath; 874d49ae65SPatrick Venture 884d49ae65SPatrick Venture // Copy the string out of the request buffer. 89ce07ee0aSPatrick Venture std::memcpy(&nameBuf[0], request->if_name, request->if_name_len); 904d49ae65SPatrick Venture std::string name = nameBuf; 914d49ae65SPatrick Venture 924d49ae65SPatrick Venture // Minor sanity & security check (of course, I'm less certain if unicode 934d49ae65SPatrick Venture // comes into play here. 944d49ae65SPatrick Venture // 954d49ae65SPatrick Venture // Basically you can't easily inject ../ or /../ into the path below. 964d49ae65SPatrick Venture if (name.find("/") != std::string::npos) 974d49ae65SPatrick Venture { 98ce07ee0aSPatrick Venture std::fprintf(stderr, "Invalid or illegal name: '%s'\n", nameBuf); 99*fff98617SPatrick Venture return IPMI_CC_INVALID_FIELD_REQUEST; 1004d49ae65SPatrick Venture } 1014d49ae65SPatrick Venture 1024d49ae65SPatrick Venture opath << "/sys/class/net/" << name << "/statistics/rx_packets"; 1034d49ae65SPatrick Venture std::string path = opath.str(); 1044d49ae65SPatrick Venture 1054d49ae65SPatrick Venture std::error_code ec; 1064d49ae65SPatrick Venture if (!fs::exists(path, ec)) 1074d49ae65SPatrick Venture { 108ce07ee0aSPatrick Venture std::fprintf(stderr, "Path: '%s' doesn't exist.\n", path.c_str()); 109*fff98617SPatrick Venture return IPMI_CC_INVALID_FIELD_REQUEST; 1104d49ae65SPatrick Venture } 1114d49ae65SPatrick Venture // We're uninterested in the state of ec. 1124d49ae65SPatrick Venture 1134d49ae65SPatrick Venture // Read the file and check the result. 1144d49ae65SPatrick Venture int64_t count = 0; 1154d49ae65SPatrick Venture std::ifstream ifs; 1164d49ae65SPatrick Venture ifs.exceptions(std::ifstream::failbit); 1174d49ae65SPatrick Venture try 1184d49ae65SPatrick Venture { 1194d49ae65SPatrick Venture ifs.open(path); 1204d49ae65SPatrick Venture ifs >> count; 1214d49ae65SPatrick Venture } 1224d49ae65SPatrick Venture catch (std::ios_base::failure& fail) 1234d49ae65SPatrick Venture { 124*fff98617SPatrick Venture return IPMI_CC_UNSPECIFIED_ERROR; 1254d49ae65SPatrick Venture } 1264d49ae65SPatrick Venture 1274d49ae65SPatrick Venture struct CableReply reply; 1284d49ae65SPatrick Venture reply.subcommand = SysCableCheck; 1294d49ae65SPatrick Venture 1304d49ae65SPatrick Venture // If we have received packets then there is a cable present. 1314d49ae65SPatrick Venture reply.value = (count > 0) ? 1 : 0; 1324d49ae65SPatrick Venture 1334d49ae65SPatrick Venture // Return the subcommand and the result. 134ce07ee0aSPatrick Venture std::memcpy(&replyBuf[0], &reply, sizeof(struct CableReply)); 1354d49ae65SPatrick Venture (*dataLen) = sizeof(struct CableReply); 1364d49ae65SPatrick Venture 1374d49ae65SPatrick Venture return IPMI_CC_OK; 1384d49ae65SPatrick Venture } 1394d49ae65SPatrick Venture 1404d49ae65SPatrick Venture } // namespace ipmi 1414d49ae65SPatrick Venture } // namespace google 142