diff options
Diffstat (limited to 'transporthandler.cpp')
-rw-r--r-- | transporthandler.cpp | 400 |
1 files changed, 400 insertions, 0 deletions
diff --git a/transporthandler.cpp b/transporthandler.cpp index 61065ad..1a06ae5 100644 --- a/transporthandler.cpp +++ b/transporthandler.cpp @@ -89,6 +89,10 @@ constexpr Cc ccParamReadOnly = 0x82; constexpr uint16_t VLAN_VALUE_MASK = 0x0fff; constexpr uint16_t VLAN_ENABLE_FLAG = 0x8000; +// Arbitrary v6 Address Limits to prevent too much output in ipmitool +constexpr uint8_t MAX_IPV6_STATIC_ADDRESSES = 15; +constexpr uint8_t MAX_IPV6_DYNAMIC_ADDRESSES = 15; + // D-Bus Network Daemon definitions constexpr auto PATH_ROOT = "/xyz/openbmc_project/network"; constexpr auto PATH_SYSTEMCONFIG = "/xyz/openbmc_project/network/config"; @@ -122,12 +126,31 @@ struct AddrFamily<AF_INET> static constexpr char propertyGateway[] = "DefaultGateway"; }; +/** @brief Parameter specialization for IPv6 */ +template <> +struct AddrFamily<AF_INET6> +{ + using addr = in6_addr; + static constexpr auto protocol = IP::Protocol::IPv6; + static constexpr size_t maxStrLen = INET6_ADDRSTRLEN; + static constexpr uint8_t defaultPrefix = 128; + static constexpr char propertyGateway[] = "DefaultGateway6"; +}; + /** @brief Valid address origins for IPv4 */ const std::unordered_set<IP::AddressOrigin> originsV4 = { IP::AddressOrigin::Static, IP::AddressOrigin::DHCP, }; +/** @brief Valid address origins for IPv6 */ +const std::unordered_set<IP::AddressOrigin> originsV6Static = { + IP::AddressOrigin::Static}; +const std::unordered_set<IP::AddressOrigin> originsV6Dynamic = { + IP::AddressOrigin::DHCP, + IP::AddressOrigin::SLAAC, +}; + /** @brief Interface IP Address configuration parameters */ template <int family> struct IfAddr @@ -162,6 +185,16 @@ enum class LanParam : uint8_t VLANId = 20, CiphersuiteSupport = 22, CiphersuiteEntries = 23, + IPFamilySupport = 50, + IPFamilyEnables = 51, + IPv6Status = 55, + IPv6StaticAddresses = 56, + IPv6DynamicAddresses = 59, + IPv6RouterControl = 64, + IPv6StaticRouter1IP = 65, + IPv6StaticRouter1MAC = 66, + IPv6StaticRouter1PrefixLength = 67, + IPv6StaticRouter1PrefixValue = 68, }; static constexpr uint8_t oemCmdStart = 192; @@ -185,6 +218,50 @@ enum class SetStatus : uint8_t Commit = 2, }; +/** @brief IPMI Family Suport Bits */ +namespace IPFamilySupportFlag +{ +constexpr uint8_t IPv6Only = 0; +constexpr uint8_t DualStack = 1; +constexpr uint8_t IPv6Alerts = 2; +} // namespace IPFamilySupportFlag + +/** @brief IPMI IPFamily Enables Flag */ +enum class IPFamilyEnables : uint8_t +{ + IPv4Only = 0, + IPv6Only = 1, + DualStack = 2, +}; + +/** @brief IPMI IPv6 Dyanmic Status Bits */ +namespace IPv6StatusFlag +{ +constexpr uint8_t DHCP = 0; +constexpr uint8_t SLAAC = 1; +}; // namespace IPv6StatusFlag + +/** @brief IPMI IPv6 Source */ +enum class IPv6Source : uint8_t +{ + Static = 0, + SLAAC = 1, + DHCP = 2, +}; + +/** @brief IPMI IPv6 Address Status */ +enum class IPv6AddressStatus : uint8_t +{ + Active = 0, + Disabled = 1, +}; + +namespace IPv6RouterControlFlag +{ +constexpr uint8_t Static = 0; +constexpr uint8_t Dynamic = 1; +}; // namespace IPv6RouterControlFlag + /** @brief A trivial helper used to determine if two PODs are equal * * @params[in] a - The first object to compare @@ -888,6 +965,97 @@ void reconfigureGatewayMAC(sdbusplus::bus::bus& bus, createNeighbor<family>(bus, params, *gateway, mac); } +/** @brief Deconfigures the IPv6 address info configured for the interface + * + * @param[in] bus - The bus object used for lookups + * @param[in] params - The parameters for the channel + * @param[in] idx - The address index to operate on + */ +void deconfigureIfAddr6(sdbusplus::bus::bus& bus, const ChannelParams& params, + uint8_t idx) +{ + auto ifaddr = getIfAddr<AF_INET6>(bus, params, idx, originsV6Static); + if (ifaddr) + { + deleteObjectIfExists(bus, params.service, ifaddr->path); + } +} + +/** @brief Reconfigures the IPv6 address info configured for the interface + * + * @param[in] bus - The bus object used for lookups + * @param[in] params - The parameters for the channel + * @param[in] idx - The address index to operate on + * @param[in] address - The new address + * @param[in] prefix - The new address prefix + */ +void reconfigureIfAddr6(sdbusplus::bus::bus& bus, const ChannelParams& params, + uint8_t idx, const in6_addr& address, uint8_t prefix) +{ + deconfigureIfAddr6(bus, params, idx); + createIfAddr<AF_INET6>(bus, params, address, prefix); +} + +/** @brief Converts the AddressOrigin into an IPv6Source + * + * @param[in] origin - The DBus Address Origin to convert + * @return The IPv6Source version of the origin + */ +IPv6Source originToSourceType(IP::AddressOrigin origin) +{ + switch (origin) + { + case IP::AddressOrigin::Static: + return IPv6Source::Static; + case IP::AddressOrigin::DHCP: + return IPv6Source::DHCP; + case IP::AddressOrigin::SLAAC: + return IPv6Source::SLAAC; + default: + { + auto originStr = sdbusplus::xyz::openbmc_project::Network::server:: + convertForMessage(origin); + log<level::ERR>( + "Invalid IP::AddressOrigin conversion to IPv6Source", + entry("ORIGIN=%s", originStr.c_str())); + elog<InternalFailure>(); + } + } +} + +/** @brief Packs the IPMI message response with IPv6 address data + * + * @param[out] ret - The IPMI response payload to be packed + * @param[in] channel - The channel id corresponding to an ethernet interface + * @param[in] set - The set selector for determining address index + * @param[in] origins - Set of valid origins for address filtering + */ +void getLanIPv6Address(message::Payload& ret, uint8_t channel, uint8_t set, + const std::unordered_set<IP::AddressOrigin>& origins) +{ + auto source = IPv6Source::Static; + bool enabled = false; + in6_addr addr{}; + uint8_t prefix = AddrFamily<AF_INET6>::defaultPrefix; + auto status = IPv6AddressStatus::Disabled; + + auto ifaddr = channelCall<getIfAddr<AF_INET6>>(channel, set, origins); + if (ifaddr) + { + source = originToSourceType(ifaddr->origin); + enabled = true; + addr = ifaddr->address; + prefix = ifaddr->prefix; + status = IPv6AddressStatus::Active; + } + + ret.pack(set); + ret.pack(static_cast<uint4_t>(source), uint3_t{}, enabled); + ret.pack(std::string_view(reinterpret_cast<char*>(&addr), sizeof(addr))); + ret.pack(prefix); + ret.pack(static_cast<uint8_t>(status)); +} + /** @brief Gets the vlan ID configured on the interface * * @param[in] bus - The bus object used for lookups @@ -987,9 +1155,21 @@ void reconfigureVLAN(sdbusplus::bus::bus& bus, ChannelParams& params, // Save info from the old logical interface ObjectLookupCache ips(bus, params, INTF_IP); auto ifaddr4 = findIfAddr<AF_INET>(bus, params, 0, originsV4, ips); + std::vector<IfAddr<AF_INET6>> ifaddrs6; + for (uint8_t i = 0; i < MAX_IPV6_STATIC_ADDRESSES; ++i) + { + auto ifaddr6 = + findIfAddr<AF_INET6>(bus, params, i, originsV6Static, ips); + if (!ifaddr6) + { + break; + } + ifaddrs6.push_back(std::move(*ifaddr6)); + } auto dhcp = getDHCPProperty(bus, params); ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR); auto neighbor4 = findGatewayNeighbor<AF_INET>(bus, params, neighbors); + auto neighbor6 = findGatewayNeighbor<AF_INET6>(bus, params, neighbors); deconfigureChannel(bus, params); createVLAN(bus, params, vlan); @@ -1000,10 +1180,18 @@ void reconfigureVLAN(sdbusplus::bus::bus& bus, ChannelParams& params, { createIfAddr<AF_INET>(bus, params, ifaddr4->address, ifaddr4->prefix); } + for (const auto& ifaddr6 : ifaddrs6) + { + createIfAddr<AF_INET6>(bus, params, ifaddr6.address, ifaddr6.prefix); + } if (neighbor4) { createNeighbor<AF_INET>(bus, params, neighbor4->ip, neighbor4->mac); } + if (neighbor6) + { + createNeighbor<AF_INET6>(bus, params, neighbor6->ip, neighbor6->mac); + } } /** @brief Turns a prefix into a netmask @@ -1287,10 +1475,132 @@ RspType<> setLan(uint4_t channelBits, uint4_t, uint8_t parameter, } case LanParam::CiphersuiteSupport: case LanParam::CiphersuiteEntries: + case LanParam::IPFamilySupport: + { + req.trailingOk = true; + return response(ccParamReadOnly); + } + case LanParam::IPFamilyEnables: + { + uint8_t enables; + if (req.unpack(enables) != 0 || !req.fullyUnpacked()) + { + return responseReqDataLenInvalid(); + } + switch (static_cast<IPFamilyEnables>(enables)) + { + case IPFamilyEnables::DualStack: + return responseSuccess(); + case IPFamilyEnables::IPv4Only: + case IPFamilyEnables::IPv6Only: + return response(ccParamNotSupported); + } + return response(ccParamNotSupported); + } + case LanParam::IPv6Status: + { + req.trailingOk = true; + return response(ccParamReadOnly); + } + case LanParam::IPv6StaticAddresses: + { + uint8_t set; + uint7_t rsvd; + bool enabled; + in6_addr ip; + std::array<uint8_t, sizeof(ip)> ipbytes; + uint8_t prefix; + uint8_t status; + if (req.unpack(set, rsvd, enabled, ipbytes, prefix, status) != 0 || + !req.fullyUnpacked()) + { + return responseReqDataLenInvalid(); + } + copyInto(ip, ipbytes); + if (enabled) + { + channelCall<reconfigureIfAddr6>(channel, set, ip, prefix); + } + else + { + channelCall<deconfigureIfAddr6>(channel, set); + } + return responseSuccess(); + } + case LanParam::IPv6DynamicAddresses: { req.trailingOk = true; return response(ccParamReadOnly); } + case LanParam::IPv6RouterControl: + { + std::bitset<8> control; + if (req.unpack(control) != 0 || !req.fullyUnpacked()) + { + return responseReqDataLenInvalid(); + } + std::bitset<8> expected; + if (channelCall<getDHCPProperty>(channel)) + { + expected[IPv6RouterControlFlag::Dynamic] = 1; + } + else + { + expected[IPv6RouterControlFlag::Static] = 1; + } + if (expected != control) + { + return responseInvalidFieldRequest(); + } + return responseSuccess(); + } + case LanParam::IPv6StaticRouter1IP: + { + in6_addr gateway; + std::array<uint8_t, sizeof(gateway)> bytes; + if (req.unpack(bytes) != 0 || !req.fullyUnpacked()) + { + return responseReqDataLenInvalid(); + } + copyInto(gateway, bytes); + channelCall<setGatewayProperty<AF_INET6>>(channel, gateway); + return responseSuccess(); + } + case LanParam::IPv6StaticRouter1MAC: + { + ether_addr mac; + std::array<uint8_t, sizeof(mac)> bytes; + if (req.unpack(bytes) != 0 || !req.fullyUnpacked()) + { + return responseReqDataLenInvalid(); + } + copyInto(mac, bytes); + channelCall<reconfigureGatewayMAC<AF_INET6>>(channel, mac); + return responseSuccess(); + } + case LanParam::IPv6StaticRouter1PrefixLength: + { + uint8_t prefix; + if (req.unpack(prefix) != 0 || !req.fullyUnpacked()) + { + return responseReqDataLenInvalid(); + } + if (prefix != 0) + { + return responseInvalidFieldRequest(); + } + return responseSuccess(); + } + case LanParam::IPv6StaticRouter1PrefixValue: + { + std::array<uint8_t, sizeof(in6_addr)> bytes; + if (req.unpack(bytes) != 0 || !req.fullyUnpacked()) + { + return responseReqDataLenInvalid(); + } + // Accept any prefix value since our prefix length has to be 0 + return responseSuccess(); + } } if ((parameter >= oemCmdStart) && (parameter <= oemCmdEnd)) @@ -1456,6 +1766,96 @@ RspType<message::Payload> getLan(uint4_t channelBits, uint3_t, bool revOnly, ret.pack(cipherList); return responseSuccess(std::move(ret)); } + case LanParam::IPFamilySupport: + { + std::bitset<8> support; + support[IPFamilySupportFlag::IPv6Only] = 0; + support[IPFamilySupportFlag::DualStack] = 1; + support[IPFamilySupportFlag::IPv6Alerts] = 1; + ret.pack(support); + return responseSuccess(std::move(ret)); + } + case LanParam::IPFamilyEnables: + { + ret.pack(static_cast<uint8_t>(IPFamilyEnables::DualStack)); + return responseSuccess(std::move(ret)); + } + case LanParam::IPv6Status: + { + ret.pack(MAX_IPV6_STATIC_ADDRESSES); + ret.pack(MAX_IPV6_DYNAMIC_ADDRESSES); + std::bitset<8> support; + support[IPv6StatusFlag::DHCP] = 1; + support[IPv6StatusFlag::SLAAC] = 1; + ret.pack(support); + return responseSuccess(std::move(ret)); + } + case LanParam::IPv6StaticAddresses: + { + if (set >= MAX_IPV6_STATIC_ADDRESSES) + { + return responseParmOutOfRange(); + } + getLanIPv6Address(ret, channel, set, originsV6Static); + return responseSuccess(std::move(ret)); + } + case LanParam::IPv6DynamicAddresses: + { + if (set >= MAX_IPV6_DYNAMIC_ADDRESSES) + { + return responseParmOutOfRange(); + } + getLanIPv6Address(ret, channel, set, originsV6Dynamic); + return responseSuccess(std::move(ret)); + } + case LanParam::IPv6RouterControl: + { + std::bitset<8> control; + if (channelCall<getDHCPProperty>(channel)) + { + control[IPv6RouterControlFlag::Dynamic] = 1; + } + else + { + control[IPv6RouterControlFlag::Static] = 1; + } + ret.pack(control); + return responseSuccess(std::move(ret)); + } + case LanParam::IPv6StaticRouter1IP: + { + in6_addr gateway{}; + if (!channelCall<getDHCPProperty>(channel)) + { + gateway = + channelCall<getGatewayProperty<AF_INET6>>(channel).value_or( + in6_addr{}); + } + ret.pack(dataRef(gateway)); + return responseSuccess(std::move(ret)); + } + case LanParam::IPv6StaticRouter1MAC: + { + ether_addr mac{}; + auto neighbor = channelCall<getGatewayNeighbor<AF_INET6>>(channel); + if (neighbor) + { + mac = neighbor->mac; + } + ret.pack(dataRef(mac)); + return responseSuccess(std::move(ret)); + } + case LanParam::IPv6StaticRouter1PrefixLength: + { + ret.pack(UINT8_C(0)); + return responseSuccess(std::move(ret)); + } + case LanParam::IPv6StaticRouter1PrefixValue: + { + in6_addr prefix{}; + ret.pack(dataRef(prefix)); + return responseSuccess(std::move(ret)); + } } if ((parameter >= oemCmdStart) && (parameter <= oemCmdEnd)) |