1 #pragma once
2 
3 #include "app/channel.hpp"
4 #include "user_channel/cipher_mgmt.hpp"
5 
6 #include <arpa/inet.h>
7 #include <netinet/ether.h>
8 
9 #include <array>
10 #include <bitset>
11 #include <cinttypes>
12 #include <cstdint>
13 #include <cstring>
14 #include <fstream>
15 #include <functional>
16 #include <ipmid/api-types.hpp>
17 #include <ipmid/api.hpp>
18 #include <ipmid/message.hpp>
19 #include <ipmid/message/types.hpp>
20 #include <ipmid/types.hpp>
21 #include <ipmid/utils.hpp>
22 #include <optional>
23 #include <phosphor-logging/elog-errors.hpp>
24 #include <phosphor-logging/elog.hpp>
25 #include <phosphor-logging/log.hpp>
26 #include <sdbusplus/bus.hpp>
27 #include <sdbusplus/exception.hpp>
28 #include <string>
29 #include <string_view>
30 #include <type_traits>
31 #include <unordered_map>
32 #include <unordered_set>
33 #include <user_channel/channel_layer.hpp>
34 #include <utility>
35 #include <vector>
36 #include <xyz/openbmc_project/Common/error.hpp>
37 #include <xyz/openbmc_project/Network/EthernetInterface/server.hpp>
38 #include <xyz/openbmc_project/Network/IP/server.hpp>
39 #include <xyz/openbmc_project/Network/Neighbor/server.hpp>
40 
41 namespace ipmi
42 {
43 namespace transport
44 {
45 
46 // D-Bus Network Daemon definitions
47 constexpr auto PATH_ROOT = "/xyz/openbmc_project/network";
48 constexpr auto INTF_ETHERNET = "xyz.openbmc_project.Network.EthernetInterface";
49 constexpr auto INTF_IP = "xyz.openbmc_project.Network.IP";
50 constexpr auto INTF_IP_CREATE = "xyz.openbmc_project.Network.IP.Create";
51 constexpr auto INTF_MAC = "xyz.openbmc_project.Network.MACAddress";
52 constexpr auto INTF_NEIGHBOR = "xyz.openbmc_project.Network.Neighbor";
53 constexpr auto INTF_NEIGHBOR_CREATE_STATIC =
54     "xyz.openbmc_project.Network.Neighbor.CreateStatic";
55 constexpr auto INTF_VLAN = "xyz.openbmc_project.Network.VLAN";
56 constexpr auto INTF_VLAN_CREATE = "xyz.openbmc_project.Network.VLAN.Create";
57 
58 /** @brief IPMI LAN Parameters */
59 enum class LanParam : uint8_t
60 {
61     SetStatus = 0,
62     AuthSupport = 1,
63     AuthEnables = 2,
64     IP = 3,
65     IPSrc = 4,
66     MAC = 5,
67     SubnetMask = 6,
68     Gateway1 = 12,
69     Gateway1MAC = 13,
70     VLANId = 20,
71     CiphersuiteSupport = 22,
72     CiphersuiteEntries = 23,
73     cipherSuitePrivilegeLevels = 24,
74     IPFamilySupport = 50,
75     IPFamilyEnables = 51,
76     IPv6Status = 55,
77     IPv6StaticAddresses = 56,
78     IPv6DynamicAddresses = 59,
79     IPv6RouterControl = 64,
80     IPv6StaticRouter1IP = 65,
81     IPv6StaticRouter1MAC = 66,
82     IPv6StaticRouter1PrefixLength = 67,
83     IPv6StaticRouter1PrefixValue = 68,
84 };
85 
86 /** @brief IPMI IP Origin Types */
87 enum class IPSrc : uint8_t
88 {
89     Unspecified = 0,
90     Static = 1,
91     DHCP = 2,
92     BIOS = 3,
93     BMC = 4,
94 };
95 
96 /** @brief IPMI Set Status */
97 enum class SetStatus : uint8_t
98 {
99     Complete = 0,
100     InProgress = 1,
101     Commit = 2,
102 };
103 
104 /** @brief IPMI Family Suport Bits */
105 namespace IPFamilySupportFlag
106 {
107 constexpr uint8_t IPv6Only = 0;
108 constexpr uint8_t DualStack = 1;
109 constexpr uint8_t IPv6Alerts = 2;
110 } // namespace IPFamilySupportFlag
111 
112 /** @brief IPMI IPFamily Enables Flag */
113 enum class IPFamilyEnables : uint8_t
114 {
115     IPv4Only = 0,
116     IPv6Only = 1,
117     DualStack = 2,
118 };
119 
120 /** @brief IPMI IPv6 Dyanmic Status Bits */
121 namespace IPv6StatusFlag
122 {
123 constexpr uint8_t DHCP = 0;
124 constexpr uint8_t SLAAC = 1;
125 }; // namespace IPv6StatusFlag
126 
127 /** @brief IPMI IPv6 Source */
128 enum class IPv6Source : uint8_t
129 {
130     Static = 0,
131     SLAAC = 1,
132     DHCP = 2,
133 };
134 
135 /** @brief IPMI IPv6 Address Status */
136 enum class IPv6AddressStatus : uint8_t
137 {
138     Active = 0,
139     Disabled = 1,
140 };
141 
142 namespace IPv6RouterControlFlag
143 {
144 constexpr uint8_t Static = 0;
145 constexpr uint8_t Dynamic = 1;
146 }; // namespace IPv6RouterControlFlag
147 
148 // LAN Handler specific response codes
149 constexpr Cc ccParamNotSupported = 0x80;
150 constexpr Cc ccParamSetLocked = 0x81;
151 constexpr Cc ccParamReadOnly = 0x82;
152 
153 // VLANs are a 12-bit value
154 constexpr uint16_t VLAN_VALUE_MASK = 0x0fff;
155 constexpr uint16_t VLAN_ENABLE_FLAG = 0x8000;
156 
157 // Arbitrary v6 Address Limits to prevent too much output in ipmitool
158 constexpr uint8_t MAX_IPV6_STATIC_ADDRESSES = 15;
159 constexpr uint8_t MAX_IPV6_DYNAMIC_ADDRESSES = 15;
160 
161 // Prefix length limits of phosphor-networkd
162 constexpr uint8_t MIN_IPV4_PREFIX_LENGTH = 1;
163 constexpr uint8_t MAX_IPV4_PREFIX_LENGTH = 32;
164 constexpr uint8_t MIN_IPV6_PREFIX_LENGTH = 1;
165 constexpr uint8_t MAX_IPV6_PREFIX_LENGTH = 128;
166 
167 /** @brief The dbus parameters for the interface corresponding to a channel
168  *         This helps reduce the number of mapper lookups we need for each
169  *         query and simplifies finding the VLAN interface if needed.
170  */
171 struct ChannelParams
172 {
173     /** @brief The channel ID */
174     int id;
175     /** @brief channel name for the interface */
176     std::string ifname;
177     /** @brief Name of the service on the bus */
178     std::string service;
179     /** @brief Lower level adapter path that is guaranteed to not be a VLAN */
180     std::string ifPath;
181     /** @brief Logical adapter path used for address assignment */
182     std::string logicalPath;
183 };
184 
185 /** @brief A trivial helper used to determine if two PODs are equal
186  *
187  *  @params[in] a - The first object to compare
188  *  @params[in] b - The second object to compare
189  *  @return True if the objects are the same bytewise
190  */
191 template <typename T>
192 bool equal(const T& a, const T& b)
193 {
194     static_assert(std::is_trivially_copyable_v<T>);
195     return std::memcmp(&a, &b, sizeof(T)) == 0;
196 }
197 
198 /** @brief Copies bytes from an array into a trivially copyable container
199  *
200  *  @params[out] t     - The container receiving the data
201  *  @params[in]  bytes - The data to copy
202  */
203 template <size_t N, typename T>
204 void copyInto(T& t, const std::array<uint8_t, N>& bytes)
205 {
206     static_assert(std::is_trivially_copyable_v<T>);
207     static_assert(N == sizeof(T));
208     std::memcpy(&t, bytes.data(), bytes.size());
209 }
210 
211 /** @brief Gets a generic view of the bytes in the input container
212  *
213  *  @params[in] t - The data to reference
214  *  @return A string_view referencing the bytes in the container
215  */
216 template <typename T>
217 std::string_view dataRef(const T& t)
218 {
219     static_assert(std::is_trivially_copyable_v<T>);
220     return {reinterpret_cast<const char*>(&t), sizeof(T)};
221 }
222 
223 /** @brief Determines the ethernet interface name corresponding to a channel
224  *         Tries to map a VLAN object first so that the address information
225  *         is accurate. Otherwise it gets the standard ethernet interface.
226  *
227  *  @param[in] bus     - The bus object used for lookups
228  *  @param[in] channel - The channel id corresponding to an ethernet interface
229  *  @return Ethernet interface service and object path if it exists
230  */
231 std::optional<ChannelParams> maybeGetChannelParams(sdbusplus::bus_t& bus,
232                                                    uint8_t channel);
233 
234 /** @brief A trivial helper around maybeGetChannelParams() that throws an
235  *         exception when it is unable to acquire parameters for the channel.
236  *
237  *  @param[in] bus     - The bus object used for lookups
238  *  @param[in] channel - The channel id corresponding to an ethernet interface
239  *  @return Ethernet interface service and object path
240  */
241 ChannelParams getChannelParams(sdbusplus::bus_t& bus, uint8_t channel);
242 
243 /** @brief Trivializes using parameter getter functions by providing a bus
244  *         and channel parameters automatically.
245  *
246  *  @param[in] channel - The channel id corresponding to an ethernet interface
247  *  ...
248  */
249 template <auto func, typename... Args>
250 auto channelCall(uint8_t channel, Args&&... args)
251 {
252     sdbusplus::bus_t bus(ipmid_get_sd_bus_connection());
253     auto params = getChannelParams(bus, channel);
254     return std::invoke(func, bus, params, std::forward<Args>(args)...);
255 }
256 
257 /** @brief Generic paramters for different address families */
258 template <int family>
259 struct AddrFamily
260 {
261 };
262 
263 /** @brief Parameter specialization for IPv4 */
264 template <>
265 struct AddrFamily<AF_INET>
266 {
267     using addr = in_addr;
268     static constexpr auto protocol =
269         sdbusplus::xyz::openbmc_project::Network::server::IP::Protocol::IPv4;
270     static constexpr size_t maxStrLen = INET6_ADDRSTRLEN;
271     static constexpr uint8_t defaultPrefix = 32;
272     static constexpr char propertyGateway[] = "DefaultGateway";
273 };
274 
275 /** @brief Parameter specialization for IPv6 */
276 template <>
277 struct AddrFamily<AF_INET6>
278 {
279     using addr = in6_addr;
280     static constexpr auto protocol =
281         sdbusplus::xyz::openbmc_project::Network::server::IP::Protocol::IPv6;
282     static constexpr size_t maxStrLen = INET6_ADDRSTRLEN;
283     static constexpr uint8_t defaultPrefix = 128;
284     static constexpr char propertyGateway[] = "DefaultGateway6";
285 };
286 
287 /** @brief Interface Neighbor configuration parameters */
288 template <int family>
289 struct IfNeigh
290 {
291     std::string path;
292     typename AddrFamily<family>::addr ip;
293     ether_addr mac;
294 };
295 
296 /** @brief Interface IP Address configuration parameters */
297 template <int family>
298 struct IfAddr
299 {
300     std::string path;
301     typename AddrFamily<family>::addr address;
302     sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin origin;
303     uint8_t prefix;
304 };
305 
306 /** @brief Valid address origins for IPv6 */
307 static inline const std::unordered_set<
308     sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin>
309     originsV6Static = {sdbusplus::xyz::openbmc_project::Network::server::IP::
310                            AddressOrigin::Static};
311 static inline const std::unordered_set<
312     sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin>
313     originsV6Dynamic = {
314         sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin::
315             DHCP,
316         sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin::
317             SLAAC,
318 };
319 
320 /** @brief A lazy lookup mechanism for iterating over object properties stored
321  *         in DBus. This will only perform the object lookup when needed, and
322  *         retains a cache of previous lookups to speed up future iterations.
323  */
324 class ObjectLookupCache
325 {
326   public:
327     using PropertiesCache = std::unordered_map<std::string, PropertyMap>;
328 
329     /** @brief Creates a new ObjectLookupCache for the interface on the bus
330      *         NOTE: The inputs to this object must outlive the object since
331      *         they are only referenced by it.
332      *
333      *  @param[in] bus    - The bus object used for lookups
334      *  @param[in] params - The parameters for the channel
335      *  @param[in] intf   - The interface we are looking up
336      */
337     ObjectLookupCache(sdbusplus::bus_t& bus, const ChannelParams& params,
338                       const char* intf) :
339         bus(bus),
340         params(params), intf(intf),
341         objs(getAllDbusObjects(bus, params.logicalPath, intf, ""))
342     {
343     }
344 
345     class iterator : public ObjectTree::const_iterator
346     {
347       public:
348         using value_type = PropertiesCache::value_type;
349 
350         iterator(ObjectTree::const_iterator it, ObjectLookupCache& container) :
351             ObjectTree::const_iterator(it), container(container),
352             ret(container.cache.end())
353         {
354         }
355         value_type& operator*()
356         {
357             ret = container.get(ObjectTree::const_iterator::operator*().first);
358             return *ret;
359         }
360         value_type* operator->()
361         {
362             return &operator*();
363         }
364 
365       private:
366         ObjectLookupCache& container;
367         PropertiesCache::iterator ret;
368     };
369 
370     iterator begin() noexcept
371     {
372         return iterator(objs.begin(), *this);
373     }
374 
375     iterator end() noexcept
376     {
377         return iterator(objs.end(), *this);
378     }
379 
380   private:
381     sdbusplus::bus_t& bus;
382     const ChannelParams& params;
383     const char* const intf;
384     const ObjectTree objs;
385     PropertiesCache cache;
386 
387     /** @brief Gets a cached copy of the object properties if possible
388      *         Otherwise performs a query on DBus to look them up
389      *
390      *  @param[in] path - The object path to lookup
391      *  @return An iterator for the specified object path + properties
392      */
393     PropertiesCache::iterator get(const std::string& path)
394     {
395         auto it = cache.find(path);
396         if (it != cache.end())
397         {
398             return it;
399         }
400         auto properties = getAllDbusProperties(bus, params.service, path, intf);
401         return cache.insert({path, std::move(properties)}).first;
402     }
403 };
404 
405 /** @brief Turns an IP address string into the network byte order form
406  *         NOTE: This version strictly validates family matches
407  *
408  *  @param[in] address - The string form of the address
409  *  @return A network byte order address or none if conversion failed
410  */
411 template <int family>
412 std::optional<typename AddrFamily<family>::addr>
413     maybeStringToAddr(const char* address)
414 {
415     typename AddrFamily<family>::addr ret;
416     if (inet_pton(family, address, &ret) == 1)
417     {
418         return ret;
419     }
420     return std::nullopt;
421 }
422 
423 /** @brief Turns an IP address string into the network byte order form
424  *         NOTE: This version strictly validates family matches
425  *
426  *  @param[in] address - The string form of the address
427  *  @return A network byte order address
428  */
429 template <int family>
430 typename AddrFamily<family>::addr stringToAddr(const char* address)
431 {
432     auto ret = maybeStringToAddr<family>(address);
433     if (!ret)
434     {
435         phosphor::logging::log<phosphor::logging::level::ERR>(
436             "Failed to convert IP Address",
437             phosphor::logging::entry("FAMILY=%d", family),
438             phosphor::logging::entry("ADDRESS=%s", address));
439         phosphor::logging::elog<
440             sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure>();
441     }
442     return *ret;
443 }
444 
445 /** @brief Turns an IP address in network byte order into a string
446  *
447  *  @param[in] address - The string form of the address
448  *  @return A network byte order address
449  */
450 template <int family>
451 std::string addrToString(const typename AddrFamily<family>::addr& address)
452 {
453     std::string ret(AddrFamily<family>::maxStrLen, '\0');
454     inet_ntop(family, &address, ret.data(), ret.size());
455     ret.resize(strlen(ret.c_str()));
456     return ret;
457 }
458 
459 /** @brief Converts a human readable MAC string into MAC bytes
460  *
461  *  @param[in] mac - The MAC string
462  *  @return MAC in bytes
463  */
464 ether_addr stringToMAC(const char* mac);
465 /** @brief Searches the ip object lookup cache for an address matching
466  *         the input parameters. NOTE: The index lacks stability across address
467  *         changes since the network daemon has no notion of stable indicies.
468  *
469  *  @param[in] bus     - The bus object used for lookups
470  *  @param[in] params  - The parameters for the channel
471  *  @param[in] idx     - The index of the desired address on the interface
472  *  @param[in] origins - The allowed origins for the address objects
473  *  @param[in] ips     - The object lookup cache holding all of the address info
474  *  @return The address and prefix if it was found
475  */
476 template <int family>
477 std::optional<IfAddr<family>> findIfAddr(
478     [[maybe_unused]] sdbusplus::bus_t& bus,
479     [[maybe_unused]] const ChannelParams& params, uint8_t idx,
480     const std::unordered_set<
481         sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin>&
482         origins,
483     ObjectLookupCache& ips)
484 {
485     for (const auto& [path, properties] : ips)
486     {
487         const auto& addrStr = std::get<std::string>(properties.at("Address"));
488         auto addr = maybeStringToAddr<family>(addrStr.c_str());
489         if (!addr)
490         {
491             continue;
492         }
493 
494         sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin
495             origin = sdbusplus::xyz::openbmc_project::Network::server::IP::
496                 convertAddressOriginFromString(
497                     std::get<std::string>(properties.at("Origin")));
498         if (origins.find(origin) == origins.end())
499         {
500             continue;
501         }
502 
503         if (idx > 0)
504         {
505             idx--;
506             continue;
507         }
508 
509         IfAddr<family> ifaddr;
510         ifaddr.path = path;
511         ifaddr.address = *addr;
512         ifaddr.prefix = std::get<uint8_t>(properties.at("PrefixLength"));
513         ifaddr.origin = origin;
514         return ifaddr;
515     }
516 
517     return std::nullopt;
518 }
519 /** @brief Trivial helper around findIfAddr that simplifies calls
520  *         for one off lookups. Don't use this if you intend to do multiple
521  *         lookups at a time.
522  *
523  *  @param[in] bus     - The bus object used for lookups
524  *  @param[in] params  - The parameters for the channel
525  *  @param[in] idx     - The index of the desired address on the interface
526  *  @param[in] origins - The allowed origins for the address objects
527  *  @return The address and prefix if it was found
528  */
529 template <int family>
530 auto getIfAddr(
531     sdbusplus::bus_t& bus, const ChannelParams& params, uint8_t idx,
532     const std::unordered_set<
533         sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin>&
534         origins)
535 {
536     ObjectLookupCache ips(bus, params, INTF_IP);
537     return findIfAddr<family>(bus, params, idx, origins, ips);
538 }
539 
540 /** @brief Determines if the ethernet interface is using DHCP
541  *
542  *  @param[in] bus    - The bus object used for lookups
543  *  @param[in] params - The parameters for the channel
544  *  @return DHCPConf enumeration
545  */
546 sdbusplus::xyz::openbmc_project::Network::server::EthernetInterface::DHCPConf
547     getDHCPProperty(sdbusplus::bus_t& bus, const ChannelParams& params);
548 
549 /** @brief Sets the DHCP v6 state on the given interface
550  *
551  *  @param[in] bus           - The bus object used for lookups
552  *  @param[in] params        - The parameters for the channel
553  *  @param[in] requestedDhcp - DHCP state to assign (none, v6, both)
554  *  @param[in] defaultMode   - True: Use algorithmic assignment
555  *                             False: requestedDhcp assigned unconditionally
556  */
557 void setDHCPv6Property(sdbusplus::bus_t& bus, const ChannelParams& params,
558                        const sdbusplus::xyz::openbmc_project::Network::server::
559                            EthernetInterface::DHCPConf requestedDhcp,
560                        const bool defaultMode);
561 
562 /** @brief Reconfigures the IPv6 address info configured for the interface
563  *
564  *  @param[in] bus     - The bus object used for lookups
565  *  @param[in] params  - The parameters for the channel
566  *  @param[in] idx     - The address index to operate on
567  *  @param[in] address - The new address
568  *  @param[in] prefix  - The new address prefix
569  */
570 void reconfigureIfAddr6(sdbusplus::bus_t& bus, const ChannelParams& params,
571                         uint8_t idx, const in6_addr& address, uint8_t prefix);
572 
573 /** @brief Retrieves the current gateway for the address family on the system
574  *         NOTE: The gateway is per channel instead of the system wide one.
575  *
576  *  @param[in] bus    - The bus object used for lookups
577  *  @param[in] params - The parameters for the channel
578  *  @return An address representing the gateway address if it exists
579  */
580 template <int family>
581 std::optional<typename AddrFamily<family>::addr>
582     getGatewayProperty(sdbusplus::bus_t& bus, const ChannelParams& params)
583 {
584     auto objPath = "/xyz/openbmc_project/network/" + params.ifname;
585     auto gatewayStr = std::get<std::string>(
586         getDbusProperty(bus, params.service, objPath, INTF_ETHERNET,
587                         AddrFamily<family>::propertyGateway));
588     if (gatewayStr.empty())
589     {
590         return std::nullopt;
591     }
592     return stringToAddr<family>(gatewayStr.c_str());
593 }
594 
595 template <int family>
596 std::optional<IfNeigh<family>>
597     findStaticNeighbor(sdbusplus::bus_t&, const ChannelParams&,
598                        const typename AddrFamily<family>::addr& ip,
599                        ObjectLookupCache& neighbors)
600 {
601     using sdbusplus::xyz::openbmc_project::Network::server::Neighbor;
602     const auto state =
603         sdbusplus::xyz::openbmc_project::Network::server::convertForMessage(
604             Neighbor::State::Permanent);
605     for (const auto& [path, neighbor] : neighbors)
606     {
607         const auto& ipStr = std::get<std::string>(neighbor.at("IPAddress"));
608         auto neighIP = maybeStringToAddr<family>(ipStr.c_str());
609         if (!neighIP)
610         {
611             continue;
612         }
613         if (!equal(*neighIP, ip))
614         {
615             continue;
616         }
617         if (state != std::get<std::string>(neighbor.at("State")))
618         {
619             continue;
620         }
621 
622         IfNeigh<family> ret;
623         ret.path = path;
624         ret.ip = ip;
625         const auto& macStr = std::get<std::string>(neighbor.at("MACAddress"));
626         ret.mac = stringToMAC(macStr.c_str());
627         return ret;
628     }
629 
630     return std::nullopt;
631 }
632 
633 template <int family>
634 void createNeighbor(sdbusplus::bus_t& bus, const ChannelParams& params,
635                     const typename AddrFamily<family>::addr& address,
636                     const ether_addr& mac)
637 {
638     auto newreq =
639         bus.new_method_call(params.service.c_str(), params.logicalPath.c_str(),
640                             INTF_NEIGHBOR_CREATE_STATIC, "Neighbor");
641     std::string macStr = ether_ntoa(&mac);
642     newreq.append(addrToString<family>(address), macStr);
643     bus.call_noreply(newreq);
644 }
645 
646 /** @brief Deletes the dbus object. Ignores empty objects or objects that are
647  *         missing from the bus.
648  *
649  *  @param[in] bus     - The bus object used for lookups
650  *  @param[in] service - The name of the service
651  *  @param[in] path    - The path of the object to delete
652  */
653 void deleteObjectIfExists(sdbusplus::bus_t& bus, const std::string& service,
654                           const std::string& path);
655 
656 /** @brief Sets the value for the default gateway of the channel
657  *
658  *  @param[in] bus     - The bus object used for lookups
659  *  @param[in] params  - The parameters for the channel
660  *  @param[in] gateway - Gateway address to apply
661  */
662 template <int family>
663 void setGatewayProperty(sdbusplus::bus_t& bus, const ChannelParams& params,
664                         const typename AddrFamily<family>::addr& address)
665 {
666     // Save the old gateway MAC address if it exists so we can recreate it
667     auto gateway = getGatewayProperty<family>(bus, params);
668     std::optional<IfNeigh<family>> neighbor;
669     if (gateway)
670     {
671         ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
672         neighbor = findStaticNeighbor<family>(bus, params, *gateway, neighbors);
673     }
674 
675     auto objPath = "/xyz/openbmc_project/network/" + params.ifname;
676     setDbusProperty(bus, params.service, objPath, INTF_ETHERNET,
677                     AddrFamily<family>::propertyGateway,
678                     addrToString<family>(address));
679 
680     // Restore the gateway MAC if we had one
681     if (neighbor)
682     {
683         deleteObjectIfExists(bus, params.service, neighbor->path);
684         createNeighbor<family>(bus, params, address, neighbor->mac);
685     }
686 }
687 
688 /** @enum SolConfParam
689  *
690  *  using for Set/Get SOL configuration parameters command.
691  */
692 enum class SolConfParam : uint8_t
693 {
694     Progress,       //!< Set In Progress.
695     Enable,         //!< SOL Enable.
696     Authentication, //!< SOL Authentication.
697     Accumulate,     //!< Character Accumulate Interval & Send Threshold.
698     Retry,          //!< SOL Retry.
699     NonVbitrate,    //!< SOL non-volatile bit rate.
700     Vbitrate,       //!< SOL volatile bit rate.
701     Channel,        //!< SOL payload channel.
702     Port,           //!< SOL payload port.
703 };
704 
705 constexpr uint8_t ipmiCCParamNotSupported = 0x80;
706 constexpr uint8_t ipmiCCWriteReadParameter = 0x82;
707 
708 } // namespace transport
709 } // namespace ipmi
710