1 #include "utils.hpp"
2 
3 #include "common/utils.hpp"
4 
5 #include <libpldm/base.h>
6 #include <libpldm/platform.h>
7 #include <sys/socket.h>
8 #include <sys/types.h>
9 #include <sys/un.h>
10 #include <unistd.h>
11 
12 #include <phosphor-logging/lg2.hpp>
13 #include <xyz/openbmc_project/Inventory/Decorator/Asset/client.hpp>
14 #include <xyz/openbmc_project/Inventory/Item/Connector/client.hpp>
15 #include <xyz/openbmc_project/ObjectMapper/client.hpp>
16 
17 PHOSPHOR_LOG2_USING;
18 
19 using namespace pldm::utils;
20 
21 namespace pldm
22 {
23 namespace responder
24 {
25 namespace utils
26 {
27 int setupUnixSocket(const std::string& socketInterface)
28 {
29     int sock;
30     struct sockaddr_un addr;
31     memset(&addr, 0, sizeof(addr));
32     addr.sun_family = AF_UNIX;
33     size_t interfaceLength =
34         strnlen(socketInterface.c_str(), sizeof(addr.sun_path));
35     if (interfaceLength == sizeof(addr.sun_path))
36     {
37         error("Setup unix socket path '{PATH}' is too long '{LENGTH}'", "PATH",
38               socketInterface, "LENGTH", interfaceLength);
39         return -1;
40     }
41 
42     strncpy(addr.sun_path, socketInterface.c_str(), sizeof(addr.sun_path) - 1);
43 
44     if ((sock = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0)) == -1)
45     {
46         error("Failed to open unix socket");
47         return -1;
48     }
49 
50     if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1)
51     {
52         error("Failed to bind unix socket, error number - {ERROR_NUM}",
53               "ERROR_NUM", errno);
54         close(sock);
55         return -1;
56     }
57 
58     if (listen(sock, 1) == -1)
59     {
60         error("Failed listen() call while setting up unix socket");
61         close(sock);
62         return -1;
63     }
64 
65     fd_set rfd;
66     struct timeval tv;
67     tv.tv_sec = 1;
68     tv.tv_usec = 0;
69 
70     FD_ZERO(&rfd);
71     FD_SET(sock, &rfd);
72     int nfd = sock + 1;
73     int fd = -1;
74 
75     int retval = select(nfd, &rfd, NULL, NULL, &tv);
76     if (retval < 0)
77     {
78         error(
79             "Failed select() call while setting up unix socket, error number - {ERROR_NUM}",
80             "ERROR_NUM", errno);
81         close(sock);
82         return -1;
83     }
84 
85     if ((retval > 0) && (FD_ISSET(sock, &rfd)))
86     {
87         fd = accept(sock, NULL, NULL);
88         if (fd < 0)
89         {
90             error(
91                 "Failed accept() call while setting up unix socket, error number - {ERROR_NUM}",
92                 "ERROR_NUM", errno);
93             close(sock);
94             return -1;
95         }
96         close(sock);
97     }
98     return fd;
99 }
100 
101 int writeToUnixSocket(const int sock, const char* buf, const uint64_t blockSize)
102 {
103     uint64_t i;
104     int nwrite = 0;
105 
106     for (i = 0; i < blockSize; i = i + nwrite)
107     {
108         fd_set wfd;
109         struct timeval tv;
110         tv.tv_sec = 1;
111         tv.tv_usec = 0;
112 
113         FD_ZERO(&wfd);
114         FD_SET(sock, &wfd);
115         int nfd = sock + 1;
116 
117         int retval = select(nfd, NULL, &wfd, NULL, &tv);
118         if (retval < 0)
119         {
120             error(
121                 "Failed to write to unix socket select, error number - {ERROR_NUM}",
122                 "ERROR_NUM", errno);
123             close(sock);
124             return -1;
125         }
126         if (retval == 0)
127         {
128             nwrite = 0;
129             continue;
130         }
131         if ((retval > 0) && (FD_ISSET(sock, &wfd)))
132         {
133             nwrite = write(sock, buf + i, blockSize - i);
134             if (nwrite < 0)
135             {
136                 if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
137                 {
138                     error(
139                         "Failed to write to unix socket, error number - {ERROR_NUM}",
140                         "ERROR_NUM", errno);
141                     nwrite = 0;
142                     continue;
143                 }
144                 error(
145                     "Failed to write to unix socket, error number - {ERROR_NUM}",
146                     "ERROR_NUM", errno);
147                 close(sock);
148                 return -1;
149             }
150         }
151         else
152         {
153             nwrite = 0;
154         }
155     }
156     return 0;
157 }
158 
159 bool checkIfIBMFru(const std::string& objPath)
160 {
161     using DecoratorAsset =
162         sdbusplus::client::xyz::openbmc_project::inventory::decorator::Asset<>;
163 
164     try
165     {
166         auto propVal = pldm::utils::DBusHandler().getDbusPropertyVariant(
167             objPath.c_str(), "Model", DecoratorAsset::interface);
168         const auto& model = std::get<std::string>(propVal);
169         if (!model.empty())
170         {
171             return true;
172         }
173     }
174     catch (const std::exception&)
175     {
176         return false;
177     }
178     return false;
179 }
180 
181 std::vector<std::string> findPortObjects(const std::string& adapterObjPath)
182 {
183     using ItemConnector =
184         sdbusplus::client::xyz::openbmc_project::inventory::item::Connector<>;
185 
186     std::vector<std::string> portObjects;
187     try
188     {
189         portObjects = pldm::utils::DBusHandler().getSubTreePaths(
190             adapterObjPath, 0,
191             std::vector<std::string>({ItemConnector::interface}));
192     }
193     catch (const std::exception& e)
194     {
195         error("No ports under adapter '{ADAPTER_OBJ_PATH}'  - {ERROR}.",
196               "ADAPTER_OBJ_PATH", adapterObjPath.c_str(), "ERROR", e);
197     }
198 
199     return portObjects;
200 }
201 
202 } // namespace utils
203 
204 namespace oem_ibm_utils
205 {
206 using namespace pldm::utils;
207 
208 int pldm::responder::oem_ibm_utils::Handler::setCoreCount(
209     const EntityAssociations& Associations, const EntityMaps entityMaps)
210 {
211     int coreCountRef = 0;
212     // get the CPU pldm entities
213     for (const auto& entries : Associations)
214     {
215         auto parent = pldm_entity_extract(entries[0]);
216         // entries[0] would be the parent in the entity association map
217         if (parent.entity_type == PLDM_ENTITY_PROC)
218         {
219             int& coreCount = coreCountRef;
220             for (const auto& entry : entries)
221             {
222                 auto child = pldm_entity_extract(entry);
223                 if (child.entity_type == (PLDM_ENTITY_PROC | 0x8000))
224                 {
225                     // got a core child
226                     ++coreCount;
227                 }
228             }
229             try
230             {
231                 auto grand_parent = pldm_entity_get_parent(entries[0]);
232                 std::string grepWord = std::format(
233                     "{}{}/{}{}", entityMaps.at(grand_parent.entity_type),
234                     std::to_string(grand_parent.entity_instance_num),
235                     entityMaps.at(parent.entity_type),
236                     std::to_string(parent.entity_instance_num));
237                 static constexpr auto searchpath = "/xyz/openbmc_project/";
238                 std::vector<std::string> cpuInterface = {
239                     "xyz.openbmc_project.Inventory.Item.Cpu"};
240                 pldm::utils::GetSubTreeResponse response = dBusIntf->getSubtree(
241                     searchpath, 0 /* depth */, cpuInterface);
242                 for (const auto& [objectPath, serviceMap] : response)
243                 {
244                     // find the object path with first occurrence of coreX
245                     if (objectPath.contains(grepWord))
246                     {
247                         pldm::utils::DBusMapping dbusMapping{
248                             objectPath, cpuInterface[0], "CoreCount",
249                             "uint16_t"};
250                         pldm::utils::PropertyValue value =
251                             static_cast<uint16_t>(coreCount);
252                         try
253                         {
254                             dBusIntf->setDbusProperty(dbusMapping, value);
255                         }
256                         catch (const std::exception& e)
257                         {
258                             error(
259                                 "Failed to set the core count property at interface '{INTERFACE}': {ERROR}",
260                                 "INTERFACE", cpuInterface[0], "ERROR", e);
261                         }
262                     }
263                 }
264             }
265             catch (const std::exception& e)
266             {
267                 error("Failed to searching CoreCount property: {ERROR}",
268                       "ERROR", e);
269             }
270         }
271     }
272     return coreCountRef;
273 }
274 
275 } // namespace oem_ibm_utils
276 } // namespace responder
277 } // namespace pldm
278