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