1690a2342SPatrick Venture #pragma once
2690a2342SPatrick Venture 
38a7236aeSJohn Wang #include "app/channel.hpp"
48a7236aeSJohn Wang #include "user_channel/cipher_mgmt.hpp"
58a7236aeSJohn Wang 
68a7236aeSJohn Wang #include <arpa/inet.h>
78a7236aeSJohn Wang #include <netinet/ether.h>
88a7236aeSJohn Wang 
98a7236aeSJohn Wang #include <array>
108a7236aeSJohn Wang #include <bitset>
118a7236aeSJohn Wang #include <cinttypes>
12690a2342SPatrick Venture #include <cstdint>
138a7236aeSJohn Wang #include <cstring>
148a7236aeSJohn Wang #include <fstream>
158a7236aeSJohn Wang #include <functional>
16690a2342SPatrick Venture #include <ipmid/api-types.hpp>
178a7236aeSJohn Wang #include <ipmid/api.hpp>
188a7236aeSJohn Wang #include <ipmid/message.hpp>
198a7236aeSJohn Wang #include <ipmid/message/types.hpp>
208a7236aeSJohn Wang #include <ipmid/types.hpp>
218a7236aeSJohn Wang #include <ipmid/utils.hpp>
228a7236aeSJohn Wang #include <optional>
238a7236aeSJohn Wang #include <phosphor-logging/elog-errors.hpp>
248a7236aeSJohn Wang #include <phosphor-logging/elog.hpp>
258a7236aeSJohn Wang #include <phosphor-logging/log.hpp>
268a7236aeSJohn Wang #include <sdbusplus/bus.hpp>
278a7236aeSJohn Wang #include <sdbusplus/exception.hpp>
288a7236aeSJohn Wang #include <string>
298a7236aeSJohn Wang #include <string_view>
308a7236aeSJohn Wang #include <type_traits>
318a7236aeSJohn Wang #include <unordered_map>
328a7236aeSJohn Wang #include <unordered_set>
338a7236aeSJohn Wang #include <user_channel/channel_layer.hpp>
348a7236aeSJohn Wang #include <utility>
358a7236aeSJohn Wang #include <vector>
368a7236aeSJohn Wang #include <xyz/openbmc_project/Common/error.hpp>
378a7236aeSJohn Wang #include <xyz/openbmc_project/Network/EthernetInterface/server.hpp>
388a7236aeSJohn Wang #include <xyz/openbmc_project/Network/IP/server.hpp>
398a7236aeSJohn Wang #include <xyz/openbmc_project/Network/Neighbor/server.hpp>
40690a2342SPatrick Venture 
41690a2342SPatrick Venture namespace ipmi
42690a2342SPatrick Venture {
43690a2342SPatrick Venture namespace transport
44690a2342SPatrick Venture {
45690a2342SPatrick Venture 
468a7236aeSJohn Wang // D-Bus Network Daemon definitions
478a7236aeSJohn Wang constexpr auto PATH_ROOT = "/xyz/openbmc_project/network";
488a7236aeSJohn Wang constexpr auto INTF_ETHERNET = "xyz.openbmc_project.Network.EthernetInterface";
498a7236aeSJohn Wang constexpr auto INTF_IP = "xyz.openbmc_project.Network.IP";
508a7236aeSJohn Wang constexpr auto INTF_IP_CREATE = "xyz.openbmc_project.Network.IP.Create";
518a7236aeSJohn Wang constexpr auto INTF_MAC = "xyz.openbmc_project.Network.MACAddress";
528a7236aeSJohn Wang constexpr auto INTF_NEIGHBOR = "xyz.openbmc_project.Network.Neighbor";
538a7236aeSJohn Wang constexpr auto INTF_NEIGHBOR_CREATE_STATIC =
548a7236aeSJohn Wang     "xyz.openbmc_project.Network.Neighbor.CreateStatic";
558a7236aeSJohn Wang constexpr auto INTF_VLAN = "xyz.openbmc_project.Network.VLAN";
568a7236aeSJohn Wang constexpr auto INTF_VLAN_CREATE = "xyz.openbmc_project.Network.VLAN.Create";
578a7236aeSJohn Wang 
58690a2342SPatrick Venture /** @brief IPMI LAN Parameters */
59690a2342SPatrick Venture enum class LanParam : uint8_t
60690a2342SPatrick Venture {
61690a2342SPatrick Venture     SetStatus = 0,
62690a2342SPatrick Venture     AuthSupport = 1,
63690a2342SPatrick Venture     AuthEnables = 2,
64690a2342SPatrick Venture     IP = 3,
65690a2342SPatrick Venture     IPSrc = 4,
66690a2342SPatrick Venture     MAC = 5,
67690a2342SPatrick Venture     SubnetMask = 6,
68690a2342SPatrick Venture     Gateway1 = 12,
69690a2342SPatrick Venture     Gateway1MAC = 13,
70690a2342SPatrick Venture     VLANId = 20,
71690a2342SPatrick Venture     CiphersuiteSupport = 22,
72690a2342SPatrick Venture     CiphersuiteEntries = 23,
73690a2342SPatrick Venture     cipherSuitePrivilegeLevels = 24,
74690a2342SPatrick Venture     IPFamilySupport = 50,
75690a2342SPatrick Venture     IPFamilyEnables = 51,
76690a2342SPatrick Venture     IPv6Status = 55,
77690a2342SPatrick Venture     IPv6StaticAddresses = 56,
78690a2342SPatrick Venture     IPv6DynamicAddresses = 59,
79690a2342SPatrick Venture     IPv6RouterControl = 64,
80690a2342SPatrick Venture     IPv6StaticRouter1IP = 65,
81690a2342SPatrick Venture     IPv6StaticRouter1MAC = 66,
82690a2342SPatrick Venture     IPv6StaticRouter1PrefixLength = 67,
83690a2342SPatrick Venture     IPv6StaticRouter1PrefixValue = 68,
84690a2342SPatrick Venture };
85690a2342SPatrick Venture 
86690a2342SPatrick Venture /** @brief IPMI IP Origin Types */
87690a2342SPatrick Venture enum class IPSrc : uint8_t
88690a2342SPatrick Venture {
89690a2342SPatrick Venture     Unspecified = 0,
90690a2342SPatrick Venture     Static = 1,
91690a2342SPatrick Venture     DHCP = 2,
92690a2342SPatrick Venture     BIOS = 3,
93690a2342SPatrick Venture     BMC = 4,
94690a2342SPatrick Venture };
95690a2342SPatrick Venture 
96690a2342SPatrick Venture /** @brief IPMI Set Status */
97690a2342SPatrick Venture enum class SetStatus : uint8_t
98690a2342SPatrick Venture {
99690a2342SPatrick Venture     Complete = 0,
100690a2342SPatrick Venture     InProgress = 1,
101690a2342SPatrick Venture     Commit = 2,
102690a2342SPatrick Venture };
103690a2342SPatrick Venture 
104690a2342SPatrick Venture /** @brief IPMI Family Suport Bits */
105690a2342SPatrick Venture namespace IPFamilySupportFlag
106690a2342SPatrick Venture {
107690a2342SPatrick Venture constexpr uint8_t IPv6Only = 0;
108690a2342SPatrick Venture constexpr uint8_t DualStack = 1;
109690a2342SPatrick Venture constexpr uint8_t IPv6Alerts = 2;
110690a2342SPatrick Venture } // namespace IPFamilySupportFlag
111690a2342SPatrick Venture 
112690a2342SPatrick Venture /** @brief IPMI IPFamily Enables Flag */
113690a2342SPatrick Venture enum class IPFamilyEnables : uint8_t
114690a2342SPatrick Venture {
115690a2342SPatrick Venture     IPv4Only = 0,
116690a2342SPatrick Venture     IPv6Only = 1,
117690a2342SPatrick Venture     DualStack = 2,
118690a2342SPatrick Venture };
119690a2342SPatrick Venture 
120690a2342SPatrick Venture /** @brief IPMI IPv6 Dyanmic Status Bits */
121690a2342SPatrick Venture namespace IPv6StatusFlag
122690a2342SPatrick Venture {
123690a2342SPatrick Venture constexpr uint8_t DHCP = 0;
124690a2342SPatrick Venture constexpr uint8_t SLAAC = 1;
125690a2342SPatrick Venture }; // namespace IPv6StatusFlag
126690a2342SPatrick Venture 
127690a2342SPatrick Venture /** @brief IPMI IPv6 Source */
128690a2342SPatrick Venture enum class IPv6Source : uint8_t
129690a2342SPatrick Venture {
130690a2342SPatrick Venture     Static = 0,
131690a2342SPatrick Venture     SLAAC = 1,
132690a2342SPatrick Venture     DHCP = 2,
133690a2342SPatrick Venture };
134690a2342SPatrick Venture 
135690a2342SPatrick Venture /** @brief IPMI IPv6 Address Status */
136690a2342SPatrick Venture enum class IPv6AddressStatus : uint8_t
137690a2342SPatrick Venture {
138690a2342SPatrick Venture     Active = 0,
139690a2342SPatrick Venture     Disabled = 1,
140690a2342SPatrick Venture };
141690a2342SPatrick Venture 
142690a2342SPatrick Venture namespace IPv6RouterControlFlag
143690a2342SPatrick Venture {
144690a2342SPatrick Venture constexpr uint8_t Static = 0;
145690a2342SPatrick Venture constexpr uint8_t Dynamic = 1;
146690a2342SPatrick Venture }; // namespace IPv6RouterControlFlag
147690a2342SPatrick Venture 
148690a2342SPatrick Venture // LAN Handler specific response codes
149690a2342SPatrick Venture constexpr Cc ccParamNotSupported = 0x80;
150690a2342SPatrick Venture constexpr Cc ccParamSetLocked = 0x81;
151690a2342SPatrick Venture constexpr Cc ccParamReadOnly = 0x82;
152690a2342SPatrick Venture 
153690a2342SPatrick Venture // VLANs are a 12-bit value
154690a2342SPatrick Venture constexpr uint16_t VLAN_VALUE_MASK = 0x0fff;
155690a2342SPatrick Venture constexpr uint16_t VLAN_ENABLE_FLAG = 0x8000;
156690a2342SPatrick Venture 
157690a2342SPatrick Venture // Arbitrary v6 Address Limits to prevent too much output in ipmitool
158690a2342SPatrick Venture constexpr uint8_t MAX_IPV6_STATIC_ADDRESSES = 15;
159690a2342SPatrick Venture constexpr uint8_t MAX_IPV6_DYNAMIC_ADDRESSES = 15;
160690a2342SPatrick Venture 
161*6d4a44edSJiaqing Zhao // Prefix length limits of phosphor-networkd
162*6d4a44edSJiaqing Zhao constexpr uint8_t MIN_IPV4_PREFIX_LENGTH = 1;
163*6d4a44edSJiaqing Zhao constexpr uint8_t MAX_IPV4_PREFIX_LENGTH = 32;
164*6d4a44edSJiaqing Zhao constexpr uint8_t MIN_IPV6_PREFIX_LENGTH = 1;
165*6d4a44edSJiaqing Zhao constexpr uint8_t MAX_IPV6_PREFIX_LENGTH = 128;
166*6d4a44edSJiaqing Zhao 
1678a7236aeSJohn Wang /** @brief The dbus parameters for the interface corresponding to a channel
1688a7236aeSJohn Wang  *         This helps reduce the number of mapper lookups we need for each
1698a7236aeSJohn Wang  *         query and simplifies finding the VLAN interface if needed.
1708a7236aeSJohn Wang  */
1718a7236aeSJohn Wang struct ChannelParams
1728a7236aeSJohn Wang {
1738a7236aeSJohn Wang     /** @brief The channel ID */
1748a7236aeSJohn Wang     int id;
1758a7236aeSJohn Wang     /** @brief channel name for the interface */
1768a7236aeSJohn Wang     std::string ifname;
1778a7236aeSJohn Wang     /** @brief Name of the service on the bus */
1788a7236aeSJohn Wang     std::string service;
1798a7236aeSJohn Wang     /** @brief Lower level adapter path that is guaranteed to not be a VLAN */
1808a7236aeSJohn Wang     std::string ifPath;
1818a7236aeSJohn Wang     /** @brief Logical adapter path used for address assignment */
1828a7236aeSJohn Wang     std::string logicalPath;
1838a7236aeSJohn Wang };
1848a7236aeSJohn Wang 
1858a7236aeSJohn Wang /** @brief A trivial helper used to determine if two PODs are equal
1868a7236aeSJohn Wang  *
1878a7236aeSJohn Wang  *  @params[in] a - The first object to compare
1888a7236aeSJohn Wang  *  @params[in] b - The second object to compare
1898a7236aeSJohn Wang  *  @return True if the objects are the same bytewise
1908a7236aeSJohn Wang  */
1918a7236aeSJohn Wang template <typename T>
1928a7236aeSJohn Wang bool equal(const T& a, const T& b)
1938a7236aeSJohn Wang {
1948a7236aeSJohn Wang     static_assert(std::is_trivially_copyable_v<T>);
1958a7236aeSJohn Wang     return std::memcmp(&a, &b, sizeof(T)) == 0;
1968a7236aeSJohn Wang }
1978a7236aeSJohn Wang 
1988a7236aeSJohn Wang /** @brief Copies bytes from an array into a trivially copyable container
1998a7236aeSJohn Wang  *
2008a7236aeSJohn Wang  *  @params[out] t     - The container receiving the data
2018a7236aeSJohn Wang  *  @params[in]  bytes - The data to copy
2028a7236aeSJohn Wang  */
2038a7236aeSJohn Wang template <size_t N, typename T>
2048a7236aeSJohn Wang void copyInto(T& t, const std::array<uint8_t, N>& bytes)
2058a7236aeSJohn Wang {
2068a7236aeSJohn Wang     static_assert(std::is_trivially_copyable_v<T>);
2078a7236aeSJohn Wang     static_assert(N == sizeof(T));
2088a7236aeSJohn Wang     std::memcpy(&t, bytes.data(), bytes.size());
2098a7236aeSJohn Wang }
2108a7236aeSJohn Wang 
2118a7236aeSJohn Wang /** @brief Gets a generic view of the bytes in the input container
2128a7236aeSJohn Wang  *
2138a7236aeSJohn Wang  *  @params[in] t - The data to reference
2148a7236aeSJohn Wang  *  @return A string_view referencing the bytes in the container
2158a7236aeSJohn Wang  */
2168a7236aeSJohn Wang template <typename T>
2178a7236aeSJohn Wang std::string_view dataRef(const T& t)
2188a7236aeSJohn Wang {
2198a7236aeSJohn Wang     static_assert(std::is_trivially_copyable_v<T>);
2208a7236aeSJohn Wang     return {reinterpret_cast<const char*>(&t), sizeof(T)};
2218a7236aeSJohn Wang }
2228a7236aeSJohn Wang 
2238a7236aeSJohn Wang /** @brief Determines the ethernet interface name corresponding to a channel
2248a7236aeSJohn Wang  *         Tries to map a VLAN object first so that the address information
2258a7236aeSJohn Wang  *         is accurate. Otherwise it gets the standard ethernet interface.
2268a7236aeSJohn Wang  *
2278a7236aeSJohn Wang  *  @param[in] bus     - The bus object used for lookups
2288a7236aeSJohn Wang  *  @param[in] channel - The channel id corresponding to an ethernet interface
2298a7236aeSJohn Wang  *  @return Ethernet interface service and object path if it exists
2308a7236aeSJohn Wang  */
2318a7236aeSJohn Wang std::optional<ChannelParams> maybeGetChannelParams(sdbusplus::bus::bus& bus,
2328a7236aeSJohn Wang                                                    uint8_t channel);
2338a7236aeSJohn Wang 
2348a7236aeSJohn Wang /** @brief A trivial helper around maybeGetChannelParams() that throws an
2358a7236aeSJohn Wang  *         exception when it is unable to acquire parameters for the channel.
2368a7236aeSJohn Wang  *
2378a7236aeSJohn Wang  *  @param[in] bus     - The bus object used for lookups
2388a7236aeSJohn Wang  *  @param[in] channel - The channel id corresponding to an ethernet interface
2398a7236aeSJohn Wang  *  @return Ethernet interface service and object path
2408a7236aeSJohn Wang  */
2418a7236aeSJohn Wang ChannelParams getChannelParams(sdbusplus::bus::bus& bus, uint8_t channel);
2428a7236aeSJohn Wang 
2438a7236aeSJohn Wang /** @brief Trivializes using parameter getter functions by providing a bus
2448a7236aeSJohn Wang  *         and channel parameters automatically.
2458a7236aeSJohn Wang  *
2468a7236aeSJohn Wang  *  @param[in] channel - The channel id corresponding to an ethernet interface
2478a7236aeSJohn Wang  *  ...
2488a7236aeSJohn Wang  */
2498a7236aeSJohn Wang template <auto func, typename... Args>
2508a7236aeSJohn Wang auto channelCall(uint8_t channel, Args&&... args)
2518a7236aeSJohn Wang {
2528a7236aeSJohn Wang     sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
2538a7236aeSJohn Wang     auto params = getChannelParams(bus, channel);
2548a7236aeSJohn Wang     return std::invoke(func, bus, params, std::forward<Args>(args)...);
2558a7236aeSJohn Wang }
2568a7236aeSJohn Wang 
2578a7236aeSJohn Wang /** @brief Generic paramters for different address families */
2588a7236aeSJohn Wang template <int family>
2598a7236aeSJohn Wang struct AddrFamily
2608a7236aeSJohn Wang {
2618a7236aeSJohn Wang };
2628a7236aeSJohn Wang 
2638a7236aeSJohn Wang /** @brief Parameter specialization for IPv4 */
2648a7236aeSJohn Wang template <>
2658a7236aeSJohn Wang struct AddrFamily<AF_INET>
2668a7236aeSJohn Wang {
2678a7236aeSJohn Wang     using addr = in_addr;
2688a7236aeSJohn Wang     static constexpr auto protocol =
2698a7236aeSJohn Wang         sdbusplus::xyz::openbmc_project::Network::server::IP::Protocol::IPv4;
2708a7236aeSJohn Wang     static constexpr size_t maxStrLen = INET6_ADDRSTRLEN;
2718a7236aeSJohn Wang     static constexpr uint8_t defaultPrefix = 32;
2728a7236aeSJohn Wang     static constexpr char propertyGateway[] = "DefaultGateway";
2738a7236aeSJohn Wang };
2748a7236aeSJohn Wang 
2758a7236aeSJohn Wang /** @brief Parameter specialization for IPv6 */
2768a7236aeSJohn Wang template <>
2778a7236aeSJohn Wang struct AddrFamily<AF_INET6>
2788a7236aeSJohn Wang {
2798a7236aeSJohn Wang     using addr = in6_addr;
2808a7236aeSJohn Wang     static constexpr auto protocol =
2818a7236aeSJohn Wang         sdbusplus::xyz::openbmc_project::Network::server::IP::Protocol::IPv6;
2828a7236aeSJohn Wang     static constexpr size_t maxStrLen = INET6_ADDRSTRLEN;
2838a7236aeSJohn Wang     static constexpr uint8_t defaultPrefix = 128;
2848a7236aeSJohn Wang     static constexpr char propertyGateway[] = "DefaultGateway6";
2858a7236aeSJohn Wang };
2868a7236aeSJohn Wang 
2878a7236aeSJohn Wang /** @brief Interface Neighbor configuration parameters */
2888a7236aeSJohn Wang template <int family>
2898a7236aeSJohn Wang struct IfNeigh
2908a7236aeSJohn Wang {
2918a7236aeSJohn Wang     std::string path;
2928a7236aeSJohn Wang     typename AddrFamily<family>::addr ip;
2938a7236aeSJohn Wang     ether_addr mac;
2948a7236aeSJohn Wang };
2958a7236aeSJohn Wang 
2968a7236aeSJohn Wang /** @brief Interface IP Address configuration parameters */
2978a7236aeSJohn Wang template <int family>
2988a7236aeSJohn Wang struct IfAddr
2998a7236aeSJohn Wang {
3008a7236aeSJohn Wang     std::string path;
3018a7236aeSJohn Wang     typename AddrFamily<family>::addr address;
3028a7236aeSJohn Wang     sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin origin;
3038a7236aeSJohn Wang     uint8_t prefix;
3048a7236aeSJohn Wang };
3058a7236aeSJohn Wang 
3068a7236aeSJohn Wang /** @brief Valid address origins for IPv6 */
3078a7236aeSJohn Wang static inline const std::unordered_set<
3088a7236aeSJohn Wang     sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin>
3098a7236aeSJohn Wang     originsV6Static = {sdbusplus::xyz::openbmc_project::Network::server::IP::
3108a7236aeSJohn Wang                            AddressOrigin::Static};
3118a7236aeSJohn Wang static inline const std::unordered_set<
3128a7236aeSJohn Wang     sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin>
3138a7236aeSJohn Wang     originsV6Dynamic = {
3148a7236aeSJohn Wang         sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin::
3158a7236aeSJohn Wang             DHCP,
3168a7236aeSJohn Wang         sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin::
3178a7236aeSJohn Wang             SLAAC,
3188a7236aeSJohn Wang };
3198a7236aeSJohn Wang 
3208a7236aeSJohn Wang /** @brief A lazy lookup mechanism for iterating over object properties stored
3218a7236aeSJohn Wang  *         in DBus. This will only perform the object lookup when needed, and
3228a7236aeSJohn Wang  *         retains a cache of previous lookups to speed up future iterations.
3238a7236aeSJohn Wang  */
3248a7236aeSJohn Wang class ObjectLookupCache
3258a7236aeSJohn Wang {
3268a7236aeSJohn Wang   public:
3278a7236aeSJohn Wang     using PropertiesCache = std::unordered_map<std::string, PropertyMap>;
3288a7236aeSJohn Wang 
3298a7236aeSJohn Wang     /** @brief Creates a new ObjectLookupCache for the interface on the bus
3308a7236aeSJohn Wang      *         NOTE: The inputs to this object must outlive the object since
3318a7236aeSJohn Wang      *         they are only referenced by it.
3328a7236aeSJohn Wang      *
3338a7236aeSJohn Wang      *  @param[in] bus    - The bus object used for lookups
3348a7236aeSJohn Wang      *  @param[in] params - The parameters for the channel
3358a7236aeSJohn Wang      *  @param[in] intf   - The interface we are looking up
3368a7236aeSJohn Wang      */
3378a7236aeSJohn Wang     ObjectLookupCache(sdbusplus::bus::bus& bus, const ChannelParams& params,
3388a7236aeSJohn Wang                       const char* intf) :
3398a7236aeSJohn Wang         bus(bus),
3408a7236aeSJohn Wang         params(params), intf(intf),
3418a7236aeSJohn Wang         objs(getAllDbusObjects(bus, params.logicalPath, intf, ""))
3428a7236aeSJohn Wang     {
3438a7236aeSJohn Wang     }
3448a7236aeSJohn Wang 
3458a7236aeSJohn Wang     class iterator : public ObjectTree::const_iterator
3468a7236aeSJohn Wang     {
3478a7236aeSJohn Wang       public:
3488a7236aeSJohn Wang         using value_type = PropertiesCache::value_type;
3498a7236aeSJohn Wang 
3508a7236aeSJohn Wang         iterator(ObjectTree::const_iterator it, ObjectLookupCache& container) :
3518a7236aeSJohn Wang             ObjectTree::const_iterator(it), container(container),
3528a7236aeSJohn Wang             ret(container.cache.end())
3538a7236aeSJohn Wang         {
3548a7236aeSJohn Wang         }
3558a7236aeSJohn Wang         value_type& operator*()
3568a7236aeSJohn Wang         {
3578a7236aeSJohn Wang             ret = container.get(ObjectTree::const_iterator::operator*().first);
3588a7236aeSJohn Wang             return *ret;
3598a7236aeSJohn Wang         }
3608a7236aeSJohn Wang         value_type* operator->()
3618a7236aeSJohn Wang         {
3628a7236aeSJohn Wang             return &operator*();
3638a7236aeSJohn Wang         }
3648a7236aeSJohn Wang 
3658a7236aeSJohn Wang       private:
3668a7236aeSJohn Wang         ObjectLookupCache& container;
3678a7236aeSJohn Wang         PropertiesCache::iterator ret;
3688a7236aeSJohn Wang     };
3698a7236aeSJohn Wang 
3708a7236aeSJohn Wang     iterator begin() noexcept
3718a7236aeSJohn Wang     {
3728a7236aeSJohn Wang         return iterator(objs.begin(), *this);
3738a7236aeSJohn Wang     }
3748a7236aeSJohn Wang 
3758a7236aeSJohn Wang     iterator end() noexcept
3768a7236aeSJohn Wang     {
3778a7236aeSJohn Wang         return iterator(objs.end(), *this);
3788a7236aeSJohn Wang     }
3798a7236aeSJohn Wang 
3808a7236aeSJohn Wang   private:
3818a7236aeSJohn Wang     sdbusplus::bus::bus& bus;
3828a7236aeSJohn Wang     const ChannelParams& params;
3838a7236aeSJohn Wang     const char* const intf;
3848a7236aeSJohn Wang     const ObjectTree objs;
3858a7236aeSJohn Wang     PropertiesCache cache;
3868a7236aeSJohn Wang 
3878a7236aeSJohn Wang     /** @brief Gets a cached copy of the object properties if possible
3888a7236aeSJohn Wang      *         Otherwise performs a query on DBus to look them up
3898a7236aeSJohn Wang      *
3908a7236aeSJohn Wang      *  @param[in] path - The object path to lookup
3918a7236aeSJohn Wang      *  @return An iterator for the specified object path + properties
3928a7236aeSJohn Wang      */
3938a7236aeSJohn Wang     PropertiesCache::iterator get(const std::string& path)
3948a7236aeSJohn Wang     {
3958a7236aeSJohn Wang         auto it = cache.find(path);
3968a7236aeSJohn Wang         if (it != cache.end())
3978a7236aeSJohn Wang         {
3988a7236aeSJohn Wang             return it;
3998a7236aeSJohn Wang         }
4008a7236aeSJohn Wang         auto properties = getAllDbusProperties(bus, params.service, path, intf);
4018a7236aeSJohn Wang         return cache.insert({path, std::move(properties)}).first;
4028a7236aeSJohn Wang     }
4038a7236aeSJohn Wang };
4048a7236aeSJohn Wang 
4058a7236aeSJohn Wang /** @brief Turns an IP address string into the network byte order form
4068a7236aeSJohn Wang  *         NOTE: This version strictly validates family matches
4078a7236aeSJohn Wang  *
4088a7236aeSJohn Wang  *  @param[in] address - The string form of the address
4098a7236aeSJohn Wang  *  @return A network byte order address or none if conversion failed
4108a7236aeSJohn Wang  */
4118a7236aeSJohn Wang template <int family>
4128a7236aeSJohn Wang std::optional<typename AddrFamily<family>::addr>
4138a7236aeSJohn Wang     maybeStringToAddr(const char* address)
4148a7236aeSJohn Wang {
4158a7236aeSJohn Wang     typename AddrFamily<family>::addr ret;
4168a7236aeSJohn Wang     if (inet_pton(family, address, &ret) == 1)
4178a7236aeSJohn Wang     {
4188a7236aeSJohn Wang         return ret;
4198a7236aeSJohn Wang     }
4208a7236aeSJohn Wang     return std::nullopt;
4218a7236aeSJohn Wang }
4228a7236aeSJohn Wang 
4238a7236aeSJohn Wang /** @brief Turns an IP address string into the network byte order form
4248a7236aeSJohn Wang  *         NOTE: This version strictly validates family matches
4258a7236aeSJohn Wang  *
4268a7236aeSJohn Wang  *  @param[in] address - The string form of the address
4278a7236aeSJohn Wang  *  @return A network byte order address
4288a7236aeSJohn Wang  */
4298a7236aeSJohn Wang template <int family>
4308a7236aeSJohn Wang typename AddrFamily<family>::addr stringToAddr(const char* address)
4318a7236aeSJohn Wang {
4328a7236aeSJohn Wang     auto ret = maybeStringToAddr<family>(address);
4338a7236aeSJohn Wang     if (!ret)
4348a7236aeSJohn Wang     {
4358a7236aeSJohn Wang         phosphor::logging::log<phosphor::logging::level::ERR>(
4368a7236aeSJohn Wang             "Failed to convert IP Address",
4378a7236aeSJohn Wang             phosphor::logging::entry("FAMILY=%d", family),
4388a7236aeSJohn Wang             phosphor::logging::entry("ADDRESS=%s", address));
4398a7236aeSJohn Wang         phosphor::logging::elog<
4408a7236aeSJohn Wang             sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure>();
4418a7236aeSJohn Wang     }
4428a7236aeSJohn Wang     return *ret;
4438a7236aeSJohn Wang }
4448a7236aeSJohn Wang 
4458a7236aeSJohn Wang /** @brief Turns an IP address in network byte order into a string
4468a7236aeSJohn Wang  *
4478a7236aeSJohn Wang  *  @param[in] address - The string form of the address
4488a7236aeSJohn Wang  *  @return A network byte order address
4498a7236aeSJohn Wang  */
4508a7236aeSJohn Wang template <int family>
4518a7236aeSJohn Wang std::string addrToString(const typename AddrFamily<family>::addr& address)
4528a7236aeSJohn Wang {
4538a7236aeSJohn Wang     std::string ret(AddrFamily<family>::maxStrLen, '\0');
4548a7236aeSJohn Wang     inet_ntop(family, &address, ret.data(), ret.size());
4558a7236aeSJohn Wang     ret.resize(strlen(ret.c_str()));
4568a7236aeSJohn Wang     return ret;
4578a7236aeSJohn Wang }
4588a7236aeSJohn Wang 
4598a7236aeSJohn Wang /** @brief Converts a human readable MAC string into MAC bytes
4608a7236aeSJohn Wang  *
4618a7236aeSJohn Wang  *  @param[in] mac - The MAC string
4628a7236aeSJohn Wang  *  @return MAC in bytes
4638a7236aeSJohn Wang  */
4648a7236aeSJohn Wang ether_addr stringToMAC(const char* mac);
4658a7236aeSJohn Wang /** @brief Searches the ip object lookup cache for an address matching
4668a7236aeSJohn Wang  *         the input parameters. NOTE: The index lacks stability across address
4678a7236aeSJohn Wang  *         changes since the network daemon has no notion of stable indicies.
4688a7236aeSJohn Wang  *
4698a7236aeSJohn Wang  *  @param[in] bus     - The bus object used for lookups
4708a7236aeSJohn Wang  *  @param[in] params  - The parameters for the channel
4718a7236aeSJohn Wang  *  @param[in] idx     - The index of the desired address on the interface
4728a7236aeSJohn Wang  *  @param[in] origins - The allowed origins for the address objects
4738a7236aeSJohn Wang  *  @param[in] ips     - The object lookup cache holding all of the address info
4748a7236aeSJohn Wang  *  @return The address and prefix if it was found
4758a7236aeSJohn Wang  */
4768a7236aeSJohn Wang template <int family>
4778a7236aeSJohn Wang std::optional<IfAddr<family>> findIfAddr(
4788a7236aeSJohn Wang     sdbusplus::bus::bus& bus, const ChannelParams& params, uint8_t idx,
4798a7236aeSJohn Wang     const std::unordered_set<
4808a7236aeSJohn Wang         sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin>&
4818a7236aeSJohn Wang         origins,
4828a7236aeSJohn Wang     ObjectLookupCache& ips)
4838a7236aeSJohn Wang {
4848a7236aeSJohn Wang     for (const auto& [path, properties] : ips)
4858a7236aeSJohn Wang     {
4868a7236aeSJohn Wang         const auto& addrStr = std::get<std::string>(properties.at("Address"));
4878a7236aeSJohn Wang         auto addr = maybeStringToAddr<family>(addrStr.c_str());
4888a7236aeSJohn Wang         if (!addr)
4898a7236aeSJohn Wang         {
4908a7236aeSJohn Wang             continue;
4918a7236aeSJohn Wang         }
4928a7236aeSJohn Wang 
4938a7236aeSJohn Wang         sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin
4948a7236aeSJohn Wang             origin = sdbusplus::xyz::openbmc_project::Network::server::IP::
4958a7236aeSJohn Wang                 convertAddressOriginFromString(
4968a7236aeSJohn Wang                     std::get<std::string>(properties.at("Origin")));
4978a7236aeSJohn Wang         if (origins.find(origin) == origins.end())
4988a7236aeSJohn Wang         {
4998a7236aeSJohn Wang             continue;
5008a7236aeSJohn Wang         }
5018a7236aeSJohn Wang 
5028a7236aeSJohn Wang         if (idx > 0)
5038a7236aeSJohn Wang         {
5048a7236aeSJohn Wang             idx--;
5058a7236aeSJohn Wang             continue;
5068a7236aeSJohn Wang         }
5078a7236aeSJohn Wang 
5088a7236aeSJohn Wang         IfAddr<family> ifaddr;
5098a7236aeSJohn Wang         ifaddr.path = path;
5108a7236aeSJohn Wang         ifaddr.address = *addr;
5118a7236aeSJohn Wang         ifaddr.prefix = std::get<uint8_t>(properties.at("PrefixLength"));
5128a7236aeSJohn Wang         ifaddr.origin = origin;
5138a7236aeSJohn Wang         return std::move(ifaddr);
5148a7236aeSJohn Wang     }
5158a7236aeSJohn Wang 
5168a7236aeSJohn Wang     return std::nullopt;
5178a7236aeSJohn Wang }
5188a7236aeSJohn Wang /** @brief Trivial helper around findIfAddr that simplifies calls
5198a7236aeSJohn Wang  *         for one off lookups. Don't use this if you intend to do multiple
5208a7236aeSJohn Wang  *         lookups at a time.
5218a7236aeSJohn Wang  *
5228a7236aeSJohn Wang  *  @param[in] bus     - The bus object used for lookups
5238a7236aeSJohn Wang  *  @param[in] params  - The parameters for the channel
5248a7236aeSJohn Wang  *  @param[in] idx     - The index of the desired address on the interface
5258a7236aeSJohn Wang  *  @param[in] origins - The allowed origins for the address objects
5268a7236aeSJohn Wang  *  @return The address and prefix if it was found
5278a7236aeSJohn Wang  */
5288a7236aeSJohn Wang template <int family>
5298a7236aeSJohn Wang auto getIfAddr(
5308a7236aeSJohn Wang     sdbusplus::bus::bus& bus, const ChannelParams& params, uint8_t idx,
5318a7236aeSJohn Wang     const std::unordered_set<
5328a7236aeSJohn Wang         sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin>&
5338a7236aeSJohn Wang         origins)
5348a7236aeSJohn Wang {
5358a7236aeSJohn Wang     ObjectLookupCache ips(bus, params, INTF_IP);
5368a7236aeSJohn Wang     return findIfAddr<family>(bus, params, idx, origins, ips);
5378a7236aeSJohn Wang }
5388a7236aeSJohn Wang 
5398a7236aeSJohn Wang /** @brief Determines if the ethernet interface is using DHCP
5408a7236aeSJohn Wang  *
5418a7236aeSJohn Wang  *  @param[in] bus    - The bus object used for lookups
5428a7236aeSJohn Wang  *  @param[in] params - The parameters for the channel
5438a7236aeSJohn Wang  *  @return DHCPConf enumeration
5448a7236aeSJohn Wang  */
5458a7236aeSJohn Wang sdbusplus::xyz::openbmc_project::Network::server::EthernetInterface::DHCPConf
5468a7236aeSJohn Wang     getDHCPProperty(sdbusplus::bus::bus& bus, const ChannelParams& params);
5478a7236aeSJohn Wang 
5488a7236aeSJohn Wang /** @brief Sets the DHCP v6 state on the given interface
5498a7236aeSJohn Wang  *
5508a7236aeSJohn Wang  *  @param[in] bus           - The bus object used for lookups
5518a7236aeSJohn Wang  *  @param[in] params        - The parameters for the channel
5528a7236aeSJohn Wang  *  @param[in] requestedDhcp - DHCP state to assign (none, v6, both)
5538a7236aeSJohn Wang  *  @param[in] defaultMode   - True: Use algorithmic assignment
5548a7236aeSJohn Wang  *                             False: requestedDhcp assigned unconditionally
5558a7236aeSJohn Wang  */
5568a7236aeSJohn Wang void setDHCPv6Property(sdbusplus::bus::bus& bus, const ChannelParams& params,
5578a7236aeSJohn Wang                        const sdbusplus::xyz::openbmc_project::Network::server::
5588a7236aeSJohn Wang                            EthernetInterface::DHCPConf requestedDhcp,
5598a7236aeSJohn Wang                        const bool defaultMode);
5608a7236aeSJohn Wang 
5618a7236aeSJohn Wang /** @brief Reconfigures the IPv6 address info configured for the interface
5628a7236aeSJohn Wang  *
5638a7236aeSJohn Wang  *  @param[in] bus     - The bus object used for lookups
5648a7236aeSJohn Wang  *  @param[in] params  - The parameters for the channel
5658a7236aeSJohn Wang  *  @param[in] idx     - The address index to operate on
5668a7236aeSJohn Wang  *  @param[in] address - The new address
5678a7236aeSJohn Wang  *  @param[in] prefix  - The new address prefix
5688a7236aeSJohn Wang  */
5698a7236aeSJohn Wang void reconfigureIfAddr6(sdbusplus::bus::bus& bus, const ChannelParams& params,
5708a7236aeSJohn Wang                         uint8_t idx, const in6_addr& address, uint8_t prefix);
5718a7236aeSJohn Wang 
5728a7236aeSJohn Wang /** @brief Retrieves the current gateway for the address family on the system
573d1bd8c48SLei YU  *         NOTE: The gateway is per channel instead of the system wide one.
5748a7236aeSJohn Wang  *
5758a7236aeSJohn Wang  *  @param[in] bus    - The bus object used for lookups
5768a7236aeSJohn Wang  *  @param[in] params - The parameters for the channel
5778a7236aeSJohn Wang  *  @return An address representing the gateway address if it exists
5788a7236aeSJohn Wang  */
5798a7236aeSJohn Wang template <int family>
5808a7236aeSJohn Wang std::optional<typename AddrFamily<family>::addr>
5818a7236aeSJohn Wang     getGatewayProperty(sdbusplus::bus::bus& bus, const ChannelParams& params)
5828a7236aeSJohn Wang {
583d1bd8c48SLei YU     auto objPath = "/xyz/openbmc_project/network/" + params.ifname;
584d1bd8c48SLei YU     auto gatewayStr = std::get<std::string>(
585d1bd8c48SLei YU         getDbusProperty(bus, params.service, objPath, INTF_ETHERNET,
5868a7236aeSJohn Wang                         AddrFamily<family>::propertyGateway));
5878a7236aeSJohn Wang     if (gatewayStr.empty())
5888a7236aeSJohn Wang     {
5898a7236aeSJohn Wang         return std::nullopt;
5908a7236aeSJohn Wang     }
5918a7236aeSJohn Wang     return stringToAddr<family>(gatewayStr.c_str());
5928a7236aeSJohn Wang }
5938a7236aeSJohn Wang 
5948a7236aeSJohn Wang template <int family>
5958a7236aeSJohn Wang std::optional<IfNeigh<family>>
5968a7236aeSJohn Wang     findStaticNeighbor(sdbusplus::bus::bus& bus, const ChannelParams& params,
5978a7236aeSJohn Wang                        const typename AddrFamily<family>::addr& ip,
5988a7236aeSJohn Wang                        ObjectLookupCache& neighbors)
5998a7236aeSJohn Wang {
6008a7236aeSJohn Wang     using sdbusplus::xyz::openbmc_project::Network::server::Neighbor;
6018a7236aeSJohn Wang     const auto state =
6028a7236aeSJohn Wang         sdbusplus::xyz::openbmc_project::Network::server::convertForMessage(
6038a7236aeSJohn Wang             Neighbor::State::Permanent);
6048a7236aeSJohn Wang     for (const auto& [path, neighbor] : neighbors)
6058a7236aeSJohn Wang     {
6068a7236aeSJohn Wang         const auto& ipStr = std::get<std::string>(neighbor.at("IPAddress"));
6078a7236aeSJohn Wang         auto neighIP = maybeStringToAddr<family>(ipStr.c_str());
6088a7236aeSJohn Wang         if (!neighIP)
6098a7236aeSJohn Wang         {
6108a7236aeSJohn Wang             continue;
6118a7236aeSJohn Wang         }
6128a7236aeSJohn Wang         if (!equal(*neighIP, ip))
6138a7236aeSJohn Wang         {
6148a7236aeSJohn Wang             continue;
6158a7236aeSJohn Wang         }
6168a7236aeSJohn Wang         if (state != std::get<std::string>(neighbor.at("State")))
6178a7236aeSJohn Wang         {
6188a7236aeSJohn Wang             continue;
6198a7236aeSJohn Wang         }
6208a7236aeSJohn Wang 
6218a7236aeSJohn Wang         IfNeigh<family> ret;
6228a7236aeSJohn Wang         ret.path = path;
6238a7236aeSJohn Wang         ret.ip = ip;
6248a7236aeSJohn Wang         const auto& macStr = std::get<std::string>(neighbor.at("MACAddress"));
6258a7236aeSJohn Wang         ret.mac = stringToMAC(macStr.c_str());
6268a7236aeSJohn Wang         return std::move(ret);
6278a7236aeSJohn Wang     }
6288a7236aeSJohn Wang 
6298a7236aeSJohn Wang     return std::nullopt;
6308a7236aeSJohn Wang }
6318a7236aeSJohn Wang 
6328a7236aeSJohn Wang template <int family>
6338a7236aeSJohn Wang void createNeighbor(sdbusplus::bus::bus& bus, const ChannelParams& params,
6348a7236aeSJohn Wang                     const typename AddrFamily<family>::addr& address,
6358a7236aeSJohn Wang                     const ether_addr& mac)
6368a7236aeSJohn Wang {
6378a7236aeSJohn Wang     auto newreq =
6388a7236aeSJohn Wang         bus.new_method_call(params.service.c_str(), params.logicalPath.c_str(),
6398a7236aeSJohn Wang                             INTF_NEIGHBOR_CREATE_STATIC, "Neighbor");
6408a7236aeSJohn Wang     std::string macStr = ether_ntoa(&mac);
6418a7236aeSJohn Wang     newreq.append(addrToString<family>(address), macStr);
6428a7236aeSJohn Wang     bus.call_noreply(newreq);
6438a7236aeSJohn Wang }
6448a7236aeSJohn Wang 
6458a7236aeSJohn Wang /** @brief Deletes the dbus object. Ignores empty objects or objects that are
6468a7236aeSJohn Wang  *         missing from the bus.
6478a7236aeSJohn Wang  *
6488a7236aeSJohn Wang  *  @param[in] bus     - The bus object used for lookups
6498a7236aeSJohn Wang  *  @param[in] service - The name of the service
6508a7236aeSJohn Wang  *  @param[in] path    - The path of the object to delete
6518a7236aeSJohn Wang  */
6528a7236aeSJohn Wang void deleteObjectIfExists(sdbusplus::bus::bus& bus, const std::string& service,
6538a7236aeSJohn Wang                           const std::string& path);
6548a7236aeSJohn Wang 
655d1bd8c48SLei YU /** @brief Sets the value for the default gateway of the channel
6568a7236aeSJohn Wang  *
6578a7236aeSJohn Wang  *  @param[in] bus     - The bus object used for lookups
6588a7236aeSJohn Wang  *  @param[in] params  - The parameters for the channel
6598a7236aeSJohn Wang  *  @param[in] gateway - Gateway address to apply
6608a7236aeSJohn Wang  */
6618a7236aeSJohn Wang template <int family>
6628a7236aeSJohn Wang void setGatewayProperty(sdbusplus::bus::bus& bus, const ChannelParams& params,
6638a7236aeSJohn Wang                         const typename AddrFamily<family>::addr& address)
6648a7236aeSJohn Wang {
6658a7236aeSJohn Wang     // Save the old gateway MAC address if it exists so we can recreate it
6668a7236aeSJohn Wang     auto gateway = getGatewayProperty<family>(bus, params);
6678a7236aeSJohn Wang     std::optional<IfNeigh<family>> neighbor;
6688a7236aeSJohn Wang     if (gateway)
6698a7236aeSJohn Wang     {
6708a7236aeSJohn Wang         ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
6718a7236aeSJohn Wang         neighbor = findStaticNeighbor<family>(bus, params, *gateway, neighbors);
6728a7236aeSJohn Wang     }
6738a7236aeSJohn Wang 
674d1bd8c48SLei YU     auto objPath = "/xyz/openbmc_project/network/" + params.ifname;
675d1bd8c48SLei YU     setDbusProperty(bus, params.service, objPath, INTF_ETHERNET,
6768a7236aeSJohn Wang                     AddrFamily<family>::propertyGateway,
6778a7236aeSJohn Wang                     addrToString<family>(address));
6788a7236aeSJohn Wang 
6798a7236aeSJohn Wang     // Restore the gateway MAC if we had one
6808a7236aeSJohn Wang     if (neighbor)
6818a7236aeSJohn Wang     {
6828a7236aeSJohn Wang         deleteObjectIfExists(bus, params.service, neighbor->path);
6838a7236aeSJohn Wang         createNeighbor<family>(bus, params, address, neighbor->mac);
6848a7236aeSJohn Wang     }
6858a7236aeSJohn Wang }
6868a7236aeSJohn Wang 
68723f44657SJian Zhang /** @enum SolConfParam
68823f44657SJian Zhang  *
68923f44657SJian Zhang  *  using for Set/Get SOL configuration parameters command.
69023f44657SJian Zhang  */
69123f44657SJian Zhang enum class SolConfParam : uint8_t
69223f44657SJian Zhang {
69323f44657SJian Zhang     Progress,       //!< Set In Progress.
69423f44657SJian Zhang     Enable,         //!< SOL Enable.
69523f44657SJian Zhang     Authentication, //!< SOL Authentication.
69623f44657SJian Zhang     Accumulate,     //!< Character Accumulate Interval & Send Threshold.
69723f44657SJian Zhang     Retry,          //!< SOL Retry.
69823f44657SJian Zhang     NonVbitrate,    //!< SOL non-volatile bit rate.
69923f44657SJian Zhang     Vbitrate,       //!< SOL volatile bit rate.
70023f44657SJian Zhang     Channel,        //!< SOL payload channel.
70123f44657SJian Zhang     Port,           //!< SOL payload port.
70223f44657SJian Zhang };
70323f44657SJian Zhang 
70423f44657SJian Zhang constexpr uint8_t ipmiCCParamNotSupported = 0x80;
70523f44657SJian Zhang constexpr uint8_t ipmiCCWriteReadParameter = 0x82;
70623f44657SJian Zhang 
707690a2342SPatrick Venture } // namespace transport
708690a2342SPatrick Venture } // namespace ipmi
709