1 #include <stdio.h>
2 #include <string.h>
3 #include <stdint.h>
4 #include <arpa/inet.h>
5 #include <string>
6 
7 #include "host-ipmid/ipmid-api.h"
8 #include "ipmid.hpp"
9 #include "transporthandler.hpp"
10 #include "utils.hpp"
11 
12 #include <phosphor-logging/log.hpp>
13 #include <phosphor-logging/elog-errors.hpp>
14 #include "xyz/openbmc_project/Common/error.hpp"
15 
16 #define SYSTEMD_NETWORKD_DBUS 1
17 
18 #ifdef SYSTEMD_NETWORKD_DBUS
19 #include <systemd/sd-bus.h>
20 #include <mapper.h>
21 #endif
22 
23 // OpenBMC System Manager dbus framework
24 const char  *obj   =  "/org/openbmc/NetworkManager/Interface";
25 const char  *ifc   =  "org.openbmc.NetworkManager";
26 
27 const char *nwinterface = "eth0";
28 
29 const int SIZE_MAC = 18; //xx:xx:xx:xx:xx:xx
30 
31 struct ChannelConfig_t channelConfig;
32 
33 const uint8_t SET_COMPLETE = 0;
34 const uint8_t SET_IN_PROGRESS = 1;
35 const uint8_t SET_COMMIT_WRITE = 2; //Optional
36 const uint8_t SET_IN_PROGRESS_RESERVED = 3; //Reserved
37 
38 // Status of Set-In-Progress Parameter (# 0)
39 uint8_t lan_set_in_progress = SET_COMPLETE;
40 
41 using namespace phosphor::logging;
42 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
43 
44 void register_netfn_transport_functions() __attribute__((constructor));
45 
46 // Helper Function to get IP Address/NetMask/Gateway/MAC Address from Network Manager or
47 // Cache based on Set-In-Progress State
48 ipmi_ret_t getNetworkData(uint8_t lan_param, uint8_t* data)
49 {
50     ipmi_ret_t rc = IPMI_CC_OK;
51     sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
52 
53     try
54     {
55         switch (lan_param)
56         {
57             case LAN_PARM_IP:
58             {
59                 std::string ipaddress;
60                 if (lan_set_in_progress == SET_COMPLETE)
61                 {
62                     auto ipObjectInfo = ipmi::getDbusObject(
63                                             bus,
64                                             ipmi::network::IP_INTERFACE,
65                                             ipmi::network::ROOT,
66                                             ipmi::network::IP_TYPE);
67 
68                     auto properties = ipmi::getAllDbusProperties(
69                                          bus,
70                                          ipObjectInfo.second,
71                                          ipObjectInfo.first,
72                                          ipmi::network::IP_INTERFACE);
73 
74                     ipaddress = properties["Address"].get<std::string>();
75                 }
76                 else if (lan_set_in_progress == SET_IN_PROGRESS)
77                 {
78                     ipaddress = channelConfig.ipaddr;
79                 }
80 
81                 inet_pton(AF_INET, ipaddress.c_str(),
82                           reinterpret_cast<void*>(data));
83             }
84             break;
85 
86             case LAN_PARM_SUBNET:
87             {
88                 if (lan_set_in_progress == SET_COMPLETE)
89                 {
90                     auto ipObjectInfo = ipmi::getDbusObject(
91                                             bus,
92                                             ipmi::network::IP_INTERFACE,
93                                             ipmi::network::ROOT,
94                                             ipmi::network::IP_TYPE);
95 
96                     auto properties = ipmi::getAllDbusProperties(
97                                          bus,
98                                          ipObjectInfo.second,
99                                          ipObjectInfo.first,
100                                          ipmi::network::IP_INTERFACE);
101 
102                     auto prefix = properties["PrefixLength"].get<uint8_t>();
103                     unsigned long mask = ipmi::network::MASK_32_BIT;
104                     mask = htonl(mask << (ipmi::network::BITS_32 - prefix));
105                     memcpy(data, &mask, ipmi::network::IPV4_ADDRESS_SIZE_BYTE);
106                 }
107                 else if (lan_set_in_progress == SET_IN_PROGRESS)
108                 {
109                     inet_pton(AF_INET, channelConfig.netmask.c_str(),
110                               reinterpret_cast<void*>(data));
111 
112                 }
113 
114             }
115             break;
116 
117             case LAN_PARM_GATEWAY:
118             {
119                 std::string gateway;
120 
121                 if (lan_set_in_progress == SET_COMPLETE)
122                 {
123                     auto systemObject = ipmi::getDbusObject(
124                             bus,
125                             ipmi::network::SYSTEMCONFIG_INTERFACE,
126                             ipmi::network::ROOT);
127 
128                     auto systemProperties = ipmi::getAllDbusProperties(
129                             bus,
130                             systemObject.second,
131                             systemObject.first,
132                             ipmi::network::SYSTEMCONFIG_INTERFACE);
133 
134                     gateway = systemProperties["DefaultGateway"].get<
135                                  std::string>();
136 
137                 }
138                 else if (lan_set_in_progress == SET_IN_PROGRESS)
139                 {
140                     gateway = channelConfig.gateway;
141                 }
142 
143                 inet_pton(AF_INET, gateway.c_str(),
144                           reinterpret_cast<void*>(data));
145 
146             }
147             break;
148 
149             case LAN_PARM_MAC:
150             {
151                 std::string macAddress;
152                 if (lan_set_in_progress == SET_COMPLETE)
153                 {
154                     auto macObjectInfo = ipmi::getDbusObject(
155                                              bus,
156                                              ipmi::network::MAC_INTERFACE,
157                                              ipmi::network::ROOT);
158 
159                     auto variant = ipmi::getDbusProperty(
160                                      bus,
161                                      macObjectInfo.second,
162                                      macObjectInfo.first,
163                                      ipmi::network::MAC_INTERFACE,
164                                      "MACAddress");
165 
166                     macAddress = variant.get<std::string>();
167 
168                 }
169                 else if (lan_set_in_progress == SET_IN_PROGRESS)
170                 {
171                     macAddress = channelConfig.macAddress;
172                 }
173 
174                 sscanf(macAddress.c_str(), ipmi::network::MAC_ADDRESS_FORMAT,
175                        (data),
176                        (data + 1),
177                        (data + 2),
178                        (data + 3),
179                        (data + 4),
180                        (data + 5));
181             }
182             break;
183 
184             case LAN_PARM_VLAN:
185             {
186                 if (lan_set_in_progress == SET_COMPLETE)
187                 {
188                     auto ipObjectInfo = ipmi::getDbusObject(
189                                             bus,
190                                             ipmi::network::IP_INTERFACE,
191                                             ipmi::network::ROOT,
192                                             ipmi::network::IP_TYPE);
193 
194                     auto vlanID = static_cast<uint16_t>(
195                             ipmi::network::getVLAN(ipObjectInfo.first));
196 
197                     vlanID = htole16(vlanID);
198 
199                     if (vlanID)
200                     {
201                         //Enable the 16th bit
202                         vlanID |= htole16(ipmi::network::VLAN_ENABLE_MASK);
203                     }
204 
205                     memcpy(data, &vlanID, ipmi::network::VLAN_SIZE_BYTE);
206                 }
207                 else if (lan_set_in_progress == SET_IN_PROGRESS)
208                 {
209                     memcpy(data, &(channelConfig.vlanID),
210                            ipmi::network::VLAN_SIZE_BYTE);
211                 }
212             }
213             break;
214 
215             default:
216                 rc = IPMI_CC_PARM_OUT_OF_RANGE;
217         }
218     }
219     catch (InternalFailure& e)
220     {
221         commit<InternalFailure>();
222         rc = IPMI_CC_UNSPECIFIED_ERROR;
223         return rc;
224     }
225     return rc;
226 }
227 
228 ipmi_ret_t ipmi_transport_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
229                               ipmi_request_t request, ipmi_response_t response,
230                               ipmi_data_len_t data_len, ipmi_context_t context)
231 {
232     printf("Handling TRANSPORT WILDCARD Netfn:[0x%X], Cmd:[0x%X]\n",netfn, cmd);
233     // Status code.
234     ipmi_ret_t rc = IPMI_CC_INVALID;
235     *data_len = 0;
236     return rc;
237 }
238 
239 struct set_lan_t
240 {
241     uint8_t channel;
242     uint8_t parameter;
243     uint8_t data[8]; // Per IPMI spec, not expecting more than this size
244 }  __attribute__((packed));
245 
246 ipmi_ret_t ipmi_transport_set_lan(ipmi_netfn_t netfn,
247                                   ipmi_cmd_t cmd,
248                                   ipmi_request_t request,
249                                   ipmi_response_t response,
250                                   ipmi_data_len_t data_len,
251                                   ipmi_context_t context)
252 {
253     ipmi_ret_t rc = IPMI_CC_OK;
254     *data_len = 0;
255 
256     char ipaddr[INET_ADDRSTRLEN];
257     char netmask[INET_ADDRSTRLEN];
258     char gateway[INET_ADDRSTRLEN];
259 
260     auto reqptr = reinterpret_cast<const set_lan_t*>(request);
261     sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
262 
263     switch (reqptr->parameter)
264     {
265         case LAN_PARM_IP:
266         {
267             snprintf(ipaddr, INET_ADDRSTRLEN, ipmi::network::IP_ADDRESS_FORMAT,
268                      reqptr->data[0], reqptr->data[1],
269                      reqptr->data[2], reqptr->data[3]);
270 
271             channelConfig.ipaddr.assign(ipaddr);
272 
273         }
274         break;
275 
276         case LAN_PARM_MAC:
277         {
278             char mac[SIZE_MAC];
279 
280             snprintf(mac, SIZE_MAC, ipmi::network::MAC_ADDRESS_FORMAT,
281                      reqptr->data[0],
282                      reqptr->data[1],
283                      reqptr->data[2],
284                      reqptr->data[3],
285                      reqptr->data[4],
286                      reqptr->data[5]);
287 
288             auto macObjectInfo = ipmi::getDbusObject(
289                                      bus,
290                                      ipmi::network::MAC_INTERFACE,
291                                      ipmi::network::ROOT,
292                                      ipmi::network::INTERFACE);
293 
294             ipmi::setDbusProperty(bus,
295                                   macObjectInfo.second,
296                                   macObjectInfo.first,
297                                   ipmi::network::MAC_INTERFACE,
298                                   "MACAddress",
299                                   std::string(mac));
300 
301             channelConfig.macAddress = mac;
302 
303         }
304         break;
305 
306         case LAN_PARM_SUBNET:
307         {
308             snprintf(netmask, INET_ADDRSTRLEN, ipmi::network::IP_ADDRESS_FORMAT,
309                      reqptr->data[0], reqptr->data[1],
310                      reqptr->data[2], reqptr->data[3]);
311             channelConfig.netmask.assign(netmask);
312         }
313         break;
314 
315         case LAN_PARM_GATEWAY:
316         {
317             snprintf(gateway, INET_ADDRSTRLEN, ipmi::network::IP_ADDRESS_FORMAT,
318                      reqptr->data[0], reqptr->data[1],
319                      reqptr->data[2], reqptr->data[3]);
320             channelConfig.gateway.assign(gateway);
321 
322         }
323         break;
324 
325         case LAN_PARM_VLAN:
326         {
327             uint16_t vlan {};
328             memcpy(&vlan, reqptr->data, ipmi::network::VLAN_SIZE_BYTE);
329             // We are not storing the enable bit
330             // We assume that ipmitool always send enable
331             // bit as 1.
332             vlan = le16toh(vlan);
333             channelConfig.vlanID = vlan;
334         }
335         break;
336 
337         case LAN_PARM_INPROGRESS:
338         {
339             if (reqptr->data[0] == SET_COMPLETE)
340             {
341                 lan_set_in_progress = SET_COMPLETE;
342 
343                 log<level::INFO>("Network data from Cache",
344                                  entry("PREFIX=%s", channelConfig.netmask.c_str()),
345                                  entry("ADDRESS=%s", channelConfig.ipaddr.c_str()),
346                                  entry("GATEWAY=%s", channelConfig.gateway.c_str()),
347                                  entry("VLAN=%d", channelConfig.vlanID));
348 
349                 log<level::INFO>("Use Set Channel Access command to apply");
350 
351             }
352             else if (reqptr->data[0] == SET_IN_PROGRESS) // Set In Progress
353             {
354                 lan_set_in_progress = SET_IN_PROGRESS;
355             }
356 
357         }
358         break;
359 
360         default:
361         {
362             rc = IPMI_CC_PARM_NOT_SUPPORTED;
363         }
364 
365     }
366 
367     return rc;
368 }
369 
370 struct get_lan_t
371 {
372     uint8_t rev_channel;
373     uint8_t parameter;
374     uint8_t parameter_set;
375     uint8_t parameter_block;
376 }  __attribute__((packed));
377 
378 ipmi_ret_t ipmi_transport_get_lan(ipmi_netfn_t netfn,
379                                   ipmi_cmd_t cmd,
380                                   ipmi_request_t request,
381                                   ipmi_response_t response,
382                                   ipmi_data_len_t data_len,
383                                   ipmi_context_t context)
384 {
385     ipmi_ret_t rc = IPMI_CC_OK;
386     *data_len = 0;
387     const uint8_t current_revision = 0x11; // Current rev per IPMI Spec 2.0
388 
389     get_lan_t *reqptr = (get_lan_t*) request;
390 
391     if (reqptr->rev_channel & 0x80) // Revision is bit 7
392     {
393         // Only current revision was requested
394         *data_len = sizeof(current_revision);
395         memcpy(response, &current_revision, *data_len);
396         return IPMI_CC_OK;
397     }
398 
399     if (reqptr->parameter == LAN_PARM_INPROGRESS)
400     {
401         uint8_t buf[] = {current_revision, lan_set_in_progress};
402         *data_len = sizeof(buf);
403         memcpy(response, &buf, *data_len);
404     }
405     else if (reqptr->parameter == LAN_PARM_AUTHSUPPORT)
406     {
407         uint8_t buf[] = {current_revision,0x04};
408         *data_len = sizeof(buf);
409         memcpy(response, &buf, *data_len);
410     }
411     else if (reqptr->parameter == LAN_PARM_AUTHENABLES)
412     {
413         uint8_t buf[] = {current_revision,0x04,0x04,0x04,0x04,0x04};
414         *data_len = sizeof(buf);
415         memcpy(response, &buf, *data_len);
416     }
417     else if ((reqptr->parameter == LAN_PARM_IP) ||
418              (reqptr->parameter == LAN_PARM_SUBNET) ||
419              (reqptr->parameter == LAN_PARM_GATEWAY) ||
420              (reqptr->parameter == LAN_PARM_MAC))
421     {
422         uint8_t buf[ipmi::network::MAC_ADDRESS_SIZE_BYTE + 1];
423 
424         *data_len = sizeof(current_revision);
425         memcpy(buf, &current_revision, *data_len);
426 
427         if (getNetworkData(reqptr->parameter, &buf[1]) == IPMI_CC_OK)
428         {
429             if (reqptr->parameter == LAN_PARM_MAC)
430             {
431                 *data_len = sizeof(buf);
432             }
433             else
434             {
435                 *data_len = ipmi::network::IPV4_ADDRESS_SIZE_BYTE + 1;
436             }
437             memcpy(response, &buf, *data_len);
438         }
439         else
440         {
441             rc = IPMI_CC_UNSPECIFIED_ERROR;
442         }
443     }
444     else if (reqptr->parameter == LAN_PARM_VLAN)
445     {
446         uint8_t buf[ipmi::network::VLAN_SIZE_BYTE + 1];
447 
448         *data_len = sizeof(current_revision);
449         memcpy(buf, &current_revision, *data_len);
450         if (getNetworkData(reqptr->parameter, &buf[1]) == IPMI_CC_OK)
451         {
452             *data_len = sizeof(buf);
453             memcpy(response, &buf, *data_len);
454         }
455     }
456     else
457     {
458         log<level::ERR>("Unsupported parameter",
459                         entry("PARAMETER=0x%x", reqptr->parameter));
460         rc = IPMI_CC_PARM_NOT_SUPPORTED;
461     }
462 
463     return rc;
464 }
465 
466 void register_netfn_transport_functions()
467 {
468     // <Wildcard Command>
469     printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_TRANSPORT, IPMI_CMD_WILDCARD);
470     ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_WILDCARD, NULL, ipmi_transport_wildcard,
471                            PRIVILEGE_USER);
472 
473     // <Set LAN Configuration Parameters>
474     printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_TRANSPORT, IPMI_CMD_SET_LAN);
475     ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_SET_LAN, NULL, ipmi_transport_set_lan,
476                            PRIVILEGE_ADMIN);
477 
478     // <Get LAN Configuration Parameters>
479     printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_TRANSPORT, IPMI_CMD_GET_LAN);
480     ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_GET_LAN, NULL, ipmi_transport_get_lan,
481                            PRIVILEGE_OPERATOR);
482 
483     return;
484 }
485