1 #include <bitset>
2 #include <phosphor-logging/elog-errors.hpp>
3 #include <phosphor-logging/log.hpp>
4 #include "xyz/openbmc_project/Common/error.hpp"
5 #include "types.hpp"
6 #include "sensordatahandler.hpp"
7 
8 namespace ipmi
9 {
10 namespace sensor
11 {
12 
13 using namespace phosphor::logging;
14 using InternalFailure =
15     sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
16 
17 static constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
18 static constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
19 static constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
20 
21 /** @brief get the D-Bus service and service path
22  *  @param[in] bus - The Dbus bus object
23  *  @param[in] interface - interface to the service
24  *  @param[in] path - interested path in the list of objects
25  *  @return pair of service path and service
26  */
27 ServicePath getServiceAndPath(sdbusplus::bus::bus& bus,
28                               const std::string& interface,
29                               const std::string& path)
30 {
31     auto depth = 0;
32     auto mapperCall = bus.new_method_call(MAPPER_BUSNAME,
33                                           MAPPER_PATH,
34                                           MAPPER_INTERFACE,
35                                           "GetSubTree");
36     mapperCall.append("/");
37     mapperCall.append(depth);
38     mapperCall.append(std::vector<Interface>({interface}));
39 
40     auto mapperResponseMsg = bus.call(mapperCall);
41     if (mapperResponseMsg.is_method_error())
42     {
43         log<level::ERR>("Mapper GetSubTree failed",
44                         entry("PATH=%s", path),
45                         entry("INTERFACE=%s", interface));
46         elog<InternalFailure>();
47     }
48 
49     MapperResponseType mapperResponse;
50     mapperResponseMsg.read(mapperResponse);
51     if (mapperResponse.empty())
52     {
53         log<level::ERR>("Invalid mapper response",
54                         entry("PATH=%s", path),
55                         entry("INTERFACE=%s", interface));
56         elog<InternalFailure>();
57     }
58 
59     if (path.empty())
60     {
61         //Get the first one if the path is not in list.
62         return std::make_pair(mapperResponse.begin()->first,
63                               mapperResponse.begin()->second.begin()->first);
64     }
65     const auto& iter = mapperResponse.find(path);
66     if (iter == mapperResponse.end())
67     {
68         log<level::ERR>("Coudn't find d-bus path",
69                         entry("PATH=%s", path),
70                         entry("INTERFACE=%s", interface));
71         elog<InternalFailure>();
72     }
73     return std::make_pair(iter->first, iter->second.begin()->first);
74 }
75 
76 AssertionSet getAssertionSet(const SetSensorReadingReq& cmdData)
77 {
78     Assertion assertionStates =
79         (static_cast<Assertion>(cmdData.assertOffset8_14)) << 8 |
80         cmdData.assertOffset0_7;
81     Deassertion deassertionStates =
82         (static_cast<Deassertion>(cmdData.deassertOffset8_14)) << 8 |
83         cmdData.deassertOffset0_7;
84     return std::make_pair(assertionStates, deassertionStates);
85 }
86 
87 ipmi_ret_t updateToDbus(IpmiUpdateData& msg)
88 {
89     sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
90     try
91     {
92         auto serviceResponseMsg = bus.call(msg);
93         if (serviceResponseMsg.is_method_error())
94         {
95             log<level::ERR>("Error in D-Bus call");
96             return IPMI_CC_UNSPECIFIED_ERROR;
97         }
98     }
99     catch (InternalFailure& e)
100     {
101         commit<InternalFailure>();
102         return IPMI_CC_UNSPECIFIED_ERROR;
103     }
104     return IPMI_CC_OK;
105 }
106 
107 namespace set
108 {
109 
110 IpmiUpdateData makeDbusMsg(const std::string& updateInterface,
111                            const std::string& sensorPath,
112                            const std::string& command,
113                            const std::string& sensorInterface)
114 {
115     sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
116     using namespace std::string_literals;
117 
118     std::string dbusService;
119     std::string dbusPath;
120 
121     std::tie(dbusPath, dbusService) = getServiceAndPath(bus,
122                                       sensorInterface,
123                                       sensorPath);
124     return bus.new_method_call(dbusService.c_str(),
125                                dbusPath.c_str(),
126                                updateInterface.c_str(),
127                                command.c_str());
128 }
129 
130 ipmi_ret_t appendDiscreteSignalData(IpmiUpdateData& msg,
131                                     const DbusInterfaceMap& interfaceMap,
132                                     uint8_t data)
133 {
134     const auto& interface = interfaceMap.begin();
135     msg.append(interface->first);
136     for (const auto& property : interface->second)
137     {
138         msg.append(property.first);
139         const auto& iter = property.second.find(data);
140         if (iter == property.second.end())
141         {
142             log<level::ERR>("Invalid event data");
143             return IPMI_CC_PARM_OUT_OF_RANGE;
144         }
145         msg.append(iter->second.assert);
146     }
147     return IPMI_CC_OK;
148 }
149 
150 ipmi_ret_t appendReadingData(IpmiUpdateData& msg,
151                              const DbusInterfaceMap& interfaceMap,
152                              const Value &data)
153 {
154     const auto& interface = interfaceMap.begin();
155     msg.append(interface->first);
156     for (const auto& property : interface->second)
157     {
158         msg.append(property.first);
159         msg.append(data);
160     }
161     return IPMI_CC_OK;
162 }
163 
164 ipmi_ret_t appendAssertion(IpmiUpdateData& msg,
165                            const DbusInterfaceMap& interfaceMap,
166                            const std::string& sensorPath,
167                            const SetSensorReadingReq& cmdData)
168 {
169     std::bitset<16> assertionSet(getAssertionSet(cmdData).first);
170     std::bitset<16> deassertionSet(getAssertionSet(cmdData).second);
171 
172     const auto& interface = interfaceMap.begin();
173     msg.append(interface->first);
174     for (const auto& property : interface->second)
175     {
176         msg.append(property.first);
177         for (const auto& value : property.second)
178         {
179             if (assertionSet.test(value.first))
180             {
181                 msg.append(value.second.assert);
182             }
183             if (deassertionSet.test(value.first))
184             {
185                 msg.append(value.second.deassert);
186             }
187         }
188     }
189     return IPMI_CC_OK;
190 }
191 }//namespace set
192 
193 namespace notify
194 {
195 
196 IpmiUpdateData makeDbusMsg(const std::string& updateInterface,
197                            const std::string& sensorPath,
198                            const std::string& command,
199                            const std::string& sensorInterface)
200 {
201     sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
202     using namespace std::string_literals;
203 
204     std::string dbusService;
205     std::string dbusPath;
206 
207     std::tie(dbusPath, dbusService) = getServiceAndPath(bus,
208                                       updateInterface);
209 
210     return bus.new_method_call(dbusService.c_str(),
211                                dbusPath.c_str(),
212                                updateInterface.c_str(),
213                                command.c_str());
214 }
215 
216 ipmi_ret_t appendAssertion(IpmiUpdateData& msg,
217                            const DbusInterfaceMap& interfaceMap,
218                            const std::string& sensorPath,
219                            const SetSensorReadingReq& cmdData)
220 {
221     std::bitset<16> assertionSet(getAssertionSet(cmdData).first);
222     std::bitset<16> deassertionSet(getAssertionSet(cmdData).second);
223     ipmi::sensor::ObjectMap objects;
224     ipmi::sensor::InterfaceMap interfaces;
225     for (const auto& interface : interfaceMap)
226     {
227         for (const auto& property : interface.second)
228         {
229             ipmi::sensor::PropertyMap props;
230             bool valid = false;
231             for (const auto& value : property.second)
232             {
233                 if (assertionSet.test(value.first))
234                 {
235                     props.emplace(property.first, value.second.assert);
236                     valid = true;
237                 }
238                 else if (deassertionSet.test(value.first))
239                 {
240                     props.emplace(property.first, value.second.deassert);
241                     valid = true;
242                 }
243             }
244             if (valid)
245             {
246                 interfaces.emplace(interface.first, std::move(props));
247             }
248         }
249     }
250     objects.emplace(sensorPath, std::move(interfaces));
251     msg.append(std::move(objects));
252     return IPMI_CC_OK;
253 }
254 }//namespace notify
255 }//namespace sensor
256 }//namespace ipmi
257