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(
29             "Wrong string type, STRING_TYPE={STR_TYPE} ATTRIBUTE_NAME={ATTR_NAME}",
30             "STR_TYP", strTypeTmp, "ATTR_NAME", name);
31         throw std::invalid_argument("Wrong string type");
32     }
33     stringInfo.stringType = static_cast<uint8_t>(iter->second);
34 
35     stringInfo.minLength = entry.at("minimum_string_length");
36     stringInfo.maxLength = entry.at("maximum_string_length");
37     stringInfo.defLength = entry.at("default_string_length");
38     stringInfo.defString = entry.at("default_string");
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_NAME={ATTR_NAME} ERRMSG={ERR_MSG} MINIMUM_STRING_LENGTH={MIN_LEN} MAXIMUM_STRING_LENGTH={MAX_LEN} DEFAULT_STRING_LENGTH={DEF_LEN} DEFAULT_STRING={DEF_STR}",
56             "ATTR_NAME", name, "ERR_MSG", errmsg, "MIN_LEN",
57             stringInfo.minLength, "MAX_LEN", stringInfo.maxLength, "DEF_LEN",
58             stringInfo.defLength, "DEF_STR", 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             "Error getting string attribute '{ATTR}' from '{INTERFACE}': {ERROR}",
93             "ATTR", name, "INTERFACE", dBusMap->interface, "ERROR", e);
94         return stringInfo.defString;
95     }
96 }
97 
98 void BIOSStringAttribute::constructEntry(
99     const BIOSStringTable& stringTable, Table& attrTable, Table& attrValueTable,
100     std::optional<std::variant<int64_t, std::string>> optAttributeValue)
101 {
102     pldm_bios_table_attr_entry_string_info info = {
103         stringTable.findHandle(name), readOnly,
104         stringInfo.stringType,        stringInfo.minLength,
105         stringInfo.maxLength,         stringInfo.defLength,
106         stringInfo.defString.data(),
107     };
108 
109     auto attrTableEntry = table::attribute::constructStringEntry(attrTable,
110                                                                  &info);
111     auto [attrHandle, attrType,
112           _] = table::attribute::decodeHeader(attrTableEntry);
113 
114     std::string currStr{};
115     if (optAttributeValue.has_value())
116     {
117         auto attributeValue = optAttributeValue.value();
118         if (attributeValue.index() == 1)
119         {
120             currStr = std::get<std::string>(attributeValue);
121         }
122         else
123         {
124             currStr = getAttrValue();
125         }
126     }
127     else
128     {
129         currStr = getAttrValue();
130     }
131 
132     table::attribute_value::constructStringEntry(attrValueTable, attrHandle,
133                                                  attrType, currStr);
134 }
135 
136 int BIOSStringAttribute::updateAttrVal(Table& newValue, uint16_t attrHdl,
137                                        uint8_t attrType,
138                                        const PropertyValue& newPropVal)
139 {
140     try
141     {
142         const auto& newStringValue = std::get<std::string>(newPropVal);
143         table::attribute_value::constructStringEntry(newValue, attrHdl,
144                                                      attrType, newStringValue);
145     }
146     catch (const std::bad_variant_access& e)
147     {
148         error("invalid value passed for the property, error: {ERR_EXCEP}",
149               "ERR_EXCEP", e.what());
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