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