sensors: rework sensor assertion
Prior to this patch the sensor assertion logic would generate an invalid
DBus message or undefined behavior in several scenarios.
- A bit is both asserted and desasserted:
A well behaving client won't do this but the existing logic would
generate an invalid property-set message with signature ssvv. Rework
the logic such that no dbus traffic occurs.
- No bits are asserted:
Results in an invalid message with signature ss.
Rework such that no dbus traffic occurs.
- Empty offset value map in configuration:
Results in an invalid message with signature s.
Rework such that no dbus traffic occurs.
- Empty offset value map entry (either assert or deassert) in
configuration:
Results in an invalid variant signature.
Rework such that no dbus traffic occurs.
- The same bit is specified in the configuration for multiple
properties or interfaces:
Can result in invalid messages with a wide variety of signatures.
Rework such that one message is sent for each property
being updated.
- Invalid bit specified in value map entry
Results in undefined behavior calling bitset::test.
Rework such that entries in the value map with invalid bits
are ignored.
Tested: Verified the OperatingSystemStatus sensor can be set by a BIOS
Change-Id: I4df9472a8bdc9e44e98e1a963838da0912d10683
Signed-off-by: Brad Bishop <bradleyb@fuzziesquirrel.com>
diff --git a/sensordatahandler.cpp b/sensordatahandler.cpp
index 7db8fe0..4d87341 100644
--- a/sensordatahandler.cpp
+++ b/sensordatahandler.cpp
@@ -256,33 +256,55 @@
ipmi_ret_t assertion(const SetSensorReadingReq& cmdData,
const Info& sensorInfo)
{
- auto msg = makeDbusMsg(
+ std::bitset<16> assertionSet(getAssertionSet(cmdData).first);
+ std::bitset<16> deassertionSet(getAssertionSet(cmdData).second);
+ auto bothSet = assertionSet ^ deassertionSet;
+
+ const auto& interface = sensorInfo.propertyInterfaces.begin();
+
+ for (const auto& property : interface->second)
+ {
+ Value tmp{mapbox::util::no_init()};
+ for (const auto& value : std::get<OffsetValueMap>(property.second))
+ {
+ if (bothSet.size() <= value.first || !bothSet.test(value.first))
+ {
+ // A BIOS shouldn't do this but ignore if they do.
+ continue;
+ }
+
+ if (assertionSet.test(value.first))
+ {
+ tmp = value.second.assert;
+ break;
+ }
+ if (deassertionSet.test(value.first))
+ {
+ tmp = value.second.deassert;
+ break;
+ }
+ }
+
+ if (tmp.valid())
+ {
+ auto msg = makeDbusMsg(
"org.freedesktop.DBus.Properties",
sensorInfo.sensorPath,
"Set",
sensorInfo.sensorInterface);
+ msg.append(interface->first);
+ msg.append(property.first);
+ msg.append(tmp);
- std::bitset<16> assertionSet(getAssertionSet(cmdData).first);
- std::bitset<16> deassertionSet(getAssertionSet(cmdData).second);
-
- const auto& interface = sensorInfo.propertyInterfaces.begin();
- msg.append(interface->first);
- for (const auto& property : interface->second)
- {
- msg.append(property.first);
- for (const auto& value : std::get<OffsetValueMap>(property.second))
- {
- if (assertionSet.test(value.first))
+ auto rc = updateToDbus(msg);
+ if (rc)
{
- msg.append(value.second.assert);
- }
- if (deassertionSet.test(value.first))
- {
- msg.append(value.second.deassert);
+ return rc;
}
}
}
- return updateToDbus(msg);
+
+ return IPMI_CC_OK;
}
}//namespace set