1 #include "bios_string_attribute.hpp"
2 
3 #include "common/utils.hpp"
4 
5 #include <phosphor-logging/lg2.hpp>
6 
7 #include <tuple>
8 #include <variant>
9 
10 PHOSPHOR_LOG2_USING;
11 
12 using namespace pldm::utils;
13 
14 namespace pldm
15 {
16 namespace responder
17 {
18 namespace bios
19 {
20 BIOSStringAttribute::BIOSStringAttribute(const Json& entry,
21                                          DBusHandler* const dbusHandler) :
22     BIOSAttribute(entry, dbusHandler)
23 {
24     std::string strTypeTmp = entry.at("string_type");
25     auto iter = strTypeMap.find(strTypeTmp);
26     if (iter == strTypeMap.end())
27     {
28         error("Wrong string type '{TYPE}' for attribute '{ATTRIBUTE}'", "TYPE",
29               strTypeTmp, "ATTRIBUTE", name);
30         throw std::invalid_argument("Wrong string type");
31     }
32     stringInfo.stringType = static_cast<uint8_t>(iter->second);
33 
34     stringInfo.minLength = entry.at("minimum_string_length");
35     stringInfo.maxLength = entry.at("maximum_string_length");
36     stringInfo.defLength = entry.at("default_string_length");
37     stringInfo.defString = entry.at("default_string");
38 
39     pldm_bios_table_attr_entry_string_info info = {
40         0,
41         readOnly,
42         stringInfo.stringType,
43         stringInfo.minLength,
44         stringInfo.maxLength,
45         stringInfo.defLength,
46         stringInfo.defString.data(),
47     };
48 
49     const char* errmsg;
50     auto rc = pldm_bios_table_attr_entry_string_info_check(&info, &errmsg);
51     if (rc != PLDM_SUCCESS)
52     {
53         error(
54             "Wrong field for string attribute '{ATTRIBUTE}', error '{ERROR}', minimum string length '{MINIMUM_STRING_LENGTH}', maximum string length '{MAXIMUM_STRING_LENGTH}', default string length '{DEFAULT_STRING_LENGTH}' and default string '{DEFAULT_STRING}'",
55             "ATTRIBUTE", name, "ERROR", errmsg, "MINIMUM_STRING_LENGTH",
56             stringInfo.minLength, "MAXIMUM_STRING_LENGTH", stringInfo.maxLength,
57             "DEFAULT_STRING_LENGTH", stringInfo.defLength, "DEFAULT_STRING",
58             stringInfo.defString);
59         throw std::invalid_argument("Wrong field for string attribute");
60     }
61 }
62 
63 void BIOSStringAttribute::setAttrValueOnDbus(
64     const pldm_bios_attr_val_table_entry* attrValueEntry,
65     const pldm_bios_attr_table_entry*, const BIOSStringTable&)
66 {
67     if (!dBusMap.has_value())
68     {
69         return;
70     }
71 
72     PropertyValue value =
73         table::attribute_value::decodeStringEntry(attrValueEntry);
74     dbusHandler->setDbusProperty(*dBusMap, value);
75 }
76 
77 std::string BIOSStringAttribute::getAttrValue()
78 {
79     if (!dBusMap.has_value())
80     {
81         return stringInfo.defString;
82     }
83     try
84     {
85         return dbusHandler->getDbusProperty<std::string>(
86             dBusMap->objectPath.c_str(), dBusMap->propertyName.c_str(),
87             dBusMap->interface.c_str());
88     }
89     catch (const std::exception& e)
90     {
91         error(
92             "Failed to get string attribute '{ATTRIBUTE}' at path '{PATH}' and interface '{INTERFACE}' for property '{PROPERTY}', error - {ERROR}",
93             "ATTRIBUTE", name, "PATH", dBusMap->objectPath, "INTERFACE",
94             dBusMap->interface, "PROPERTY", dBusMap->propertyName, "ERROR", e);
95         return stringInfo.defString;
96     }
97 }
98 
99 void BIOSStringAttribute::constructEntry(
100     const BIOSStringTable& stringTable, Table& attrTable, Table& attrValueTable,
101     std::optional<std::variant<int64_t, std::string>> optAttributeValue)
102 {
103     pldm_bios_table_attr_entry_string_info info = {
104         stringTable.findHandle(name), readOnly,
105         stringInfo.stringType,        stringInfo.minLength,
106         stringInfo.maxLength,         stringInfo.defLength,
107         stringInfo.defString.data(),
108     };
109 
110     auto attrTableEntry = table::attribute::constructStringEntry(attrTable,
111                                                                  &info);
112     auto [attrHandle, attrType,
113           _] = table::attribute::decodeHeader(attrTableEntry);
114 
115     std::string currStr{};
116     if (optAttributeValue.has_value())
117     {
118         auto attributeValue = optAttributeValue.value();
119         if (attributeValue.index() == 1)
120         {
121             currStr = std::get<std::string>(attributeValue);
122         }
123         else
124         {
125             currStr = getAttrValue();
126         }
127     }
128     else
129     {
130         currStr = getAttrValue();
131     }
132 
133     table::attribute_value::constructStringEntry(attrValueTable, attrHandle,
134                                                  attrType, currStr);
135 }
136 
137 int BIOSStringAttribute::updateAttrVal(Table& newValue, uint16_t attrHdl,
138                                        uint8_t attrType,
139                                        const PropertyValue& newPropVal)
140 {
141     try
142     {
143         const auto& newStringValue = std::get<std::string>(newPropVal);
144         table::attribute_value::constructStringEntry(newValue, attrHdl,
145                                                      attrType, newStringValue);
146     }
147     catch (const std::bad_variant_access& e)
148     {
149         error("Invalid value passed for the property - {ERROR}", "ERROR", e);
150         return PLDM_ERROR;
151     }
152     return PLDM_SUCCESS;
153 }
154 
155 void BIOSStringAttribute::generateAttributeEntry(
156     const std::variant<int64_t, std::string>& attributevalue,
157     Table& attrValueEntry)
158 {
159     std::string value = std::get<std::string>(attributevalue);
160     uint16_t len = value.size();
161 
162     attrValueEntry.resize(sizeof(pldm_bios_attr_val_table_entry) +
163                           sizeof(uint16_t) + len - 1);
164 
165     auto entry = reinterpret_cast<pldm_bios_attr_val_table_entry*>(
166         attrValueEntry.data());
167 
168     entry->attr_type = 1;
169     memcpy(entry->value, &len, sizeof(uint16_t));
170     memcpy(entry->value + sizeof(uint16_t), value.c_str(), value.size());
171 }
172 
173 } // namespace bios
174 } // namespace responder
175 } // namespace pldm
176