1*d7be555eSGeorge Liu /*
2*d7be555eSGeorge Liu // Copyright (c) 2018 Intel Corporation
3*d7be555eSGeorge Liu //
4*d7be555eSGeorge Liu // Licensed under the Apache License, Version 2.0 (the "License");
5*d7be555eSGeorge Liu // you may not use this file except in compliance with the License.
6*d7be555eSGeorge Liu // You may obtain a copy of the License at
7*d7be555eSGeorge Liu //
8*d7be555eSGeorge Liu //      http://www.apache.org/licenses/LICENSE-2.0
9*d7be555eSGeorge Liu //
10*d7be555eSGeorge Liu // Unless required by applicable law or agreed to in writing, software
11*d7be555eSGeorge Liu // distributed under the License is distributed on an "AS IS" BASIS,
12*d7be555eSGeorge Liu // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*d7be555eSGeorge Liu // See the License for the specific language governing permissions and
14*d7be555eSGeorge Liu // limitations under the License.
15*d7be555eSGeorge Liu */
16*d7be555eSGeorge Liu 
17*d7be555eSGeorge Liu #include "ChassisIntrusionSensor.hpp"
18*d7be555eSGeorge Liu #include "Utils.hpp"
19*d7be555eSGeorge Liu 
20*d7be555eSGeorge Liu #include <boost/asio/error.hpp>
21*d7be555eSGeorge Liu #include <boost/asio/io_context.hpp>
22*d7be555eSGeorge Liu #include <boost/asio/steady_timer.hpp>
23*d7be555eSGeorge Liu #include <boost/container/flat_map.hpp>
24*d7be555eSGeorge Liu #include <phosphor-logging/lg2.hpp>
25*d7be555eSGeorge Liu #include <sdbusplus/asio/connection.hpp>
26*d7be555eSGeorge Liu #include <sdbusplus/asio/object_server.hpp>
27*d7be555eSGeorge Liu #include <sdbusplus/bus.hpp>
28*d7be555eSGeorge Liu #include <sdbusplus/bus/match.hpp>
29*d7be555eSGeorge Liu #include <sdbusplus/message.hpp>
30*d7be555eSGeorge Liu 
31*d7be555eSGeorge Liu #include <array>
32*d7be555eSGeorge Liu #include <charconv>
33*d7be555eSGeorge Liu #include <chrono>
34*d7be555eSGeorge Liu #include <cstdint>
35*d7be555eSGeorge Liu #include <ctime>
36*d7be555eSGeorge Liu #include <exception>
37*d7be555eSGeorge Liu #include <filesystem>
38*d7be555eSGeorge Liu #include <fstream>
39*d7be555eSGeorge Liu #include <functional>
40*d7be555eSGeorge Liu #include <iostream>
41*d7be555eSGeorge Liu #include <map>
42*d7be555eSGeorge Liu #include <memory>
43*d7be555eSGeorge Liu #include <string>
44*d7be555eSGeorge Liu #include <system_error>
45*d7be555eSGeorge Liu #include <utility>
46*d7be555eSGeorge Liu #include <variant>
47*d7be555eSGeorge Liu #include <vector>
48*d7be555eSGeorge Liu 
49*d7be555eSGeorge Liu static constexpr bool debug = false;
50*d7be555eSGeorge Liu 
51*d7be555eSGeorge Liu static constexpr const char* sensorType = "ChassisIntrusionSensor";
52*d7be555eSGeorge Liu static constexpr const char* nicType = "NIC";
53*d7be555eSGeorge Liu static constexpr auto nicTypes{std::to_array<const char*>({nicType})};
54*d7be555eSGeorge Liu 
55*d7be555eSGeorge Liu static const std::map<std::string, std::string> compatibleHwmonNames = {
56*d7be555eSGeorge Liu     {"Aspeed2600_Hwmon", "intrusion0_alarm"}
57*d7be555eSGeorge Liu     // Add compatible strings here for new hwmon intrusion detection
58*d7be555eSGeorge Liu     // drivers that have different hwmon names but would also like to
59*d7be555eSGeorge Liu     // use the available Hwmon class.
60*d7be555eSGeorge Liu };
61*d7be555eSGeorge Liu 
createSensorsFromConfig(boost::asio::io_context & io,sdbusplus::asio::object_server & objServer,const std::shared_ptr<sdbusplus::asio::connection> & dbusConnection,std::shared_ptr<ChassisIntrusionSensor> & pSensor)62*d7be555eSGeorge Liu static void createSensorsFromConfig(
63*d7be555eSGeorge Liu     boost::asio::io_context& io, sdbusplus::asio::object_server& objServer,
64*d7be555eSGeorge Liu     const std::shared_ptr<sdbusplus::asio::connection>& dbusConnection,
65*d7be555eSGeorge Liu     std::shared_ptr<ChassisIntrusionSensor>& pSensor)
66*d7be555eSGeorge Liu {
67*d7be555eSGeorge Liu     // find matched configuration according to sensor type
68*d7be555eSGeorge Liu     ManagedObjectType sensorConfigurations;
69*d7be555eSGeorge Liu     bool useCache = false;
70*d7be555eSGeorge Liu 
71*d7be555eSGeorge Liu     if (!getSensorConfiguration(sensorType, dbusConnection,
72*d7be555eSGeorge Liu                                 sensorConfigurations, useCache))
73*d7be555eSGeorge Liu     {
74*d7be555eSGeorge Liu         std::cerr << "error communicating to entity manager\n";
75*d7be555eSGeorge Liu         return;
76*d7be555eSGeorge Liu     }
77*d7be555eSGeorge Liu 
78*d7be555eSGeorge Liu     const SensorData* sensorData = nullptr;
79*d7be555eSGeorge Liu     const std::pair<std::string, SensorBaseConfigMap>* baseConfiguration =
80*d7be555eSGeorge Liu         nullptr;
81*d7be555eSGeorge Liu 
82*d7be555eSGeorge Liu     for (const auto& [path, cfgData] : sensorConfigurations)
83*d7be555eSGeorge Liu     {
84*d7be555eSGeorge Liu         baseConfiguration = nullptr;
85*d7be555eSGeorge Liu         sensorData = &cfgData;
86*d7be555eSGeorge Liu 
87*d7be555eSGeorge Liu         // match sensor type
88*d7be555eSGeorge Liu         auto sensorBase = sensorData->find(configInterfaceName(sensorType));
89*d7be555eSGeorge Liu         if (sensorBase == sensorData->end())
90*d7be555eSGeorge Liu         {
91*d7be555eSGeorge Liu             std::cerr << "error finding base configuration \n";
92*d7be555eSGeorge Liu             continue;
93*d7be555eSGeorge Liu         }
94*d7be555eSGeorge Liu 
95*d7be555eSGeorge Liu         baseConfiguration = &(*sensorBase);
96*d7be555eSGeorge Liu 
97*d7be555eSGeorge Liu         // Rearm defaults to "Automatic" mode
98*d7be555eSGeorge Liu         bool autoRearm = true;
99*d7be555eSGeorge Liu         auto findRearm = baseConfiguration->second.find("Rearm");
100*d7be555eSGeorge Liu         if (findRearm != baseConfiguration->second.end())
101*d7be555eSGeorge Liu         {
102*d7be555eSGeorge Liu             std::string rearmStr = std::get<std::string>(findRearm->second);
103*d7be555eSGeorge Liu             if (rearmStr != "Automatic" && rearmStr != "Manual")
104*d7be555eSGeorge Liu             {
105*d7be555eSGeorge Liu                 std::cerr << "Wrong input for Rearm parameter\n";
106*d7be555eSGeorge Liu                 continue;
107*d7be555eSGeorge Liu             }
108*d7be555eSGeorge Liu             autoRearm = (rearmStr == "Automatic");
109*d7be555eSGeorge Liu         }
110*d7be555eSGeorge Liu 
111*d7be555eSGeorge Liu         // judge class, "Gpio", "Hwmon" or "I2C"
112*d7be555eSGeorge Liu         auto findClass = baseConfiguration->second.find("Class");
113*d7be555eSGeorge Liu         if (findClass != baseConfiguration->second.end())
114*d7be555eSGeorge Liu         {
115*d7be555eSGeorge Liu             auto classString = std::get<std::string>(findClass->second);
116*d7be555eSGeorge Liu             if (classString == "Gpio")
117*d7be555eSGeorge Liu             {
118*d7be555eSGeorge Liu                 auto findGpioPolarity =
119*d7be555eSGeorge Liu                     baseConfiguration->second.find("GpioPolarity");
120*d7be555eSGeorge Liu 
121*d7be555eSGeorge Liu                 if (findGpioPolarity == baseConfiguration->second.end())
122*d7be555eSGeorge Liu                 {
123*d7be555eSGeorge Liu                     std::cerr
124*d7be555eSGeorge Liu                         << "error finding gpio polarity in configuration \n";
125*d7be555eSGeorge Liu                     continue;
126*d7be555eSGeorge Liu                 }
127*d7be555eSGeorge Liu 
128*d7be555eSGeorge Liu                 try
129*d7be555eSGeorge Liu                 {
130*d7be555eSGeorge Liu                     bool gpioInverted =
131*d7be555eSGeorge Liu                         (std::get<std::string>(findGpioPolarity->second) ==
132*d7be555eSGeorge Liu                          "Low");
133*d7be555eSGeorge Liu                     pSensor = std::make_shared<ChassisIntrusionGpioSensor>(
134*d7be555eSGeorge Liu                         autoRearm, io, objServer, gpioInverted);
135*d7be555eSGeorge Liu                     pSensor->start();
136*d7be555eSGeorge Liu                     if (debug)
137*d7be555eSGeorge Liu                     {
138*d7be555eSGeorge Liu                         std::cout
139*d7be555eSGeorge Liu                             << "find chassis intrusion sensor polarity inverted "
140*d7be555eSGeorge Liu                                "flag is "
141*d7be555eSGeorge Liu                             << gpioInverted << "\n";
142*d7be555eSGeorge Liu                     }
143*d7be555eSGeorge Liu                     return;
144*d7be555eSGeorge Liu                 }
145*d7be555eSGeorge Liu                 catch (const std::bad_variant_access& e)
146*d7be555eSGeorge Liu                 {
147*d7be555eSGeorge Liu                     std::cerr << "invalid value for gpio info in config. \n";
148*d7be555eSGeorge Liu                     continue;
149*d7be555eSGeorge Liu                 }
150*d7be555eSGeorge Liu                 catch (const std::exception& e)
151*d7be555eSGeorge Liu                 {
152*d7be555eSGeorge Liu                     std::cerr << e.what() << std::endl;
153*d7be555eSGeorge Liu                     continue;
154*d7be555eSGeorge Liu                 }
155*d7be555eSGeorge Liu             }
156*d7be555eSGeorge Liu             // If class string contains Hwmon string
157*d7be555eSGeorge Liu             else if (classString.find("Hwmon") != std::string::npos)
158*d7be555eSGeorge Liu             {
159*d7be555eSGeorge Liu                 std::string hwmonName;
160*d7be555eSGeorge Liu                 std::map<std::string, std::string>::const_iterator
161*d7be555eSGeorge Liu                     compatIterator = compatibleHwmonNames.find(classString);
162*d7be555eSGeorge Liu 
163*d7be555eSGeorge Liu                 if (compatIterator == compatibleHwmonNames.end())
164*d7be555eSGeorge Liu                 {
165*d7be555eSGeorge Liu                     std::cerr << "Hwmon Class string is not supported\n";
166*d7be555eSGeorge Liu                     continue;
167*d7be555eSGeorge Liu                 }
168*d7be555eSGeorge Liu 
169*d7be555eSGeorge Liu                 hwmonName = compatIterator->second;
170*d7be555eSGeorge Liu 
171*d7be555eSGeorge Liu                 try
172*d7be555eSGeorge Liu                 {
173*d7be555eSGeorge Liu                     pSensor = std::make_shared<ChassisIntrusionHwmonSensor>(
174*d7be555eSGeorge Liu                         autoRearm, io, objServer, hwmonName);
175*d7be555eSGeorge Liu                     pSensor->start();
176*d7be555eSGeorge Liu                     return;
177*d7be555eSGeorge Liu                 }
178*d7be555eSGeorge Liu                 catch (const std::exception& e)
179*d7be555eSGeorge Liu                 {
180*d7be555eSGeorge Liu                     std::cerr << e.what() << std::endl;
181*d7be555eSGeorge Liu                     continue;
182*d7be555eSGeorge Liu                 }
183*d7be555eSGeorge Liu             }
184*d7be555eSGeorge Liu             else
185*d7be555eSGeorge Liu             {
186*d7be555eSGeorge Liu                 auto findBus = baseConfiguration->second.find("Bus");
187*d7be555eSGeorge Liu                 auto findAddress = baseConfiguration->second.find("Address");
188*d7be555eSGeorge Liu                 if (findBus == baseConfiguration->second.end() ||
189*d7be555eSGeorge Liu                     findAddress == baseConfiguration->second.end())
190*d7be555eSGeorge Liu                 {
191*d7be555eSGeorge Liu                     std::cerr
192*d7be555eSGeorge Liu                         << "error finding bus or address in configuration \n";
193*d7be555eSGeorge Liu                     continue;
194*d7be555eSGeorge Liu                 }
195*d7be555eSGeorge Liu                 try
196*d7be555eSGeorge Liu                 {
197*d7be555eSGeorge Liu                     int busId = std::get<uint64_t>(findBus->second);
198*d7be555eSGeorge Liu                     int slaveAddr = std::get<uint64_t>(findAddress->second);
199*d7be555eSGeorge Liu                     pSensor = std::make_shared<ChassisIntrusionPchSensor>(
200*d7be555eSGeorge Liu                         autoRearm, io, objServer, busId, slaveAddr);
201*d7be555eSGeorge Liu                     pSensor->start();
202*d7be555eSGeorge Liu                     if (debug)
203*d7be555eSGeorge Liu                     {
204*d7be555eSGeorge Liu                         std::cout
205*d7be555eSGeorge Liu                             << "find matched bus " << busId
206*d7be555eSGeorge Liu                             << ", matched slave addr " << slaveAddr << "\n";
207*d7be555eSGeorge Liu                     }
208*d7be555eSGeorge Liu                     return;
209*d7be555eSGeorge Liu                 }
210*d7be555eSGeorge Liu                 catch (const std::bad_variant_access& e)
211*d7be555eSGeorge Liu                 {
212*d7be555eSGeorge Liu                     std::cerr
213*d7be555eSGeorge Liu                         << "invalid value for bus or address in config. \n";
214*d7be555eSGeorge Liu                     continue;
215*d7be555eSGeorge Liu                 }
216*d7be555eSGeorge Liu                 catch (const std::exception& e)
217*d7be555eSGeorge Liu                 {
218*d7be555eSGeorge Liu                     std::cerr << e.what() << std::endl;
219*d7be555eSGeorge Liu                     continue;
220*d7be555eSGeorge Liu                 }
221*d7be555eSGeorge Liu             }
222*d7be555eSGeorge Liu         }
223*d7be555eSGeorge Liu     }
224*d7be555eSGeorge Liu 
225*d7be555eSGeorge Liu     std::cerr << " Can't find matched I2C, GPIO or Hwmon configuration\n";
226*d7be555eSGeorge Liu 
227*d7be555eSGeorge Liu     // Make sure nothing runs when there's failure in configuration for the
228*d7be555eSGeorge Liu     // sensor after rescan
229*d7be555eSGeorge Liu     if (pSensor)
230*d7be555eSGeorge Liu     {
231*d7be555eSGeorge Liu         std::cerr << " Reset the occupied sensor pointer\n";
232*d7be555eSGeorge Liu         pSensor = nullptr;
233*d7be555eSGeorge Liu     }
234*d7be555eSGeorge Liu }
235*d7be555eSGeorge Liu 
236*d7be555eSGeorge Liu static constexpr bool debugLanLeash = false;
237*d7be555eSGeorge Liu boost::container::flat_map<int, bool> lanStatusMap;
238*d7be555eSGeorge Liu boost::container::flat_map<int, std::string> lanInfoMap;
239*d7be555eSGeorge Liu boost::container::flat_map<std::string, int> pathSuffixMap;
240*d7be555eSGeorge Liu 
getNicNameInfo(const std::shared_ptr<sdbusplus::asio::connection> & dbusConnection)241*d7be555eSGeorge Liu static void getNicNameInfo(
242*d7be555eSGeorge Liu     const std::shared_ptr<sdbusplus::asio::connection>& dbusConnection)
243*d7be555eSGeorge Liu {
244*d7be555eSGeorge Liu     auto getter = std::make_shared<GetSensorConfiguration>(
245*d7be555eSGeorge Liu         dbusConnection, [](const ManagedObjectType& sensorConfigurations) {
246*d7be555eSGeorge Liu             // Get NIC name and save to map
247*d7be555eSGeorge Liu             lanInfoMap.clear();
248*d7be555eSGeorge Liu             for (const auto& [path, cfgData] : sensorConfigurations)
249*d7be555eSGeorge Liu             {
250*d7be555eSGeorge Liu                 const std::pair<std::string, SensorBaseConfigMap>*
251*d7be555eSGeorge Liu                     baseConfiguration = nullptr;
252*d7be555eSGeorge Liu 
253*d7be555eSGeorge Liu                 // find base configuration
254*d7be555eSGeorge Liu                 auto sensorBase = cfgData.find(configInterfaceName(nicType));
255*d7be555eSGeorge Liu                 if (sensorBase == cfgData.end())
256*d7be555eSGeorge Liu                 {
257*d7be555eSGeorge Liu                     continue;
258*d7be555eSGeorge Liu                 }
259*d7be555eSGeorge Liu                 baseConfiguration = &(*sensorBase);
260*d7be555eSGeorge Liu 
261*d7be555eSGeorge Liu                 auto findEthIndex = baseConfiguration->second.find("EthIndex");
262*d7be555eSGeorge Liu                 auto findName = baseConfiguration->second.find("Name");
263*d7be555eSGeorge Liu 
264*d7be555eSGeorge Liu                 if (findEthIndex != baseConfiguration->second.end() &&
265*d7be555eSGeorge Liu                     findName != baseConfiguration->second.end())
266*d7be555eSGeorge Liu                 {
267*d7be555eSGeorge Liu                     const auto* pEthIndex =
268*d7be555eSGeorge Liu                         std::get_if<uint64_t>(&findEthIndex->second);
269*d7be555eSGeorge Liu                     const auto* pName =
270*d7be555eSGeorge Liu                         std::get_if<std::string>(&findName->second);
271*d7be555eSGeorge Liu                     if (pEthIndex != nullptr && pName != nullptr)
272*d7be555eSGeorge Liu                     {
273*d7be555eSGeorge Liu                         lanInfoMap[*pEthIndex] = *pName;
274*d7be555eSGeorge Liu                         if (debugLanLeash)
275*d7be555eSGeorge Liu                         {
276*d7be555eSGeorge Liu                             std::cout << "find name of eth" << *pEthIndex
277*d7be555eSGeorge Liu                                       << " is " << *pName << "\n";
278*d7be555eSGeorge Liu                         }
279*d7be555eSGeorge Liu                     }
280*d7be555eSGeorge Liu                 }
281*d7be555eSGeorge Liu             }
282*d7be555eSGeorge Liu 
283*d7be555eSGeorge Liu             if (lanInfoMap.empty())
284*d7be555eSGeorge Liu             {
285*d7be555eSGeorge Liu                 std::cerr << "can't find matched NIC name. \n";
286*d7be555eSGeorge Liu             }
287*d7be555eSGeorge Liu         });
288*d7be555eSGeorge Liu 
289*d7be555eSGeorge Liu     getter->getConfiguration(
290*d7be555eSGeorge Liu         std::vector<std::string>{nicTypes.begin(), nicTypes.end()});
291*d7be555eSGeorge Liu }
292*d7be555eSGeorge Liu 
processLanStatusChange(sdbusplus::message_t & message)293*d7be555eSGeorge Liu static void processLanStatusChange(sdbusplus::message_t& message)
294*d7be555eSGeorge Liu {
295*d7be555eSGeorge Liu     const std::string& pathName = message.get_path();
296*d7be555eSGeorge Liu     std::string interfaceName;
297*d7be555eSGeorge Liu     SensorBaseConfigMap properties;
298*d7be555eSGeorge Liu     message.read(interfaceName, properties);
299*d7be555eSGeorge Liu 
300*d7be555eSGeorge Liu     auto findStateProperty = properties.find("OperationalState");
301*d7be555eSGeorge Liu     if (findStateProperty == properties.end())
302*d7be555eSGeorge Liu     {
303*d7be555eSGeorge Liu         return;
304*d7be555eSGeorge Liu     }
305*d7be555eSGeorge Liu     std::string* pState =
306*d7be555eSGeorge Liu         std::get_if<std::string>(&(findStateProperty->second));
307*d7be555eSGeorge Liu     if (pState == nullptr)
308*d7be555eSGeorge Liu     {
309*d7be555eSGeorge Liu         std::cerr << "invalid OperationalState \n";
310*d7be555eSGeorge Liu         return;
311*d7be555eSGeorge Liu     }
312*d7be555eSGeorge Liu 
313*d7be555eSGeorge Liu     bool newLanConnected = (*pState == "routable" || *pState == "carrier" ||
314*d7be555eSGeorge Liu                             *pState == "degraded");
315*d7be555eSGeorge Liu 
316*d7be555eSGeorge Liu     // get ethNum from path. /org/freedesktop/network1/link/_32 for eth0
317*d7be555eSGeorge Liu     size_t pos = pathName.find("/_");
318*d7be555eSGeorge Liu     if (pos == std::string::npos || pathName.length() <= pos + 2)
319*d7be555eSGeorge Liu     {
320*d7be555eSGeorge Liu         std::cerr << "unexpected path name " << pathName << "\n";
321*d7be555eSGeorge Liu         return;
322*d7be555eSGeorge Liu     }
323*d7be555eSGeorge Liu     std::string suffixStr = pathName.substr(pos + 2);
324*d7be555eSGeorge Liu 
325*d7be555eSGeorge Liu     auto findEthNum = pathSuffixMap.find(suffixStr);
326*d7be555eSGeorge Liu     if (findEthNum == pathSuffixMap.end())
327*d7be555eSGeorge Liu     {
328*d7be555eSGeorge Liu         std::cerr << "unexpected eth for suffixStr " << suffixStr << "\n";
329*d7be555eSGeorge Liu         return;
330*d7be555eSGeorge Liu     }
331*d7be555eSGeorge Liu     int ethNum = findEthNum->second;
332*d7be555eSGeorge Liu 
333*d7be555eSGeorge Liu     // get lan status from map
334*d7be555eSGeorge Liu     auto findLanStatus = lanStatusMap.find(ethNum);
335*d7be555eSGeorge Liu     if (findLanStatus == lanStatusMap.end())
336*d7be555eSGeorge Liu     {
337*d7be555eSGeorge Liu         std::cerr << "unexpected eth " << ethNum << " in lanStatusMap \n";
338*d7be555eSGeorge Liu         return;
339*d7be555eSGeorge Liu     }
340*d7be555eSGeorge Liu     bool oldLanConnected = findLanStatus->second;
341*d7be555eSGeorge Liu 
342*d7be555eSGeorge Liu     // get lan info from map
343*d7be555eSGeorge Liu     std::string lanInfo;
344*d7be555eSGeorge Liu     if (!lanInfoMap.empty())
345*d7be555eSGeorge Liu     {
346*d7be555eSGeorge Liu         auto findLanInfo = lanInfoMap.find(ethNum);
347*d7be555eSGeorge Liu         if (findLanInfo == lanInfoMap.end())
348*d7be555eSGeorge Liu         {
349*d7be555eSGeorge Liu             std::cerr << "unexpected eth " << ethNum << " in lanInfoMap \n";
350*d7be555eSGeorge Liu         }
351*d7be555eSGeorge Liu         else
352*d7be555eSGeorge Liu         {
353*d7be555eSGeorge Liu             lanInfo = "(" + findLanInfo->second + ")";
354*d7be555eSGeorge Liu         }
355*d7be555eSGeorge Liu     }
356*d7be555eSGeorge Liu 
357*d7be555eSGeorge Liu     if (debugLanLeash)
358*d7be555eSGeorge Liu     {
359*d7be555eSGeorge Liu         std::cout << "ethNum = " << ethNum << ", state = " << *pState
360*d7be555eSGeorge Liu                   << ", oldLanConnected = "
361*d7be555eSGeorge Liu                   << (oldLanConnected ? "true" : "false")
362*d7be555eSGeorge Liu                   << ", newLanConnected = "
363*d7be555eSGeorge Liu                   << (newLanConnected ? "true" : "false") << "\n";
364*d7be555eSGeorge Liu     }
365*d7be555eSGeorge Liu 
366*d7be555eSGeorge Liu     if (oldLanConnected != newLanConnected)
367*d7be555eSGeorge Liu     {
368*d7be555eSGeorge Liu         std::string strEthNum = "eth" + std::to_string(ethNum) + lanInfo;
369*d7be555eSGeorge Liu         const auto* strState = newLanConnected ? "connected" : "lost";
370*d7be555eSGeorge Liu         const auto* strMsgId =
371*d7be555eSGeorge Liu             newLanConnected ? "OpenBMC.0.1.LanRegained" : "OpenBMC.0.1.LanLost";
372*d7be555eSGeorge Liu 
373*d7be555eSGeorge Liu         lg2::info("{ETHDEV} LAN leash {STATE}", "ETHDEV", strEthNum, "STATE",
374*d7be555eSGeorge Liu                   strState, "REDFISH_MESSAGE_ID", strMsgId,
375*d7be555eSGeorge Liu                   "REDFISH_MESSAGE_ARGS", strEthNum);
376*d7be555eSGeorge Liu 
377*d7be555eSGeorge Liu         lanStatusMap[ethNum] = newLanConnected;
378*d7be555eSGeorge Liu     }
379*d7be555eSGeorge Liu }
380*d7be555eSGeorge Liu 
381*d7be555eSGeorge Liu /** @brief Initialize the lan status.
382*d7be555eSGeorge Liu  *
383*d7be555eSGeorge Liu  * @return true on success and false on failure
384*d7be555eSGeorge Liu  */
initializeLanStatus(const std::shared_ptr<sdbusplus::asio::connection> & conn)385*d7be555eSGeorge Liu static bool initializeLanStatus(
386*d7be555eSGeorge Liu     const std::shared_ptr<sdbusplus::asio::connection>& conn)
387*d7be555eSGeorge Liu {
388*d7be555eSGeorge Liu     // init lan port name from configuration
389*d7be555eSGeorge Liu     getNicNameInfo(conn);
390*d7be555eSGeorge Liu 
391*d7be555eSGeorge Liu     // get eth info from sysfs
392*d7be555eSGeorge Liu     std::vector<fs::path> files;
393*d7be555eSGeorge Liu     if (!findFiles(fs::path("/sys/class/net/"), R"(eth\d+/ifindex)", files))
394*d7be555eSGeorge Liu     {
395*d7be555eSGeorge Liu         std::cerr << "No eth in system\n";
396*d7be555eSGeorge Liu         return false;
397*d7be555eSGeorge Liu     }
398*d7be555eSGeorge Liu 
399*d7be555eSGeorge Liu     // iterate through all found eth files, and save ifindex
400*d7be555eSGeorge Liu     for (const fs::path& fileName : files)
401*d7be555eSGeorge Liu     {
402*d7be555eSGeorge Liu         if (debugLanLeash)
403*d7be555eSGeorge Liu         {
404*d7be555eSGeorge Liu             std::cout << "Reading " << fileName << "\n";
405*d7be555eSGeorge Liu         }
406*d7be555eSGeorge Liu         std::ifstream sysFile(fileName);
407*d7be555eSGeorge Liu         if (!sysFile.good())
408*d7be555eSGeorge Liu         {
409*d7be555eSGeorge Liu             std::cerr << "Failure reading " << fileName << "\n";
410*d7be555eSGeorge Liu             continue;
411*d7be555eSGeorge Liu         }
412*d7be555eSGeorge Liu         std::string line;
413*d7be555eSGeorge Liu         getline(sysFile, line);
414*d7be555eSGeorge Liu         const uint8_t ifindex = std::stoi(line);
415*d7be555eSGeorge Liu         // pathSuffix is ASCII of ifindex
416*d7be555eSGeorge Liu         const std::string& pathSuffix = std::to_string(ifindex + 30);
417*d7be555eSGeorge Liu 
418*d7be555eSGeorge Liu         // extract ethNum
419*d7be555eSGeorge Liu         const std::string& fileStr = fileName.string();
420*d7be555eSGeorge Liu         const int pos = fileStr.find("eth");
421*d7be555eSGeorge Liu         const std::string& ethNumStr = fileStr.substr(pos + 3);
422*d7be555eSGeorge Liu         int ethNum = 0;
423*d7be555eSGeorge Liu         std::from_chars_result r = std::from_chars(
424*d7be555eSGeorge Liu             ethNumStr.data(), ethNumStr.data() + ethNumStr.size(), ethNum);
425*d7be555eSGeorge Liu         if (r.ec != std::errc())
426*d7be555eSGeorge Liu         {
427*d7be555eSGeorge Liu             std::cerr << "invalid ethNum string: " << ethNumStr << "\n";
428*d7be555eSGeorge Liu             continue;
429*d7be555eSGeorge Liu         }
430*d7be555eSGeorge Liu 
431*d7be555eSGeorge Liu         // save pathSuffix
432*d7be555eSGeorge Liu         pathSuffixMap[pathSuffix] = ethNum;
433*d7be555eSGeorge Liu         if (debugLanLeash)
434*d7be555eSGeorge Liu         {
435*d7be555eSGeorge Liu             std::cout << "ethNum = " << std::to_string(ethNum) << ", ifindex = "
436*d7be555eSGeorge Liu                       << line << ", pathSuffix = " << pathSuffix << "\n";
437*d7be555eSGeorge Liu         }
438*d7be555eSGeorge Liu 
439*d7be555eSGeorge Liu         // init lan connected status from networkd
440*d7be555eSGeorge Liu         conn->async_method_call(
441*d7be555eSGeorge Liu             [ethNum](boost::system::error_code ec,
442*d7be555eSGeorge Liu                      const std::variant<std::string>& property) {
443*d7be555eSGeorge Liu                 lanStatusMap[ethNum] = false;
444*d7be555eSGeorge Liu                 if (ec)
445*d7be555eSGeorge Liu                 {
446*d7be555eSGeorge Liu                     std::cerr
447*d7be555eSGeorge Liu                         << "Error reading init status of eth" << ethNum << "\n";
448*d7be555eSGeorge Liu                     return;
449*d7be555eSGeorge Liu                 }
450*d7be555eSGeorge Liu                 const std::string* pState = std::get_if<std::string>(&property);
451*d7be555eSGeorge Liu                 if (pState == nullptr)
452*d7be555eSGeorge Liu                 {
453*d7be555eSGeorge Liu                     std::cerr << "Unable to read lan status value\n";
454*d7be555eSGeorge Liu                     return;
455*d7be555eSGeorge Liu                 }
456*d7be555eSGeorge Liu                 bool isLanConnected =
457*d7be555eSGeorge Liu                     (*pState == "routable" || *pState == "carrier" ||
458*d7be555eSGeorge Liu                      *pState == "degraded");
459*d7be555eSGeorge Liu                 if (debugLanLeash)
460*d7be555eSGeorge Liu                 {
461*d7be555eSGeorge Liu                     std::cout << "ethNum = " << std::to_string(ethNum)
462*d7be555eSGeorge Liu                               << ", init LAN status = "
463*d7be555eSGeorge Liu                               << (isLanConnected ? "true" : "false") << "\n";
464*d7be555eSGeorge Liu                 }
465*d7be555eSGeorge Liu                 lanStatusMap[ethNum] = isLanConnected;
466*d7be555eSGeorge Liu             },
467*d7be555eSGeorge Liu             "org.freedesktop.network1",
468*d7be555eSGeorge Liu             "/org/freedesktop/network1/link/_" + pathSuffix,
469*d7be555eSGeorge Liu             "org.freedesktop.DBus.Properties", "Get",
470*d7be555eSGeorge Liu             "org.freedesktop.network1.Link", "OperationalState");
471*d7be555eSGeorge Liu     }
472*d7be555eSGeorge Liu     return true;
473*d7be555eSGeorge Liu }
474*d7be555eSGeorge Liu 
main()475*d7be555eSGeorge Liu int main()
476*d7be555eSGeorge Liu {
477*d7be555eSGeorge Liu     std::shared_ptr<ChassisIntrusionSensor> intrusionSensor;
478*d7be555eSGeorge Liu 
479*d7be555eSGeorge Liu     // setup connection to dbus
480*d7be555eSGeorge Liu     boost::asio::io_context io;
481*d7be555eSGeorge Liu     auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
482*d7be555eSGeorge Liu 
483*d7be555eSGeorge Liu     // setup object server, define interface
484*d7be555eSGeorge Liu     systemBus->request_name("xyz.openbmc_project.IntrusionSensor");
485*d7be555eSGeorge Liu 
486*d7be555eSGeorge Liu     sdbusplus::asio::object_server objServer(systemBus, true);
487*d7be555eSGeorge Liu 
488*d7be555eSGeorge Liu     objServer.add_manager("/xyz/openbmc_project/Chassis");
489*d7be555eSGeorge Liu 
490*d7be555eSGeorge Liu     createSensorsFromConfig(io, objServer, systemBus, intrusionSensor);
491*d7be555eSGeorge Liu 
492*d7be555eSGeorge Liu     // callback to handle configuration change
493*d7be555eSGeorge Liu     boost::asio::steady_timer filterTimer(io);
494*d7be555eSGeorge Liu     std::function<void(sdbusplus::message_t&)> eventHandler =
495*d7be555eSGeorge Liu         [&](sdbusplus::message_t& message) {
496*d7be555eSGeorge Liu             if (message.is_method_error())
497*d7be555eSGeorge Liu             {
498*d7be555eSGeorge Liu                 std::cerr << "callback method error\n";
499*d7be555eSGeorge Liu                 return;
500*d7be555eSGeorge Liu             }
501*d7be555eSGeorge Liu             // this implicitly cancels the timer
502*d7be555eSGeorge Liu             filterTimer.expires_after(std::chrono::seconds(1));
503*d7be555eSGeorge Liu             filterTimer.async_wait([&](const boost::system::error_code& ec) {
504*d7be555eSGeorge Liu                 if (ec == boost::asio::error::operation_aborted)
505*d7be555eSGeorge Liu                 {
506*d7be555eSGeorge Liu                     // timer was cancelled
507*d7be555eSGeorge Liu                     return;
508*d7be555eSGeorge Liu                 }
509*d7be555eSGeorge Liu                 std::cout << "rescan due to configuration change \n";
510*d7be555eSGeorge Liu                 createSensorsFromConfig(io, objServer, systemBus,
511*d7be555eSGeorge Liu                                         intrusionSensor);
512*d7be555eSGeorge Liu             });
513*d7be555eSGeorge Liu         };
514*d7be555eSGeorge Liu 
515*d7be555eSGeorge Liu     std::vector<std::unique_ptr<sdbusplus::bus::match_t>> matches =
516*d7be555eSGeorge Liu         setupPropertiesChangedMatches(
517*d7be555eSGeorge Liu             *systemBus, std::to_array<const char*>({sensorType}), eventHandler);
518*d7be555eSGeorge Liu 
519*d7be555eSGeorge Liu     if (initializeLanStatus(systemBus))
520*d7be555eSGeorge Liu     {
521*d7be555eSGeorge Liu         // add match to monitor lan status change
522*d7be555eSGeorge Liu         sdbusplus::bus::match_t lanStatusMatch(
523*d7be555eSGeorge Liu             static_cast<sdbusplus::bus_t&>(*systemBus),
524*d7be555eSGeorge Liu             "type='signal', member='PropertiesChanged',"
525*d7be555eSGeorge Liu             "arg0namespace='org.freedesktop.network1.Link'",
526*d7be555eSGeorge Liu             [](sdbusplus::message_t& msg) { processLanStatusChange(msg); });
527*d7be555eSGeorge Liu 
528*d7be555eSGeorge Liu         // add match to monitor entity manager signal about nic name config
529*d7be555eSGeorge Liu         // change
530*d7be555eSGeorge Liu         sdbusplus::bus::match_t lanConfigMatch(
531*d7be555eSGeorge Liu             static_cast<sdbusplus::bus_t&>(*systemBus),
532*d7be555eSGeorge Liu             "type='signal', member='PropertiesChanged',path_namespace='" +
533*d7be555eSGeorge Liu                 std::string(inventoryPath) + "',arg0namespace='" +
534*d7be555eSGeorge Liu                 configInterfaceName(nicType) + "'",
535*d7be555eSGeorge Liu             [&systemBus](sdbusplus::message_t& msg) {
536*d7be555eSGeorge Liu                 if (msg.is_method_error())
537*d7be555eSGeorge Liu                 {
538*d7be555eSGeorge Liu                     std::cerr << "callback method error\n";
539*d7be555eSGeorge Liu                     return;
540*d7be555eSGeorge Liu                 }
541*d7be555eSGeorge Liu                 getNicNameInfo(systemBus);
542*d7be555eSGeorge Liu             });
543*d7be555eSGeorge Liu     }
544*d7be555eSGeorge Liu 
545*d7be555eSGeorge Liu     io.run();
546*d7be555eSGeorge Liu 
547*d7be555eSGeorge Liu     return 0;
548*d7be555eSGeorge Liu }
549