xref: /openbmc/google-ipmi-sys/cable.cpp (revision 5d789734)
1 /*
2  * Copyright 2018 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 "cable.hpp"
18 
19 #include "commands.hpp"
20 #include "errors.hpp"
21 #include "handler.hpp"
22 
23 #include <cstdint>
24 #include <cstring>
25 #include <string>
26 
27 namespace google
28 {
29 namespace ipmi
30 {
31 
32 struct CableRequest
33 {
34     uint8_t subcommand;
35     uint8_t ifNameLength;
36 } __attribute__((packed));
37 
38 ipmi_ret_t cableCheck(const uint8_t* reqBuf, uint8_t* replyBuf, size_t* dataLen,
39                       const HandlerInterface* handler)
40 {
41     // There is an IPMI LAN channel statistics command which could be used for
42     // this type of check, however, we're not able to wait for the OpenBMC
43     // implementation to stabilize related to the network management.
44     //
45     // There is a link status file, but it is "unknown" to start with...
46     // The path we're checking: /sys/class/net/eth1/statistics/rx_packets
47 
48     // This command is expecting: [0x00][len][ifName]
49     if ((*dataLen) < sizeof(struct CableRequest) + sizeof(uint8_t))
50     {
51         std::fprintf(stderr, "Invalid command length: %u\n",
52                      static_cast<uint32_t>(*dataLen));
53         return IPMI_CC_REQ_DATA_LEN_INVALID;
54     }
55 
56     const auto request =
57         reinterpret_cast<const struct CableRequest*>(&reqBuf[0]);
58 
59     // Sanity check the object contents.
60     if (request->ifNameLength == 0)
61     {
62         std::fprintf(stderr, "Invalid string length: %d\n",
63                      request->ifNameLength);
64         return IPMI_CC_REQ_DATA_LEN_INVALID;
65     }
66 
67     // Verify the request buffer contains the object and the string.
68     if ((*dataLen) < (sizeof(struct CableRequest) + request->ifNameLength))
69     {
70         std::fprintf(stderr, "*dataLen too small: %u\n",
71                      static_cast<uint32_t>(*dataLen));
72         return IPMI_CC_REQ_DATA_LEN_INVALID;
73     }
74 
75     // Maximum length one can specify, plus null terminator.
76     char nameBuf[256] = {};
77     // Copy the string out of the request buffer.
78     std::memcpy(&nameBuf[0], request + 1, request->ifNameLength);
79     std::string name = nameBuf;
80     int64_t count;
81 
82     try
83     {
84         count = handler->getRxPackets(name);
85     }
86     catch (const IpmiException& e)
87     {
88         return e.getIpmiError();
89     }
90 
91     struct CableReply reply;
92     reply.subcommand = SysCableCheck;
93 
94     // If we have received packets then there is a cable present.
95     reply.value = (count > 0) ? 1 : 0;
96 
97     // Return the subcommand and the result.
98     std::memcpy(&replyBuf[0], &reply, sizeof(struct CableReply));
99     (*dataLen) = sizeof(struct CableReply);
100 
101     return IPMI_CC_OK;
102 }
103 
104 } // namespace ipmi
105 } // namespace google
106