1 #include "dbus_to_event_handler.hpp"
2
3 #include "libpldmresponder/pdr.hpp"
4
5 #include <phosphor-logging/lg2.hpp>
6
7 PHOSPHOR_LOG2_USING;
8
9 namespace pldm
10 {
11 using namespace pldm::responder;
12 using namespace pldm::responder::pdr;
13 using namespace pldm::responder::pdr_utils;
14 using namespace pldm::utils;
15 using namespace sdbusplus::bus::match::rules;
16
17 namespace state_sensor
18 {
19 const std::vector<uint8_t> pdrTypes{PLDM_STATE_SENSOR_PDR};
20
DbusToPLDMEvent(int,uint8_t mctp_eid,pldm::InstanceIdDb & instanceIdDb,pldm::requester::Handler<pldm::requester::Request> * handler)21 DbusToPLDMEvent::DbusToPLDMEvent(
22 int /* mctp_fd */, uint8_t mctp_eid, pldm::InstanceIdDb& instanceIdDb,
23 pldm::requester::Handler<pldm::requester::Request>* handler) :
24 mctp_eid(mctp_eid), instanceIdDb(instanceIdDb), handler(handler)
25 {}
26
sendEventMsg(uint8_t eventType,const std::vector<uint8_t> & eventDataVec)27 void DbusToPLDMEvent::sendEventMsg(uint8_t eventType,
28 const std::vector<uint8_t>& eventDataVec)
29 {
30 auto instanceIdResult =
31 pldm::utils::getInstanceId(instanceIdDb.next(mctp_eid));
32 if (!instanceIdResult)
33 {
34 return;
35 }
36 auto instanceId = instanceIdResult.value();
37 std::vector<uint8_t> requestMsg(
38 sizeof(pldm_msg_hdr) + PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES +
39 eventDataVec.size());
40 auto request = new (requestMsg.data()) pldm_msg;
41
42 auto rc = encode_platform_event_message_req(
43 instanceId, 1 /*formatVersion*/, TERMINUS_ID /*tId*/, eventType,
44 eventDataVec.data(), eventDataVec.size(), request,
45 eventDataVec.size() + PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES);
46 if (rc != PLDM_SUCCESS)
47 {
48 instanceIdDb.free(mctp_eid, instanceId);
49 error(
50 "Failed to encode platform event message request, response code '{RC}'",
51 "RC", rc);
52 return;
53 }
54
55 auto platformEventMessageResponseHandler = [](mctp_eid_t /*eid*/,
56 const pldm_msg* response,
57 size_t respMsgLen) {
58 if (response == nullptr || !respMsgLen)
59 {
60 error("Failed to receive response for platform event message");
61 return;
62 }
63 uint8_t completionCode{};
64 uint8_t status{};
65 auto rc = decode_platform_event_message_resp(response, respMsgLen,
66 &completionCode, &status);
67 if (rc || completionCode)
68 {
69 error(
70 "Failed to decode response of platform event message, response code '{RC}' and completion code '{CC}'",
71 "RC", rc, "CC", completionCode);
72 }
73 };
74
75 rc = handler->registerRequest(
76 mctp_eid, instanceId, PLDM_PLATFORM, PLDM_PLATFORM_EVENT_MESSAGE,
77 std::move(requestMsg), std::move(platformEventMessageResponseHandler));
78 if (rc)
79 {
80 error("Failed to send the platform event message, response code '{RC}'",
81 "RC", rc);
82 }
83 }
84
sendStateSensorEvent(SensorId sensorId,const DbusObjMaps & dbusMaps)85 void DbusToPLDMEvent::sendStateSensorEvent(SensorId sensorId,
86 const DbusObjMaps& dbusMaps)
87 {
88 // Encode PLDM platform event msg to indicate a state sensor change.
89 // DSP0248_1.2.0 Table 19
90 if (!dbusMaps.contains(sensorId))
91 {
92 // this is not an error condition, if we end up here
93 // that means that the sensor with the sensor id has
94 // custom behaviour(or probably an oem sensor) in
95 // sending events that cannot be captured via standard
96 // dbus-json infastructure
97 return;
98 }
99
100 size_t sensorEventSize = PLDM_SENSOR_EVENT_DATA_MIN_LENGTH + 1;
101 const auto& [dbusMappings, dbusValMaps] = dbusMaps.at(sensorId);
102 for (size_t offset = 0; offset < dbusMappings.size(); ++offset)
103 {
104 std::vector<uint8_t> sensorEventDataVec{};
105 sensorEventDataVec.resize(sensorEventSize);
106 auto eventData = new (sensorEventDataVec.data()) pldm_sensor_event_data;
107 eventData->sensor_id = sensorId;
108 eventData->sensor_event_class_type = PLDM_STATE_SENSOR_STATE;
109 eventData->event_class[0] = static_cast<uint8_t>(offset);
110 eventData->event_class[1] = PLDM_SENSOR_UNKNOWN;
111 eventData->event_class[2] = PLDM_SENSOR_UNKNOWN;
112
113 const auto& dbusMapping = dbusMappings[offset];
114 const auto& dbusValueMapping = dbusValMaps[offset];
115 auto stateSensorMatch = std::make_unique<sdbusplus::bus::match_t>(
116 pldm::utils::DBusHandler::getBus(),
117 propertiesChanged(dbusMapping.objectPath.c_str(),
118 dbusMapping.interface.c_str()),
119 [this, sensorEventDataVec, dbusValueMapping, dbusMapping, sensorId,
120 offset](auto& msg) mutable {
121 DbusChangedProps props{};
122 std::string intf;
123 uint8_t previousState = PLDM_SENSOR_UNKNOWN;
124 msg.read(intf, props);
125 if (!props.contains(dbusMapping.propertyName))
126 {
127 return;
128 }
129 for (const auto& itr : dbusValueMapping)
130 {
131 bool findValue = false;
132 if (dbusMapping.propertyType == "string")
133 {
134 std::string src = std::get<std::string>(itr.second);
135 std::string dst = std::get<std::string>(
136 props.at(dbusMapping.propertyName));
137
138 auto values = pldm::utils::split(src, "||", " ");
139 for (const auto& value : values)
140 {
141 if (value == dst)
142 {
143 findValue = true;
144 break;
145 }
146 }
147 }
148 else
149 {
150 findValue =
151 itr.second == props.at(dbusMapping.propertyName)
152 ? true
153 : false;
154 }
155
156 if (findValue)
157 {
158 auto eventData = new (sensorEventDataVec.data())
159 pldm_sensor_event_data;
160 eventData->event_class[1] = itr.first;
161 if (sensorCacheMap.contains(sensorId) &&
162 sensorCacheMap[sensorId][offset] !=
163 PLDM_SENSOR_UNKNOWN)
164 {
165 previousState = sensorCacheMap[sensorId][offset];
166 }
167 else
168 {
169 previousState = itr.first;
170 }
171 eventData->event_class[2] = previousState;
172 this->sendEventMsg(PLDM_SENSOR_EVENT,
173 sensorEventDataVec);
174 updateSensorCacheMaps(sensorId, offset, previousState);
175 break;
176 }
177 }
178 });
179 stateSensorMatchs.emplace_back(std::move(stateSensorMatch));
180 }
181 }
182
listenSensorEvent(const pdr_utils::Repo & repo,const DbusObjMaps & dbusMaps)183 void DbusToPLDMEvent::listenSensorEvent(const pdr_utils::Repo& repo,
184 const DbusObjMaps& dbusMaps)
185 {
186 const std::map<Type, sensorEvent> sensorHandlers = {
187 {PLDM_STATE_SENSOR_PDR,
188 [this](SensorId sensorId, const DbusObjMaps& dbusMaps) {
189 this->sendStateSensorEvent(sensorId, dbusMaps);
190 }}};
191
192 pldm_state_sensor_pdr* pdr = nullptr;
193 std::unique_ptr<pldm_pdr, decltype(&pldm_pdr_destroy)> sensorPdrRepo(
194 pldm_pdr_init(), pldm_pdr_destroy);
195 if (!sensorPdrRepo)
196 {
197 throw std::runtime_error("Unable to instantiate sensor PDR repository");
198 }
199
200 for (auto pdrType : pdrTypes)
201 {
202 Repo sensorPDRs(sensorPdrRepo.get());
203 getRepoByType(repo, sensorPDRs, pdrType);
204 if (sensorPDRs.empty())
205 {
206 return;
207 }
208
209 PdrEntry pdrEntry{};
210 auto pdrRecord = sensorPDRs.getFirstRecord(pdrEntry);
211 while (pdrRecord)
212 {
213 pdr = new (pdrEntry.data) pldm_state_sensor_pdr;
214 SensorId sensorId = LE16TOH(pdr->sensor_id);
215 if (sensorHandlers.contains(pdrType))
216 {
217 sensorHandlers.at(pdrType)(sensorId, dbusMaps);
218 }
219
220 pdrRecord = sensorPDRs.getNextRecord(pdrRecord, pdrEntry);
221 }
222 }
223 }
224
225 } // namespace state_sensor
226 } // namespace pldm
227