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