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