1 #include <chrono>
2 #include <stdio.h>
3 #include <string.h>
4 #include <stdint.h>
5 #include <arpa/inet.h>
6 #include <string>
7 #include <experimental/filesystem>
8 
9 #include "host-ipmid/ipmid-api.h"
10 #include "ipmid.hpp"
11 #include "timer.hpp"
12 #include "transporthandler.hpp"
13 #include "utils.hpp"
14 #include "net.hpp"
15 
16 #include <phosphor-logging/log.hpp>
17 #include <phosphor-logging/elog-errors.hpp>
18 #include "xyz/openbmc_project/Common/error.hpp"
19 
20 #define SYSTEMD_NETWORKD_DBUS 1
21 
22 #ifdef SYSTEMD_NETWORKD_DBUS
23 #include <systemd/sd-bus.h>
24 #include <mapper.h>
25 #endif
26 
27 extern std::unique_ptr<phosphor::ipmi::Timer> networkTimer;
28 
29 const int SIZE_MAC = 18; //xx:xx:xx:xx:xx:xx
30 constexpr auto ipv4Protocol = "xyz.openbmc_project.Network.IP.Protocol.IPv4";
31 
32 std::map<int, std::unique_ptr<struct ChannelConfig_t>> channelConfig;
33 
34 using namespace phosphor::logging;
35 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
36 
37 namespace fs = std::experimental::filesystem;
38 
39 void register_netfn_transport_functions() __attribute__((constructor));
40 
41 struct ChannelConfig_t* getChannelConfig(int channel)
42 {
43     auto item = channelConfig.find(channel);
44     if (item == channelConfig.end())
45     {
46         channelConfig[channel] = std::make_unique<struct ChannelConfig_t>();
47     }
48 
49     return channelConfig[channel].get();
50 }
51 
52 // Helper Function to get IP Address/NetMask/Gateway/MAC Address from Network Manager or
53 // Cache based on Set-In-Progress State
54 ipmi_ret_t getNetworkData(uint8_t lan_param, uint8_t* data, int channel)
55 {
56     ipmi_ret_t rc = IPMI_CC_OK;
57     sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
58 
59     auto ethdevice = ipmi::network::ChanneltoEthernet(channel);
60     // if ethdevice is an empty string they weren't expecting this channel.
61     if (ethdevice.empty())
62     {
63         // TODO: return error from getNetworkData()
64         return IPMI_CC_INVALID_FIELD_REQUEST;
65     }
66     auto ethIP = ethdevice + "/" + ipmi::network::IP_TYPE;
67     auto channelConf = getChannelConfig(channel);
68 
69     try
70     {
71         switch (lan_param)
72         {
73             case LAN_PARM_IP:
74             {
75                 std::string ipaddress;
76                 if (channelConf->lan_set_in_progress == SET_COMPLETE)
77                 {
78                     try
79                     {
80                         auto ipObjectInfo = ipmi::getIPObject(
81                                 bus,
82                                 ipmi::network::IP_INTERFACE,
83                                 ipmi::network::ROOT,
84                                 ethIP);
85 
86                         auto properties = ipmi::getAllDbusProperties(
87                                 bus,
88                                 ipObjectInfo.second,
89                                 ipObjectInfo.first,
90                                 ipmi::network::IP_INTERFACE);
91 
92                         ipaddress = properties["Address"].get<std::string>();
93                     }
94                     // ignore the exception, as it is a valid condtion that
95                     // system is not confiured with any ip.
96                     catch (InternalFailure& e)
97                     {
98                         // nothing to do.
99                     }
100                 }
101                 else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS)
102                 {
103                     ipaddress = channelConf->ipaddr;
104                 }
105 
106                 inet_pton(AF_INET, ipaddress.c_str(),
107                           reinterpret_cast<void*>(data));
108             }
109             break;
110 
111             case LAN_PARM_IPSRC:
112             {
113                 std::string networkInterfacePath;
114 
115                 if (channelConf->lan_set_in_progress == SET_COMPLETE)
116                 {
117                     try
118                     {
119                         ipmi::ObjectTree ancestorMap;
120                         // if the system is having ip object,then
121                         // get the IP object.
122                         auto ipObject = ipmi::getDbusObject(
123                                 bus,
124                                 ipmi::network::IP_INTERFACE,
125                                 ipmi::network::ROOT,
126                                 ethIP);
127 
128                         // Get the parent interface of the IP object.
129                         try
130                         {
131                             ipmi::InterfaceList interfaces;
132                             interfaces.emplace_back(
133                                     ipmi::network::ETHERNET_INTERFACE);
134 
135                             ancestorMap = ipmi::getAllAncestors(
136                                     bus,
137                                     ipObject.first,
138                                     std::move(interfaces));
139                         }
140                         catch (InternalFailure& e)
141                         {
142                             // if unable to get the parent interface
143                             // then commit the error and return.
144                             log<level::ERR>("Unable to get the parent interface",
145                                     entry("PATH=%s", ipObject.first.c_str()),
146                                     entry("INTERFACE=%s",
147                                         ipmi::network::ETHERNET_INTERFACE));
148                             break;
149 
150                         }
151                         // for an ip object there would be single parent
152                         // interface.
153                         networkInterfacePath = ancestorMap.begin()->first;
154                     }
155                     catch (InternalFailure& e)
156                     {
157                         // if there is no ip configured on the system,then
158                         // get the network interface object.
159                         auto networkInterfaceObject = ipmi::getDbusObject(
160                                 bus,
161                                 ipmi::network::ETHERNET_INTERFACE,
162                                 ipmi::network::ROOT,
163                                 ethdevice);
164 
165                         networkInterfacePath = networkInterfaceObject.first;
166                     }
167 
168                     auto variant = ipmi::getDbusProperty(
169                             bus,
170                             ipmi::network::SERVICE,
171                             networkInterfacePath,
172                             ipmi::network::ETHERNET_INTERFACE,
173                             "DHCPEnabled");
174 
175                     auto dhcpEnabled = variant.get<bool>();
176                     // As per IPMI spec 2=>DHCP, 1=STATIC
177                     auto ipsrc = dhcpEnabled ? ipmi::network::IPOrigin::DHCP :
178                                                ipmi::network::IPOrigin::STATIC;
179 
180                     memcpy(data, &ipsrc, ipmi::network::IPSRC_SIZE_BYTE);
181                 }
182                 else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS)
183                 {
184                    memcpy(data, &(channelConf->ipsrc),
185                           ipmi::network::IPSRC_SIZE_BYTE);
186                 }
187             }
188             break;
189 
190             case LAN_PARM_SUBNET:
191             {
192                 unsigned long mask {};
193                 if (channelConf->lan_set_in_progress == SET_COMPLETE)
194                 {
195                     try
196                     {
197                         auto ipObjectInfo = ipmi::getIPObject(
198                                 bus,
199                                 ipmi::network::IP_INTERFACE,
200                                 ipmi::network::ROOT,
201                                 ipmi::network::IP_TYPE);
202 
203                         auto properties = ipmi::getAllDbusProperties(
204                                 bus,
205                                 ipObjectInfo.second,
206                                 ipObjectInfo.first,
207                                 ipmi::network::IP_INTERFACE);
208 
209                         auto prefix = properties["PrefixLength"].get<uint8_t>();
210                         mask = ipmi::network::MASK_32_BIT;
211                         mask = htonl(mask << (ipmi::network::BITS_32 - prefix));
212                     }
213                     // ignore the exception, as it is a valid condtion that
214                     // system is not confiured with any ip.
215                     catch (InternalFailure& e)
216                     {
217                         // nothing to do
218                     }
219                     memcpy(data, &mask, ipmi::network::IPV4_ADDRESS_SIZE_BYTE);
220                 }
221                 else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS)
222                 {
223                     inet_pton(AF_INET, channelConf->netmask.c_str(),
224                               reinterpret_cast<void*>(data));
225                 }
226 
227             }
228             break;
229 
230             case LAN_PARM_GATEWAY:
231             {
232                 std::string gateway;
233 
234                 if (channelConf->lan_set_in_progress == SET_COMPLETE)
235                 {
236                     try
237                     {
238                         auto systemObject = ipmi::getDbusObject(
239                                 bus,
240                                 ipmi::network::SYSTEMCONFIG_INTERFACE,
241                                 ipmi::network::ROOT);
242 
243                         auto systemProperties = ipmi::getAllDbusProperties(
244                                 bus,
245                                 systemObject.second,
246                                 systemObject.first,
247                                 ipmi::network::SYSTEMCONFIG_INTERFACE);
248 
249                         gateway = systemProperties["DefaultGateway"].get<
250                             std::string>();
251                     }
252                     // ignore the exception, as it is a valid condtion that
253                     // system is not confiured with any ip.
254                     catch (InternalFailure& e)
255                     {
256                         // nothing to do
257                     }
258 
259                 }
260                 else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS)
261                 {
262                     gateway = channelConf->gateway;
263                 }
264 
265                 inet_pton(AF_INET, gateway.c_str(),
266                           reinterpret_cast<void*>(data));
267             }
268             break;
269 
270             case LAN_PARM_MAC:
271             {
272                 std::string macAddress;
273                 if (channelConf->lan_set_in_progress == SET_COMPLETE)
274                 {
275                     auto macObjectInfo = ipmi::getDbusObject(
276                                              bus,
277                                              ipmi::network::MAC_INTERFACE,
278                                              ipmi::network::ROOT,
279                                              ethdevice);
280 
281                     auto variant = ipmi::getDbusProperty(
282                                      bus,
283                                      macObjectInfo.second,
284                                      macObjectInfo.first,
285                                      ipmi::network::MAC_INTERFACE,
286                                      "MACAddress");
287 
288                     macAddress = variant.get<std::string>();
289 
290                 }
291                 else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS)
292                 {
293                     macAddress = channelConf->macAddress;
294                 }
295 
296                 sscanf(macAddress.c_str(), ipmi::network::MAC_ADDRESS_FORMAT,
297                        (data),
298                        (data + 1),
299                        (data + 2),
300                        (data + 3),
301                        (data + 4),
302                        (data + 5));
303             }
304             break;
305 
306             case LAN_PARM_VLAN:
307             {
308                 uint16_t vlanID {};
309                 if (channelConf->lan_set_in_progress == SET_COMPLETE)
310                 {
311                     try
312                     {
313                         auto ipObjectInfo = ipmi::getIPObject(
314                                 bus,
315                                 ipmi::network::IP_INTERFACE,
316                                 ipmi::network::ROOT,
317                                 ipmi::network::IP_TYPE);
318 
319                         vlanID = static_cast<uint16_t>(
320                                 ipmi::network::getVLAN(ipObjectInfo.first));
321 
322                         vlanID = htole16(vlanID);
323 
324                         if (vlanID)
325                         {
326                             //Enable the 16th bit
327                             vlanID |= htole16(ipmi::network::VLAN_ENABLE_MASK);
328                         }
329                     }
330                     // ignore the exception, as it is a valid condtion that
331                     // system is not confiured with any ip.
332                     catch (InternalFailure& e)
333                     {
334                         // nothing to do
335                     }
336 
337                     memcpy(data, &vlanID, ipmi::network::VLAN_SIZE_BYTE);
338                 }
339                 else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS)
340                 {
341                     memcpy(data, &(channelConf->vlanID),
342                            ipmi::network::VLAN_SIZE_BYTE);
343                 }
344             }
345             break;
346 
347             default:
348                 rc = IPMI_CC_PARM_OUT_OF_RANGE;
349         }
350     }
351     catch (InternalFailure& e)
352     {
353         commit<InternalFailure>();
354         rc = IPMI_CC_UNSPECIFIED_ERROR;
355         return rc;
356     }
357     return rc;
358 }
359 
360 ipmi_ret_t ipmi_transport_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
361                               ipmi_request_t request, ipmi_response_t response,
362                               ipmi_data_len_t data_len, ipmi_context_t context)
363 {
364     // Status code.
365     ipmi_ret_t rc = IPMI_CC_INVALID;
366     *data_len = 0;
367     return rc;
368 }
369 
370 struct set_lan_t
371 {
372     uint8_t channel;
373     uint8_t parameter;
374     uint8_t data[8]; // Per IPMI spec, not expecting more than this size
375 }  __attribute__((packed));
376 
377 ipmi_ret_t ipmi_transport_set_lan(ipmi_netfn_t netfn,
378                                   ipmi_cmd_t cmd,
379                                   ipmi_request_t request,
380                                   ipmi_response_t response,
381                                   ipmi_data_len_t data_len,
382                                   ipmi_context_t context)
383 {
384     ipmi_ret_t rc = IPMI_CC_OK;
385     *data_len = 0;
386 
387     using namespace std::chrono_literals;
388 
389     // time to wait before applying the network changes.
390     constexpr auto networkTimeout = 10000000us; // 10 sec
391 
392     char ipaddr[INET_ADDRSTRLEN];
393     char netmask[INET_ADDRSTRLEN];
394     char gateway[INET_ADDRSTRLEN];
395 
396     auto reqptr = reinterpret_cast<const set_lan_t*>(request);
397     sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
398 
399     // channel number is the lower nibble
400     int channel = reqptr->channel & CHANNEL_MASK;
401     auto ethdevice = ipmi::network::ChanneltoEthernet(channel);
402     if (ethdevice.empty())
403     {
404         return IPMI_CC_INVALID_FIELD_REQUEST;
405     }
406     auto channelConf = getChannelConfig(channel);
407 
408     switch (reqptr->parameter)
409     {
410         case LAN_PARM_IP:
411         {
412             snprintf(ipaddr, INET_ADDRSTRLEN, ipmi::network::IP_ADDRESS_FORMAT,
413                      reqptr->data[0], reqptr->data[1],
414                      reqptr->data[2], reqptr->data[3]);
415 
416             channelConf->ipaddr.assign(ipaddr);
417         }
418         break;
419 
420         case LAN_PARM_IPSRC:
421         {
422             uint8_t ipsrc{};
423             memcpy(&ipsrc, reqptr->data, ipmi::network::IPSRC_SIZE_BYTE);
424             channelConf->ipsrc = static_cast<ipmi::network::IPOrigin>(ipsrc);
425         }
426         break;
427 
428         case LAN_PARM_MAC:
429         {
430             char mac[SIZE_MAC];
431 
432             snprintf(mac, SIZE_MAC, ipmi::network::MAC_ADDRESS_FORMAT,
433                      reqptr->data[0],
434                      reqptr->data[1],
435                      reqptr->data[2],
436                      reqptr->data[3],
437                      reqptr->data[4],
438                      reqptr->data[5]);
439 
440             auto macObjectInfo = ipmi::getDbusObject(
441                                      bus,
442                                      ipmi::network::MAC_INTERFACE,
443                                      ipmi::network::ROOT,
444                                      ethdevice);
445 
446             ipmi::setDbusProperty(bus,
447                                   macObjectInfo.second,
448                                   macObjectInfo.first,
449                                   ipmi::network::MAC_INTERFACE,
450                                   "MACAddress",
451                                   std::string(mac));
452 
453             channelConf->macAddress = mac;
454         }
455         break;
456 
457         case LAN_PARM_SUBNET:
458         {
459             snprintf(netmask, INET_ADDRSTRLEN, ipmi::network::IP_ADDRESS_FORMAT,
460                      reqptr->data[0], reqptr->data[1],
461                      reqptr->data[2], reqptr->data[3]);
462             channelConf->netmask.assign(netmask);
463         }
464         break;
465 
466         case LAN_PARM_GATEWAY:
467         {
468             snprintf(gateway, INET_ADDRSTRLEN, ipmi::network::IP_ADDRESS_FORMAT,
469                      reqptr->data[0], reqptr->data[1],
470                      reqptr->data[2], reqptr->data[3]);
471             channelConf->gateway.assign(gateway);
472         }
473         break;
474 
475         case LAN_PARM_VLAN:
476         {
477             uint16_t vlan {};
478             memcpy(&vlan, reqptr->data, ipmi::network::VLAN_SIZE_BYTE);
479             // We are not storing the enable bit
480             // We assume that ipmitool always send enable
481             // bit as 1.
482             vlan = le16toh(vlan);
483             channelConf->vlanID = vlan;
484         }
485         break;
486 
487         case LAN_PARM_INPROGRESS:
488         {
489             if (reqptr->data[0] == SET_COMPLETE)
490             {
491                 channelConf->lan_set_in_progress = SET_COMPLETE;
492 
493                 log<level::INFO>("Network data from Cache",
494                                  entry("PREFIX=%s", channelConf->netmask.c_str()),
495                                  entry("ADDRESS=%s", channelConf->ipaddr.c_str()),
496                                  entry("GATEWAY=%s", channelConf->gateway.c_str()),
497                                  entry("VLAN=%d", channelConf->vlanID));
498 
499                 if (!networkTimer)
500                 {
501                   log<level::ERR>("Network timer is not instantiated");
502                   return IPMI_CC_UNSPECIFIED_ERROR;
503                 }
504 
505                 // start/restart the timer
506                 networkTimer->startTimer(networkTimeout);
507             }
508             else if (reqptr->data[0] == SET_IN_PROGRESS) // Set In Progress
509             {
510                 channelConf->lan_set_in_progress = SET_IN_PROGRESS;
511                 channelConf->flush = true;
512             }
513         }
514         break;
515 
516         default:
517         {
518             rc = IPMI_CC_PARM_NOT_SUPPORTED;
519         }
520     }
521 
522     return rc;
523 }
524 
525 struct get_lan_t
526 {
527     uint8_t rev_channel;
528     uint8_t parameter;
529     uint8_t parameter_set;
530     uint8_t parameter_block;
531 }  __attribute__((packed));
532 
533 ipmi_ret_t ipmi_transport_get_lan(ipmi_netfn_t netfn,
534                                   ipmi_cmd_t cmd,
535                                   ipmi_request_t request,
536                                   ipmi_response_t response,
537                                   ipmi_data_len_t data_len,
538                                   ipmi_context_t context)
539 {
540     ipmi_ret_t rc = IPMI_CC_OK;
541     *data_len = 0;
542     const uint8_t current_revision = 0x11; // Current rev per IPMI Spec 2.0
543 
544     get_lan_t *reqptr = (get_lan_t*) request;
545     // channel number is the lower nibble
546     int channel = reqptr->rev_channel & CHANNEL_MASK;
547 
548     if (reqptr->rev_channel & 0x80) // Revision is bit 7
549     {
550         // Only current revision was requested
551         *data_len = sizeof(current_revision);
552         memcpy(response, &current_revision, *data_len);
553         return IPMI_CC_OK;
554     }
555 
556     auto ethdevice = ipmi::network::ChanneltoEthernet(channel);
557     if (ethdevice.empty())
558     {
559         return IPMI_CC_INVALID_FIELD_REQUEST;
560     }
561     auto channelConf = getChannelConfig(channel);
562 
563     if (reqptr->parameter == LAN_PARM_INPROGRESS)
564     {
565         uint8_t buf[] = {current_revision, channelConf->lan_set_in_progress};
566         *data_len = sizeof(buf);
567         memcpy(response, &buf, *data_len);
568     }
569     else if (reqptr->parameter == LAN_PARM_AUTHSUPPORT)
570     {
571         uint8_t buf[] = {current_revision,0x04};
572         *data_len = sizeof(buf);
573         memcpy(response, &buf, *data_len);
574     }
575     else if (reqptr->parameter == LAN_PARM_AUTHENABLES)
576     {
577         uint8_t buf[] = {current_revision,0x04,0x04,0x04,0x04,0x04};
578         *data_len = sizeof(buf);
579         memcpy(response, &buf, *data_len);
580     }
581     else if ((reqptr->parameter == LAN_PARM_IP) ||
582              (reqptr->parameter == LAN_PARM_SUBNET) ||
583              (reqptr->parameter == LAN_PARM_GATEWAY) ||
584              (reqptr->parameter == LAN_PARM_MAC))
585     {
586         uint8_t buf[ipmi::network::MAC_ADDRESS_SIZE_BYTE + 1] = {};
587 
588         *data_len = sizeof(current_revision);
589         memcpy(buf, &current_revision, *data_len);
590 
591         if (getNetworkData(reqptr->parameter, &buf[1], channel) == IPMI_CC_OK)
592         {
593             if (reqptr->parameter == LAN_PARM_MAC)
594             {
595                 *data_len = sizeof(buf);
596             }
597             else
598             {
599                 *data_len = ipmi::network::IPV4_ADDRESS_SIZE_BYTE + 1;
600             }
601             memcpy(response, &buf, *data_len);
602         }
603         else
604         {
605             rc = IPMI_CC_UNSPECIFIED_ERROR;
606         }
607     }
608     else if (reqptr->parameter == LAN_PARM_VLAN)
609     {
610         uint8_t buf[ipmi::network::VLAN_SIZE_BYTE + 1] = {};
611 
612         *data_len = sizeof(current_revision);
613         memcpy(buf, &current_revision, *data_len);
614         if (getNetworkData(reqptr->parameter, &buf[1], channel) == IPMI_CC_OK)
615         {
616             *data_len = sizeof(buf);
617             memcpy(response, &buf, *data_len);
618         }
619     }
620     else if (reqptr->parameter == LAN_PARM_IPSRC)
621     {
622         uint8_t buff[ipmi::network::IPSRC_SIZE_BYTE + 1] = {};
623         *data_len = sizeof(current_revision);
624         memcpy(buff, &current_revision, *data_len);
625         if (getNetworkData(reqptr->parameter, &buff[1], channel) == IPMI_CC_OK)
626         {
627             *data_len = sizeof(buff);
628             memcpy(response, &buff, *data_len);
629         }
630     }
631     else
632     {
633         log<level::ERR>("Unsupported parameter",
634                         entry("PARAMETER=0x%x", reqptr->parameter));
635         rc = IPMI_CC_PARM_NOT_SUPPORTED;
636     }
637 
638     return rc;
639 }
640 
641 void applyChanges(int channel)
642 {
643     std::string ipaddress;
644     std::string gateway;
645     uint8_t prefix {};
646     uint32_t vlanID {};
647     std::string networkInterfacePath;
648     ipmi::DbusObjectInfo ipObject;
649     ipmi::DbusObjectInfo systemObject;
650 
651     auto ethdevice = ipmi::network::ChanneltoEthernet(channel);
652     if (ethdevice.empty())
653     {
654         log<level::ERR>("Unable to get the interface name",
655                         entry("CHANNEL=%d", channel));
656         return;
657     }
658     auto ethIp = ethdevice + "/" + ipmi::network::IP_TYPE;
659     auto channelConf = getChannelConfig(channel);
660 
661     try
662     {
663         sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
664 
665         log<level::INFO>("Network data from Cache",
666                          entry("PREFIX=%s", channelConf->netmask.c_str()),
667                          entry("ADDRESS=%s", channelConf->ipaddr.c_str()),
668                          entry("GATEWAY=%s", channelConf->gateway.c_str()),
669                          entry("VLAN=%d", channelConf->vlanID),
670                          entry("IPSRC=%d", channelConf->ipsrc));
671         if (channelConf->vlanID != ipmi::network::VLAN_ID_MASK)
672         {
673             //get the first twelve bits which is vlan id
674             //not interested in rest of the bits.
675             channelConf->vlanID = le32toh(channelConf->vlanID);
676             vlanID = channelConf->vlanID & ipmi::network::VLAN_ID_MASK;
677         }
678 
679         // if the asked ip src is DHCP then not interested in
680         // any given data except vlan.
681         if (channelConf->ipsrc != ipmi::network::IPOrigin::DHCP)
682         {
683             // always get the system object
684             systemObject = ipmi::getDbusObject(
685                     bus,
686                     ipmi::network::SYSTEMCONFIG_INTERFACE,
687                     ipmi::network::ROOT);
688 
689             // the below code is to determine the mode of the interface
690             // as the handling is same, if the system is configured with
691             // DHCP or user has given all the data.
692             try
693             {
694                 ipmi::ObjectTree ancestorMap;
695 
696                 ipmi::InterfaceList interfaces {
697                     ipmi::network::ETHERNET_INTERFACE };
698 
699                 // if the system is having ip object,then
700                 // get the IP object.
701                 ipObject = ipmi::getIPObject(bus,
702                                                ipmi::network::IP_INTERFACE,
703                                                ipmi::network::ROOT,
704                                                ethIp);
705 
706                 // Get the parent interface of the IP object.
707                 try
708                 {
709                     ancestorMap = ipmi::getAllAncestors(bus,
710                                                         ipObject.first,
711                                                         std::move(interfaces));
712                 }
713                 catch (InternalFailure& e)
714                 {
715                     // if unable to get the parent interface
716                     // then commit the error and return.
717                     log<level::ERR>("Unable to get the parent interface",
718                                     entry("PATH=%s", ipObject.first.c_str()),
719                                     entry("INTERFACE=%s",
720                                           ipmi::network::ETHERNET_INTERFACE));
721                     commit<InternalFailure>();
722                     channelConf->clear();
723                     return;
724                 }
725 
726                 networkInterfacePath = ancestorMap.begin()->first;
727             }
728             catch (InternalFailure& e)
729             {
730                 // TODO Currently IPMI supports single interface,need to handle
731                 // Multiple interface through
732                 // https://github.com/openbmc/openbmc/issues/2138
733 
734                 // if there is no ip configured on the system,then
735                 // get the network interface object.
736                 auto networkInterfaceObject = ipmi::getDbusObject(
737                         bus,
738                         ipmi::network::ETHERNET_INTERFACE,
739                         ipmi::network::ROOT,
740                         ethdevice);
741 
742                 networkInterfacePath = std::move(networkInterfaceObject.first);
743             }
744 
745             // get the configured mode on the system.
746             auto enableDHCP = ipmi::getDbusProperty(
747                     bus,
748                     ipmi::network::SERVICE,
749                     networkInterfacePath,
750                     ipmi::network::ETHERNET_INTERFACE,
751                     "DHCPEnabled").get<bool>();
752 
753             // if ip address source is not given then get the ip source mode
754             // from the system so that it can be applied later.
755             if (channelConf->ipsrc == ipmi::network::IPOrigin::UNSPECIFIED)
756             {
757                 channelConf->ipsrc = (enableDHCP) ?
758                     ipmi::network::IPOrigin::DHCP :
759                     ipmi::network::IPOrigin::STATIC;
760             }
761 
762             // check whether user has given all the data
763             // or the configured system interface is dhcp enabled,
764             // in both of the cases get the values from the cache.
765             if ((!channelConf->ipaddr.empty() &&
766                  !channelConf->netmask.empty() &&
767                  !channelConf->gateway.empty()) ||
768                 (enableDHCP)) // configured system interface mode = DHCP
769             {
770                 //convert mask into prefix
771                 ipaddress = channelConf->ipaddr;
772                 prefix = ipmi::network::toPrefix(AF_INET, channelConf->netmask);
773                 gateway = channelConf->gateway;
774             }
775             else // asked ip src = static and configured system src = static
776                 // or partially given data.
777             {
778                 // We have partial filled cache so get the remaining
779                 // info from the system.
780 
781                 // Get the network data from the system as user has
782                 // not given all the data then use the data fetched from the
783                 // system but it is implementation dependent,IPMI spec doesn't
784                 // force it.
785 
786                 // if system is not having any ip object don't throw error,
787                 try
788                 {
789                     auto properties = ipmi::getAllDbusProperties(
790                             bus,
791                             ipObject.second,
792                             ipObject.first,
793                             ipmi::network::IP_INTERFACE);
794 
795                     ipaddress = channelConf->ipaddr.empty() ?
796                         properties["Address"].get<std::string>() :
797                         channelConf->ipaddr;
798 
799                     prefix = channelConf->netmask.empty() ?
800                         properties["PrefixLength"].get<uint8_t>() :
801                         ipmi::network::toPrefix(AF_INET,
802                                 channelConf->netmask);
803                }
804                 catch (InternalFailure& e)
805                 {
806                     log<level::INFO>("Failed to get IP object which matches",
807                             entry("INTERFACE=%s", ipmi::network::IP_INTERFACE),
808                             entry("MATCH=%s", ethIp));
809                 }
810 
811                 auto systemProperties = ipmi::getAllDbusProperties(
812                         bus,
813                         systemObject.second,
814                         systemObject.first,
815                         ipmi::network::SYSTEMCONFIG_INTERFACE);
816 
817                 gateway = channelConf->gateway.empty() ?
818                         systemProperties["DefaultGateway"].get<std::string>() :
819                         channelConf->gateway;
820             }
821         }
822 
823         // Currently network manager doesn't support purging of all the
824         // ip addresses and the vlan interfaces from the parent interface,
825         // TODO once the support is there, will make the change here.
826         // https://github.com/openbmc/openbmc/issues/2141.
827 
828         // TODO Currently IPMI supports single interface,need to handle
829         // Multiple interface through
830         // https://github.com/openbmc/openbmc/issues/2138
831 
832         // instead of deleting all the vlan interfaces and
833         // all the ipv4 address,we will call reset method.
834         //delete all the vlan interfaces
835 
836         ipmi::deleteAllDbusObjects(bus,
837                                    ipmi::network::ROOT,
838                                    ipmi::network::VLAN_INTERFACE);
839 
840         // set the interface mode  to static
841         auto networkInterfaceObject = ipmi::getDbusObject(
842                 bus,
843                 ipmi::network::ETHERNET_INTERFACE,
844                 ipmi::network::ROOT,
845                 ethdevice);
846 
847         // setting the physical interface mode to static.
848         ipmi::setDbusProperty(bus,
849                               ipmi::network::SERVICE,
850                               networkInterfaceObject.first,
851                               ipmi::network::ETHERNET_INTERFACE,
852                               "DHCPEnabled",
853                               false);
854 
855         networkInterfacePath = networkInterfaceObject.first;
856 
857         //delete all the ipv4 addresses
858         ipmi::deleteAllDbusObjects(bus,
859                                    ipmi::network::ROOT,
860                                    ipmi::network::IP_INTERFACE,
861                                    ethIp);
862 
863         if (vlanID)
864         {
865             ipmi::network::createVLAN(bus,
866                                       ipmi::network::SERVICE,
867                                       ipmi::network::ROOT,
868                                       ethdevice,
869                                       vlanID);
870 
871             auto networkInterfaceObject = ipmi::getDbusObject(
872                     bus,
873                     ipmi::network::VLAN_INTERFACE,
874                     ipmi::network::ROOT);
875 
876            networkInterfacePath = networkInterfaceObject.first;
877         }
878 
879         if (channelConf->ipsrc == ipmi::network::IPOrigin::DHCP)
880         {
881             ipmi::setDbusProperty(bus,
882                                   ipmi::network::SERVICE,
883                                   networkInterfacePath,
884                                   ipmi::network::ETHERNET_INTERFACE,
885                                   "DHCPEnabled",
886                                   true);
887         }
888         else
889         {
890             //change the mode to static
891             ipmi::setDbusProperty(bus,
892                                   ipmi::network::SERVICE,
893                                   networkInterfacePath,
894                                   ipmi::network::ETHERNET_INTERFACE,
895                                   "DHCPEnabled",
896                                   false);
897 
898             if (!ipaddress.empty())
899             {
900                 ipmi::network::createIP(bus,
901                                         ipmi::network::SERVICE,
902                                         networkInterfacePath,
903                                         ipv4Protocol,
904                                         ipaddress,
905                                         prefix);
906             }
907 
908             if (!gateway.empty())
909             {
910                 ipmi::setDbusProperty(bus,
911                                       systemObject.second,
912                                       systemObject.first,
913                                       ipmi::network::SYSTEMCONFIG_INTERFACE,
914                                       "DefaultGateway",
915                                       std::string(gateway));
916             }
917         }
918 
919     }
920     catch (InternalFailure& e)
921     {
922         log<level::ERR>("Failed to set network data",
923                         entry("PREFIX=%d", prefix),
924                         entry("ADDRESS=%s", ipaddress.c_str()),
925                         entry("GATEWAY=%s", gateway.c_str()),
926                         entry("VLANID=%d", vlanID),
927                         entry("IPSRC=%d", channelConf->ipsrc));
928 
929         commit<InternalFailure>();
930     }
931 
932     channelConf->clear();
933 }
934 
935 void commitNetworkChanges()
936 {
937     for (const auto &channel : channelConfig)
938     {
939         if (channel.second->flush)
940         {
941             applyChanges(channel.first);
942         }
943     }
944 }
945 
946 void createNetworkTimer()
947 {
948     if (!networkTimer)
949     {
950         std::function<void()> networkTimerCallback(
951                 std::bind(&commitNetworkChanges));
952 
953         networkTimer =
954             std::make_unique<phosphor::ipmi::Timer>(
955                     ipmid_get_sd_event_connection(),
956                     networkTimerCallback);
957     }
958 
959 }
960 
961 void register_netfn_transport_functions()
962 {
963     // As this timer is only for transport handler
964     // so creating it here.
965     createNetworkTimer();
966     // <Wildcard Command>
967     ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_WILDCARD, NULL, ipmi_transport_wildcard,
968                            PRIVILEGE_USER);
969 
970     // <Set LAN Configuration Parameters>
971     ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_SET_LAN, NULL, ipmi_transport_set_lan,
972                            PRIVILEGE_ADMIN);
973 
974     // <Get LAN Configuration Parameters>
975     ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_GET_LAN, NULL, ipmi_transport_get_lan,
976                            PRIVILEGE_OPERATOR);
977 
978     return;
979 }
980