xref: /openbmc/google-ipmi-sys/handler.cpp (revision d2037c6a)
1 /*
2  * Copyright 2019 Google Inc.
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 "handler.hpp"
18 
19 #include "errors.hpp"
20 
21 #include <ipmid/api.h>
22 
23 #include <cstdio>
24 #include <filesystem>
25 #include <fstream>
26 #include <sstream>
27 #include <string>
28 #include <tuple>
29 
30 // The phosphor-host-ipmi daemon requires a configuration that maps
31 // the if_name to the IPMI LAN channel.  However, that doesn't strictly
32 // define which is meant to be used for NCSI.
33 #ifndef NCSI_IPMI_CHANNEL
34 #define NCSI_IPMI_CHANNEL 1
35 #endif
36 
37 #ifndef NCSI_IF_NAME
38 #define NCSI_IF_NAME eth0
39 #endif
40 
41 // To deal with receiving a string without quotes.
42 #define QUOTE(name) #name
43 #define STR(macro) QUOTE(macro)
44 #define NCSI_IF_NAME_STR STR(NCSI_IF_NAME)
45 
46 namespace google
47 {
48 namespace ipmi
49 {
50 namespace fs = std::filesystem;
51 
52 std::tuple<std::uint8_t, std::string> Handler::getEthDetails() const
53 {
54     return std::make_tuple(NCSI_IPMI_CHANNEL, NCSI_IF_NAME_STR);
55 }
56 
57 std::int64_t Handler::getRxPackets(const std::string& name) const
58 {
59     std::ostringstream opath;
60     opath << "/sys/class/net/" << name << "/statistics/rx_packets";
61     std::string path = opath.str();
62 
63     // Minor sanity & security check (of course, I'm less certain if unicode
64     // comes into play here.
65     //
66     // Basically you can't easily inject ../ or /../ into the path below.
67     if (name.find("/") != std::string::npos)
68     {
69         std::fprintf(stderr, "Invalid or illegal name: '%s'\n", name.c_str());
70         throw IpmiException(IPMI_CC_INVALID_FIELD_REQUEST);
71     }
72 
73     std::error_code ec;
74     if (!fs::exists(path, ec))
75     {
76         std::fprintf(stderr, "Path: '%s' doesn't exist.\n", path.c_str());
77         throw IpmiException(IPMI_CC_INVALID_FIELD_REQUEST);
78     }
79     // We're uninterested in the state of ec.
80 
81     int64_t count = 0;
82     std::ifstream ifs;
83     ifs.exceptions(std::ifstream::failbit);
84     try
85     {
86         ifs.open(path);
87         ifs >> count;
88     }
89     catch (std::ios_base::failure& fail)
90     {
91         throw IpmiException(IPMI_CC_UNSPECIFIED_ERROR);
92     }
93 
94     return count;
95 }
96 
97 Handler handlerImpl;
98 
99 } // namespace ipmi
100 } // namespace google
101