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