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