1 #include "app/channel.hpp" 2 3 #include <arpa/inet.h> 4 #include <netinet/ether.h> 5 6 #include <array> 7 #include <bitset> 8 #include <cinttypes> 9 #include <cstdint> 10 #include <cstring> 11 #include <fstream> 12 #include <functional> 13 #include <ipmid/api.hpp> 14 #include <ipmid/message.hpp> 15 #include <ipmid/message/types.hpp> 16 #include <ipmid/types.hpp> 17 #include <ipmid/utils.hpp> 18 #include <optional> 19 #include <phosphor-logging/elog-errors.hpp> 20 #include <phosphor-logging/elog.hpp> 21 #include <phosphor-logging/log.hpp> 22 #include <sdbusplus/bus.hpp> 23 #include <sdbusplus/exception.hpp> 24 #include <string> 25 #include <string_view> 26 #include <type_traits> 27 #include <unordered_map> 28 #include <unordered_set> 29 #include <user_channel/channel_layer.hpp> 30 #include <utility> 31 #include <vector> 32 #include <xyz/openbmc_project/Common/error.hpp> 33 #include <xyz/openbmc_project/Network/IP/server.hpp> 34 #include <xyz/openbmc_project/Network/Neighbor/server.hpp> 35 36 using phosphor::logging::commit; 37 using phosphor::logging::elog; 38 using phosphor::logging::entry; 39 using phosphor::logging::level; 40 using phosphor::logging::log; 41 using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; 42 using sdbusplus::xyz::openbmc_project::Network::server::IP; 43 using sdbusplus::xyz::openbmc_project::Network::server::Neighbor; 44 45 namespace cipher 46 { 47 48 std::vector<uint8_t> getCipherList() 49 { 50 std::vector<uint8_t> cipherList; 51 52 std::ifstream jsonFile(cipher::configFile); 53 if (!jsonFile.is_open()) 54 { 55 log<level::ERR>("Channel Cipher suites file not found"); 56 elog<InternalFailure>(); 57 } 58 59 auto data = Json::parse(jsonFile, nullptr, false); 60 if (data.is_discarded()) 61 { 62 log<level::ERR>("Parsing channel cipher suites JSON failed"); 63 elog<InternalFailure>(); 64 } 65 66 // Byte 1 is reserved 67 cipherList.push_back(0x00); 68 69 for (const auto& record : data) 70 { 71 cipherList.push_back(record.value(cipher, 0)); 72 } 73 74 return cipherList; 75 } 76 } // namespace cipher 77 78 namespace ipmi 79 { 80 namespace transport 81 { 82 83 // LAN Handler specific response codes 84 constexpr Cc ccParamNotSupported = 0x80; 85 constexpr Cc ccParamSetLocked = 0x81; 86 constexpr Cc ccParamReadOnly = 0x82; 87 88 // VLANs are a 12-bit value 89 constexpr uint16_t VLAN_VALUE_MASK = 0x0fff; 90 constexpr uint16_t VLAN_ENABLE_FLAG = 0x8000; 91 92 // D-Bus Network Daemon definitions 93 constexpr auto PATH_ROOT = "/xyz/openbmc_project/network"; 94 constexpr auto PATH_SYSTEMCONFIG = "/xyz/openbmc_project/network/config"; 95 96 constexpr auto INTF_SYSTEMCONFIG = 97 "xyz.openbmc_project.Network.SystemConfiguration"; 98 constexpr auto INTF_ETHERNET = "xyz.openbmc_project.Network.EthernetInterface"; 99 constexpr auto INTF_IP = "xyz.openbmc_project.Network.IP"; 100 constexpr auto INTF_IP_CREATE = "xyz.openbmc_project.Network.IP.Create"; 101 constexpr auto INTF_MAC = "xyz.openbmc_project.Network.MACAddress"; 102 constexpr auto INTF_NEIGHBOR = "xyz.openbmc_project.Network.Neighbor"; 103 constexpr auto INTF_NEIGHBOR_CREATE_STATIC = 104 "xyz.openbmc_project.Network.Neighbor.CreateStatic"; 105 constexpr auto INTF_VLAN = "xyz.openbmc_project.Network.VLAN"; 106 constexpr auto INTF_VLAN_CREATE = "xyz.openbmc_project.Network.VLAN.Create"; 107 108 /** @brief Generic paramters for different address families */ 109 template <int family> 110 struct AddrFamily 111 { 112 }; 113 114 /** @brief Parameter specialization for IPv4 */ 115 template <> 116 struct AddrFamily<AF_INET> 117 { 118 using addr = in_addr; 119 static constexpr auto protocol = IP::Protocol::IPv4; 120 static constexpr size_t maxStrLen = INET6_ADDRSTRLEN; 121 static constexpr uint8_t defaultPrefix = 32; 122 static constexpr char propertyGateway[] = "DefaultGateway"; 123 }; 124 125 /** @brief Valid address origins for IPv4 */ 126 const std::unordered_set<IP::AddressOrigin> originsV4 = { 127 IP::AddressOrigin::Static, 128 IP::AddressOrigin::DHCP, 129 }; 130 131 /** @brief Interface IP Address configuration parameters */ 132 template <int family> 133 struct IfAddr 134 { 135 std::string path; 136 typename AddrFamily<family>::addr address; 137 IP::AddressOrigin origin; 138 uint8_t prefix; 139 }; 140 141 /** @brief Interface Neighbor configuration parameters */ 142 template <int family> 143 struct IfNeigh 144 { 145 std::string path; 146 typename AddrFamily<family>::addr ip; 147 ether_addr mac; 148 }; 149 150 /** @brief IPMI LAN Parameters */ 151 enum class LanParam : uint8_t 152 { 153 SetStatus = 0, 154 AuthSupport = 1, 155 AuthEnables = 2, 156 IP = 3, 157 IPSrc = 4, 158 MAC = 5, 159 SubnetMask = 6, 160 Gateway1 = 12, 161 Gateway1MAC = 13, 162 VLANId = 20, 163 CiphersuiteSupport = 22, 164 CiphersuiteEntries = 23, 165 }; 166 167 static constexpr uint8_t oemCmdStart = 192; 168 static constexpr uint8_t oemCmdEnd = 255; 169 170 /** @brief IPMI IP Origin Types */ 171 enum class IPSrc : uint8_t 172 { 173 Unspecified = 0, 174 Static = 1, 175 DHCP = 2, 176 BIOS = 3, 177 BMC = 4, 178 }; 179 180 /** @brief IPMI Set Status */ 181 enum class SetStatus : uint8_t 182 { 183 Complete = 0, 184 InProgress = 1, 185 Commit = 2, 186 }; 187 188 /** @brief A trivial helper used to determine if two PODs are equal 189 * 190 * @params[in] a - The first object to compare 191 * @params[in] b - The second object to compare 192 * @return True if the objects are the same bytewise 193 */ 194 template <typename T> 195 bool equal(const T& a, const T& b) 196 { 197 static_assert(std::is_trivially_copyable_v<T>); 198 return std::memcmp(&a, &b, sizeof(T)) == 0; 199 } 200 201 /** @brief Copies bytes from an array into a trivially copyable container 202 * 203 * @params[out] t - The container receiving the data 204 * @params[in] bytes - The data to copy 205 */ 206 template <size_t N, typename T> 207 void copyInto(T& t, const std::array<uint8_t, N>& bytes) 208 { 209 static_assert(std::is_trivially_copyable_v<T>); 210 static_assert(N == sizeof(T)); 211 std::memcpy(&t, bytes.data(), bytes.size()); 212 } 213 214 /** @brief Gets a generic view of the bytes in the input container 215 * 216 * @params[in] t - The data to reference 217 * @return A string_view referencing the bytes in the container 218 */ 219 template <typename T> 220 std::string_view dataRef(const T& t) 221 { 222 static_assert(std::is_trivially_copyable_v<T>); 223 return {reinterpret_cast<const char*>(&t), sizeof(T)}; 224 } 225 226 /** @brief The dbus parameters for the interface corresponding to a channel 227 * This helps reduce the number of mapper lookups we need for each 228 * query and simplifies finding the VLAN interface if needed. 229 */ 230 struct ChannelParams 231 { 232 /** @brief The channel ID */ 233 int id; 234 /** @brief channel name for the interface */ 235 std::string ifname; 236 /** @brief Name of the service on the bus */ 237 std::string service; 238 /** @brief Lower level adapter path that is guaranteed to not be a VLAN */ 239 std::string ifPath; 240 /** @brief Logical adapter path used for address assignment */ 241 std::string logicalPath; 242 }; 243 244 /** @brief Determines the ethernet interface name corresponding to a channel 245 * Tries to map a VLAN object first so that the address information 246 * is accurate. Otherwise it gets the standard ethernet interface. 247 * 248 * @param[in] bus - The bus object used for lookups 249 * @param[in] channel - The channel id corresponding to an ethernet interface 250 * @return Ethernet interface service and object path if it exists 251 */ 252 std::optional<ChannelParams> maybeGetChannelParams(sdbusplus::bus::bus& bus, 253 uint8_t channel) 254 { 255 auto ifname = getChannelName(channel); 256 if (ifname.empty()) 257 { 258 return std::nullopt; 259 } 260 261 // Enumerate all VLAN + ETHERNET interfaces 262 auto req = bus.new_method_call(MAPPER_BUS_NAME, MAPPER_OBJ, MAPPER_INTF, 263 "GetSubTree"); 264 req.append(PATH_ROOT, 0, 265 std::vector<std::string>{INTF_VLAN, INTF_ETHERNET}); 266 auto reply = bus.call(req); 267 ObjectTree objs; 268 reply.read(objs); 269 270 ChannelParams params; 271 for (const auto& [path, impls] : objs) 272 { 273 if (path.find(ifname) == path.npos) 274 { 275 continue; 276 } 277 for (const auto& [service, intfs] : impls) 278 { 279 bool vlan = false; 280 bool ethernet = false; 281 for (const auto& intf : intfs) 282 { 283 if (intf == INTF_VLAN) 284 { 285 vlan = true; 286 } 287 else if (intf == INTF_ETHERNET) 288 { 289 ethernet = true; 290 } 291 } 292 if (params.service.empty() && (vlan || ethernet)) 293 { 294 params.service = service; 295 } 296 if (params.ifPath.empty() && !vlan && ethernet) 297 { 298 params.ifPath = path; 299 } 300 if (params.logicalPath.empty() && vlan) 301 { 302 params.logicalPath = path; 303 } 304 } 305 } 306 307 // We must have a path for the underlying interface 308 if (params.ifPath.empty()) 309 { 310 return std::nullopt; 311 } 312 // We don't have a VLAN so the logical path is the same 313 if (params.logicalPath.empty()) 314 { 315 params.logicalPath = params.ifPath; 316 } 317 318 params.id = channel; 319 params.ifname = std::move(ifname); 320 return std::move(params); 321 } 322 323 /** @brief A trivial helper around maybeGetChannelParams() that throws an 324 * exception when it is unable to acquire parameters for the channel. 325 * 326 * @param[in] bus - The bus object used for lookups 327 * @param[in] channel - The channel id corresponding to an ethernet interface 328 * @return Ethernet interface service and object path 329 */ 330 ChannelParams getChannelParams(sdbusplus::bus::bus& bus, uint8_t channel) 331 { 332 auto params = maybeGetChannelParams(bus, channel); 333 if (!params) 334 { 335 log<level::ERR>("Failed to get channel params", 336 entry("CHANNEL=%" PRIu8, channel)); 337 elog<InternalFailure>(); 338 } 339 return std::move(*params); 340 } 341 342 /** @brief Wraps the phosphor logging method to insert some additional metadata 343 * 344 * @param[in] params - The parameters for the channel 345 * ... 346 */ 347 template <auto level, typename... Args> 348 auto logWithChannel(const ChannelParams& params, Args&&... args) 349 { 350 return log<level>(std::forward<Args>(args)..., 351 entry("CHANNEL=%d", params.id), 352 entry("IFNAME=%s", params.ifname.c_str())); 353 } 354 template <auto level, typename... Args> 355 auto logWithChannel(const std::optional<ChannelParams>& params, Args&&... args) 356 { 357 if (params) 358 { 359 return logWithChannel<level>(*params, std::forward<Args>(args)...); 360 } 361 return log<level>(std::forward<Args>(args)...); 362 } 363 364 /** @brief Trivializes using parameter getter functions by providing a bus 365 * and channel parameters automatically. 366 * 367 * @param[in] channel - The channel id corresponding to an ethernet interface 368 * ... 369 */ 370 template <auto func, typename... Args> 371 auto channelCall(uint8_t channel, Args&&... args) 372 { 373 sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection()); 374 auto params = getChannelParams(bus, channel); 375 return std::invoke(func, bus, params, std::forward<Args>(args)...); 376 } 377 378 /** @brief Determines if the ethernet interface is using DHCP 379 * 380 * @param[in] bus - The bus object used for lookups 381 * @param[in] params - The parameters for the channel 382 * @return True if DHCP is enabled, false otherwise 383 */ 384 bool getDHCPProperty(sdbusplus::bus::bus& bus, const ChannelParams& params) 385 { 386 return std::get<bool>(getDbusProperty( 387 bus, params.service, params.logicalPath, INTF_ETHERNET, "DHCPEnabled")); 388 } 389 390 /** @brief Sets the system value for DHCP on the given interface 391 * 392 * @param[in] bus - The bus object used for lookups 393 * @param[in] params - The parameters for the channel 394 * @param[in] on - Whether or not to enable DHCP 395 */ 396 void setDHCPProperty(sdbusplus::bus::bus& bus, const ChannelParams& params, 397 bool on) 398 { 399 setDbusProperty(bus, params.service, params.logicalPath, INTF_ETHERNET, 400 "DHCPEnabled", on); 401 } 402 403 /** @brief Converts a human readable MAC string into MAC bytes 404 * 405 * @param[in] mac - The MAC string 406 * @return MAC in bytes 407 */ 408 ether_addr stringToMAC(const char* mac) 409 { 410 const ether_addr* ret = ether_aton(mac); 411 if (ret == nullptr) 412 { 413 log<level::ERR>("Invalid MAC Address", entry("MAC=%s", mac)); 414 elog<InternalFailure>(); 415 } 416 return *ret; 417 } 418 419 /** @brief Determines the MAC of the ethernet interface 420 * 421 * @param[in] bus - The bus object used for lookups 422 * @param[in] params - The parameters for the channel 423 * @return The configured mac address 424 */ 425 ether_addr getMACProperty(sdbusplus::bus::bus& bus, const ChannelParams& params) 426 { 427 auto macStr = std::get<std::string>(getDbusProperty( 428 bus, params.service, params.ifPath, INTF_MAC, "MACAddress")); 429 return stringToMAC(macStr.c_str()); 430 } 431 432 /** @brief Sets the system value for MAC address on the given interface 433 * 434 * @param[in] bus - The bus object used for lookups 435 * @param[in] params - The parameters for the channel 436 * @param[in] mac - MAC address to apply 437 */ 438 void setMACProperty(sdbusplus::bus::bus& bus, const ChannelParams& params, 439 const ether_addr& mac) 440 { 441 std::string macStr = ether_ntoa(&mac); 442 setDbusProperty(bus, params.service, params.ifPath, INTF_MAC, "MACAddress", 443 macStr); 444 } 445 446 /** @brief Turns an IP address string into the network byte order form 447 * NOTE: This version strictly validates family matches 448 * 449 * @param[in] address - The string form of the address 450 * @return A network byte order address or none if conversion failed 451 */ 452 template <int family> 453 std::optional<typename AddrFamily<family>::addr> 454 maybeStringToAddr(const char* address) 455 { 456 typename AddrFamily<family>::addr ret; 457 if (inet_pton(family, address, &ret) == 1) 458 { 459 return ret; 460 } 461 return std::nullopt; 462 } 463 464 /** @brief Turns an IP address string into the network byte order form 465 * NOTE: This version strictly validates family matches 466 * 467 * @param[in] address - The string form of the address 468 * @return A network byte order address 469 */ 470 template <int family> 471 typename AddrFamily<family>::addr stringToAddr(const char* address) 472 { 473 auto ret = maybeStringToAddr<family>(address); 474 if (!ret) 475 { 476 log<level::ERR>("Failed to convert IP Address", 477 entry("FAMILY=%d", family), 478 entry("ADDRESS=%s", address)); 479 elog<InternalFailure>(); 480 } 481 return *ret; 482 } 483 484 /** @brief Turns an IP address in network byte order into a string 485 * 486 * @param[in] address - The string form of the address 487 * @return A network byte order address 488 */ 489 template <int family> 490 std::string addrToString(const typename AddrFamily<family>::addr& address) 491 { 492 std::string ret(AddrFamily<family>::maxStrLen, '\0'); 493 inet_ntop(family, &address, ret.data(), ret.size()); 494 ret.resize(strlen(ret.c_str())); 495 return ret; 496 } 497 498 /** @brief Retrieves the current gateway for the address family on the system 499 * NOTE: The gateway is currently system wide and not per channel 500 * 501 * @param[in] bus - The bus object used for lookups 502 * @param[in] params - The parameters for the channel 503 * @return An address representing the gateway address if it exists 504 */ 505 template <int family> 506 std::optional<typename AddrFamily<family>::addr> 507 getGatewayProperty(sdbusplus::bus::bus& bus, const ChannelParams& params) 508 { 509 auto gatewayStr = std::get<std::string>(getDbusProperty( 510 bus, params.service, PATH_SYSTEMCONFIG, INTF_SYSTEMCONFIG, 511 AddrFamily<family>::propertyGateway)); 512 if (gatewayStr.empty()) 513 { 514 return std::nullopt; 515 } 516 return stringToAddr<family>(gatewayStr.c_str()); 517 } 518 519 /** @brief A lazy lookup mechanism for iterating over object properties stored 520 * in DBus. This will only perform the object lookup when needed, and 521 * retains a cache of previous lookups to speed up future iterations. 522 */ 523 class ObjectLookupCache 524 { 525 public: 526 using PropertiesCache = std::unordered_map<std::string, PropertyMap>; 527 528 /** @brief Creates a new ObjectLookupCache for the interface on the bus 529 * NOTE: The inputs to this object must outlive the object since 530 * they are only referenced by it. 531 * 532 * @param[in] bus - The bus object used for lookups 533 * @param[in] params - The parameters for the channel 534 * @param[in] intf - The interface we are looking up 535 */ 536 ObjectLookupCache(sdbusplus::bus::bus& bus, const ChannelParams& params, 537 const char* intf) : 538 bus(bus), 539 params(params), intf(intf), 540 objs(getAllDbusObjects(bus, params.logicalPath, intf, "")) 541 { 542 } 543 544 class iterator : public ObjectTree::const_iterator 545 { 546 public: 547 using value_type = PropertiesCache::value_type; 548 549 iterator(ObjectTree::const_iterator it, ObjectLookupCache& container) : 550 ObjectTree::const_iterator(it), container(container), 551 ret(container.cache.end()) 552 { 553 } 554 value_type& operator*() 555 { 556 ret = container.get(ObjectTree::const_iterator::operator*().first); 557 return *ret; 558 } 559 value_type* operator->() 560 { 561 return &operator*(); 562 } 563 564 private: 565 ObjectLookupCache& container; 566 PropertiesCache::iterator ret; 567 }; 568 569 iterator begin() noexcept 570 { 571 return iterator(objs.begin(), *this); 572 } 573 574 iterator end() noexcept 575 { 576 return iterator(objs.end(), *this); 577 } 578 579 private: 580 sdbusplus::bus::bus& bus; 581 const ChannelParams& params; 582 const char* const intf; 583 const ObjectTree objs; 584 PropertiesCache cache; 585 586 /** @brief Gets a cached copy of the object properties if possible 587 * Otherwise performs a query on DBus to look them up 588 * 589 * @param[in] path - The object path to lookup 590 * @return An iterator for the specified object path + properties 591 */ 592 PropertiesCache::iterator get(const std::string& path) 593 { 594 auto it = cache.find(path); 595 if (it != cache.end()) 596 { 597 return it; 598 } 599 auto properties = getAllDbusProperties(bus, params.service, path, intf); 600 return cache.insert({path, std::move(properties)}).first; 601 } 602 }; 603 604 /** @brief Searches the ip object lookup cache for an address matching 605 * the input parameters. NOTE: The index lacks stability across address 606 * changes since the network daemon has no notion of stable indicies. 607 * 608 * @param[in] bus - The bus object used for lookups 609 * @param[in] params - The parameters for the channel 610 * @param[in] idx - The index of the desired address on the interface 611 * @param[in] origins - The allowed origins for the address objects 612 * @param[in] ips - The object lookup cache holding all of the address info 613 * @return The address and prefix if it was found 614 */ 615 template <int family> 616 std::optional<IfAddr<family>> 617 findIfAddr(sdbusplus::bus::bus& bus, const ChannelParams& params, 618 uint8_t idx, 619 const std::unordered_set<IP::AddressOrigin>& origins, 620 ObjectLookupCache& ips) 621 { 622 for (const auto& [path, properties] : ips) 623 { 624 const auto& addrStr = std::get<std::string>(properties.at("Address")); 625 auto addr = maybeStringToAddr<family>(addrStr.c_str()); 626 if (!addr) 627 { 628 continue; 629 } 630 631 IP::AddressOrigin origin = IP::convertAddressOriginFromString( 632 std::get<std::string>(properties.at("Origin"))); 633 if (origins.find(origin) == origins.end()) 634 { 635 continue; 636 } 637 638 if (idx > 0) 639 { 640 idx--; 641 continue; 642 } 643 644 IfAddr<family> ifaddr; 645 ifaddr.path = path; 646 ifaddr.address = *addr; 647 ifaddr.prefix = std::get<uint8_t>(properties.at("PrefixLength")); 648 ifaddr.origin = origin; 649 return std::move(ifaddr); 650 } 651 652 return std::nullopt; 653 } 654 655 /** @brief Trivial helper around findIfAddr that simplifies calls 656 * for one off lookups. Don't use this if you intend to do multiple 657 * lookups at a time. 658 * 659 * @param[in] bus - The bus object used for lookups 660 * @param[in] params - The parameters for the channel 661 * @param[in] idx - The index of the desired address on the interface 662 * @param[in] origins - The allowed origins for the address objects 663 * @return The address and prefix if it was found 664 */ 665 template <int family> 666 auto getIfAddr(sdbusplus::bus::bus& bus, const ChannelParams& params, 667 uint8_t idx, 668 const std::unordered_set<IP::AddressOrigin>& origins) 669 { 670 ObjectLookupCache ips(bus, params, INTF_IP); 671 return findIfAddr<family>(bus, params, idx, origins, ips); 672 } 673 674 /** @brief Deletes the dbus object. Ignores empty objects or objects that are 675 * missing from the bus. 676 * 677 * @param[in] bus - The bus object used for lookups 678 * @param[in] service - The name of the service 679 * @param[in] path - The path of the object to delete 680 */ 681 void deleteObjectIfExists(sdbusplus::bus::bus& bus, const std::string& service, 682 const std::string& path) 683 { 684 if (path.empty()) 685 { 686 return; 687 } 688 try 689 { 690 auto req = bus.new_method_call(service.c_str(), path.c_str(), 691 ipmi::DELETE_INTERFACE, "Delete"); 692 bus.call_noreply(req); 693 } 694 catch (const sdbusplus::exception::SdBusError& e) 695 { 696 if (strcmp(e.name(), "org.freedesktop.DBus.Error.UnknownObject") != 0) 697 { 698 // We want to rethrow real errors 699 throw; 700 } 701 } 702 } 703 704 /** @brief Sets the address info configured for the interface 705 * If a previous address path exists then it will be removed 706 * before the new address is added. 707 * 708 * @param[in] bus - The bus object used for lookups 709 * @param[in] params - The parameters for the channel 710 * @param[in] address - The address of the new IP 711 * @param[in] prefix - The prefix of the new IP 712 */ 713 template <int family> 714 void createIfAddr(sdbusplus::bus::bus& bus, const ChannelParams& params, 715 const typename AddrFamily<family>::addr& address, 716 uint8_t prefix) 717 { 718 auto newreq = 719 bus.new_method_call(params.service.c_str(), params.logicalPath.c_str(), 720 INTF_IP_CREATE, "IP"); 721 std::string protocol = 722 sdbusplus::xyz::openbmc_project::Network::server::convertForMessage( 723 AddrFamily<family>::protocol); 724 newreq.append(protocol, addrToString<family>(address), prefix, ""); 725 bus.call_noreply(newreq); 726 } 727 728 /** @brief Trivial helper for getting the IPv4 address from getIfAddrs() 729 * 730 * @param[in] bus - The bus object used for lookups 731 * @param[in] params - The parameters for the channel 732 * @return The address and prefix if found 733 */ 734 auto getIfAddr4(sdbusplus::bus::bus& bus, const ChannelParams& params) 735 { 736 return getIfAddr<AF_INET>(bus, params, 0, originsV4); 737 } 738 739 /** @brief Reconfigures the IPv4 address info configured for the interface 740 * 741 * @param[in] bus - The bus object used for lookups 742 * @param[in] params - The parameters for the channel 743 * @param[in] address - The new address if specified 744 * @param[in] prefix - The new address prefix if specified 745 */ 746 void reconfigureIfAddr4(sdbusplus::bus::bus& bus, const ChannelParams& params, 747 const std::optional<in_addr>& address, 748 std::optional<uint8_t> prefix) 749 { 750 auto ifaddr = getIfAddr4(bus, params); 751 if (!ifaddr && !address) 752 { 753 log<level::ERR>("Missing address for IPv4 assignment"); 754 elog<InternalFailure>(); 755 } 756 uint8_t fallbackPrefix = AddrFamily<AF_INET>::defaultPrefix; 757 if (ifaddr) 758 { 759 fallbackPrefix = ifaddr->prefix; 760 deleteObjectIfExists(bus, params.service, ifaddr->path); 761 } 762 createIfAddr<AF_INET>(bus, params, address.value_or(ifaddr->address), 763 prefix.value_or(fallbackPrefix)); 764 } 765 766 template <int family> 767 std::optional<IfNeigh<family>> 768 findStaticNeighbor(sdbusplus::bus::bus& bus, const ChannelParams& params, 769 const typename AddrFamily<family>::addr& ip, 770 ObjectLookupCache& neighbors) 771 { 772 const auto state = 773 sdbusplus::xyz::openbmc_project::Network::server::convertForMessage( 774 Neighbor::State::Permanent); 775 for (const auto& [path, neighbor] : neighbors) 776 { 777 const auto& ipStr = std::get<std::string>(neighbor.at("IPAddress")); 778 auto neighIP = maybeStringToAddr<family>(ipStr.c_str()); 779 if (!neighIP) 780 { 781 continue; 782 } 783 if (!equal(*neighIP, ip)) 784 { 785 continue; 786 } 787 if (state != std::get<std::string>(neighbor.at("State"))) 788 { 789 continue; 790 } 791 792 IfNeigh<family> ret; 793 ret.path = path; 794 ret.ip = ip; 795 const auto& macStr = std::get<std::string>(neighbor.at("MACAddress")); 796 ret.mac = stringToMAC(macStr.c_str()); 797 return std::move(ret); 798 } 799 800 return std::nullopt; 801 } 802 803 template <int family> 804 void createNeighbor(sdbusplus::bus::bus& bus, const ChannelParams& params, 805 const typename AddrFamily<family>::addr& address, 806 const ether_addr& mac) 807 { 808 auto newreq = 809 bus.new_method_call(params.service.c_str(), params.logicalPath.c_str(), 810 INTF_NEIGHBOR_CREATE_STATIC, "Neighbor"); 811 std::string macStr = ether_ntoa(&mac); 812 newreq.append(addrToString<family>(address), macStr); 813 bus.call_noreply(newreq); 814 } 815 816 /** @brief Sets the system wide value for the default gateway 817 * 818 * @param[in] bus - The bus object used for lookups 819 * @param[in] params - The parameters for the channel 820 * @param[in] gateway - Gateway address to apply 821 */ 822 template <int family> 823 void setGatewayProperty(sdbusplus::bus::bus& bus, const ChannelParams& params, 824 const typename AddrFamily<family>::addr& address) 825 { 826 // Save the old gateway MAC address if it exists so we can recreate it 827 auto gateway = getGatewayProperty<family>(bus, params); 828 std::optional<IfNeigh<family>> neighbor; 829 if (gateway) 830 { 831 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR); 832 neighbor = findStaticNeighbor<family>(bus, params, *gateway, neighbors); 833 } 834 835 setDbusProperty(bus, params.service, PATH_SYSTEMCONFIG, INTF_SYSTEMCONFIG, 836 AddrFamily<family>::propertyGateway, 837 addrToString<family>(address)); 838 839 // Restore the gateway MAC if we had one 840 if (neighbor) 841 { 842 deleteObjectIfExists(bus, params.service, neighbor->path); 843 createNeighbor<family>(bus, params, address, neighbor->mac); 844 } 845 } 846 847 template <int family> 848 std::optional<IfNeigh<family>> findGatewayNeighbor(sdbusplus::bus::bus& bus, 849 const ChannelParams& params, 850 ObjectLookupCache& neighbors) 851 { 852 auto gateway = getGatewayProperty<family>(bus, params); 853 if (!gateway) 854 { 855 return std::nullopt; 856 } 857 858 return findStaticNeighbor<family>(bus, params, *gateway, neighbors); 859 } 860 861 template <int family> 862 std::optional<IfNeigh<family>> getGatewayNeighbor(sdbusplus::bus::bus& bus, 863 const ChannelParams& params) 864 { 865 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR); 866 return findGatewayNeighbor<family>(bus, params, neighbors); 867 } 868 869 template <int family> 870 void reconfigureGatewayMAC(sdbusplus::bus::bus& bus, 871 const ChannelParams& params, const ether_addr& mac) 872 { 873 auto gateway = getGatewayProperty<family>(bus, params); 874 if (!gateway) 875 { 876 log<level::ERR>("Tried to set Gateway MAC without Gateway"); 877 elog<InternalFailure>(); 878 } 879 880 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR); 881 auto neighbor = 882 findStaticNeighbor<family>(bus, params, *gateway, neighbors); 883 if (neighbor) 884 { 885 deleteObjectIfExists(bus, params.service, neighbor->path); 886 } 887 888 createNeighbor<family>(bus, params, *gateway, mac); 889 } 890 891 /** @brief Gets the vlan ID configured on the interface 892 * 893 * @param[in] bus - The bus object used for lookups 894 * @param[in] params - The parameters for the channel 895 * @return VLAN id or the standard 0 for no VLAN 896 */ 897 uint16_t getVLANProperty(sdbusplus::bus::bus& bus, const ChannelParams& params) 898 { 899 // VLAN devices will always have a separate logical object 900 if (params.ifPath == params.logicalPath) 901 { 902 return 0; 903 } 904 905 auto vlan = std::get<uint32_t>(getDbusProperty( 906 bus, params.service, params.logicalPath, INTF_VLAN, "Id")); 907 if ((vlan & VLAN_VALUE_MASK) != vlan) 908 { 909 logWithChannel<level::ERR>(params, "networkd returned an invalid vlan", 910 entry("VLAN=%" PRIu32, vlan)); 911 elog<InternalFailure>(); 912 } 913 return vlan; 914 } 915 916 /** @brief Deletes all of the possible configuration parameters for a channel 917 * 918 * @param[in] bus - The bus object used for lookups 919 * @param[in] params - The parameters for the channel 920 */ 921 void deconfigureChannel(sdbusplus::bus::bus& bus, ChannelParams& params) 922 { 923 // Delete all objects associated with the interface 924 auto objreq = bus.new_method_call(MAPPER_BUS_NAME, MAPPER_OBJ, MAPPER_INTF, 925 "GetSubTree"); 926 objreq.append(PATH_ROOT, 0, std::vector<std::string>{DELETE_INTERFACE}); 927 auto objreply = bus.call(objreq); 928 ObjectTree objs; 929 objreply.read(objs); 930 for (const auto& [path, impls] : objs) 931 { 932 if (path.find(params.ifname) == path.npos) 933 { 934 continue; 935 } 936 for (const auto& [service, intfs] : impls) 937 { 938 deleteObjectIfExists(bus, service, path); 939 } 940 // Update params to reflect the deletion of vlan 941 if (path == params.logicalPath) 942 { 943 params.logicalPath = params.ifPath; 944 } 945 } 946 947 // Clear out any settings on the lower physical interface 948 setDHCPProperty(bus, params, false); 949 } 950 951 /** @brief Creates a new VLAN on the specified interface 952 * 953 * @param[in] bus - The bus object used for lookups 954 * @param[in] params - The parameters for the channel 955 * @param[in] vlan - The id of the new vlan 956 */ 957 void createVLAN(sdbusplus::bus::bus& bus, ChannelParams& params, uint16_t vlan) 958 { 959 if (vlan == 0) 960 { 961 return; 962 } 963 964 auto req = bus.new_method_call(params.service.c_str(), PATH_ROOT, 965 INTF_VLAN_CREATE, "VLAN"); 966 req.append(params.ifname, static_cast<uint32_t>(vlan)); 967 auto reply = bus.call(req); 968 sdbusplus::message::object_path newPath; 969 reply.read(newPath); 970 params.logicalPath = std::move(newPath); 971 } 972 973 /** @brief Performs the necessary reconfiguration to change the VLAN 974 * 975 * @param[in] bus - The bus object used for lookups 976 * @param[in] params - The parameters for the channel 977 * @param[in] vlan - The new vlan id to use 978 */ 979 void reconfigureVLAN(sdbusplus::bus::bus& bus, ChannelParams& params, 980 uint16_t vlan) 981 { 982 // Unfortunatetly we don't have built-in functions to migrate our interface 983 // customizations to new VLAN interfaces, or have some kind of decoupling. 984 // We therefore must retain all of our old information, setup the new VLAN 985 // configuration, then restore the old info. 986 987 // Save info from the old logical interface 988 ObjectLookupCache ips(bus, params, INTF_IP); 989 auto ifaddr4 = findIfAddr<AF_INET>(bus, params, 0, originsV4, ips); 990 auto dhcp = getDHCPProperty(bus, params); 991 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR); 992 auto neighbor4 = findGatewayNeighbor<AF_INET>(bus, params, neighbors); 993 994 deconfigureChannel(bus, params); 995 createVLAN(bus, params, vlan); 996 997 // Re-establish the saved settings 998 setDHCPProperty(bus, params, dhcp); 999 if (ifaddr4) 1000 { 1001 createIfAddr<AF_INET>(bus, params, ifaddr4->address, ifaddr4->prefix); 1002 } 1003 if (neighbor4) 1004 { 1005 createNeighbor<AF_INET>(bus, params, neighbor4->ip, neighbor4->mac); 1006 } 1007 } 1008 1009 /** @brief Turns a prefix into a netmask 1010 * 1011 * @param[in] prefix - The prefix length 1012 * @return The netmask 1013 */ 1014 in_addr prefixToNetmask(uint8_t prefix) 1015 { 1016 if (prefix > 32) 1017 { 1018 log<level::ERR>("Invalid prefix", entry("PREFIX=%" PRIu8, prefix)); 1019 elog<InternalFailure>(); 1020 } 1021 if (prefix == 0) 1022 { 1023 // Avoids 32-bit lshift by 32 UB 1024 return {}; 1025 } 1026 return {htobe32(~UINT32_C(0) << (32 - prefix))}; 1027 } 1028 1029 /** @brief Turns a a netmask into a prefix length 1030 * 1031 * @param[in] netmask - The netmask in byte form 1032 * @return The prefix length 1033 */ 1034 uint8_t netmaskToPrefix(in_addr netmask) 1035 { 1036 uint32_t x = be32toh(netmask.s_addr); 1037 if ((~x & (~x + 1)) != 0) 1038 { 1039 char maskStr[INET_ADDRSTRLEN]; 1040 inet_ntop(AF_INET, &netmask, maskStr, sizeof(maskStr)); 1041 log<level::ERR>("Invalid netmask", entry("NETMASK=%s", maskStr)); 1042 elog<InternalFailure>(); 1043 } 1044 return 32 - __builtin_ctz(x); 1045 } 1046 1047 // We need to store this value so it can be returned to the client 1048 // It is volatile so safe to store in daemon memory. 1049 static std::unordered_map<uint8_t, SetStatus> setStatus; 1050 1051 // Until we have good support for fixed versions of IPMI tool 1052 // we need to return the VLAN id for disabled VLANs. The value is only 1053 // used for verification that a disable operation succeeded and will only 1054 // be sent if our system indicates that vlans are disabled. 1055 static std::unordered_map<uint8_t, uint16_t> lastDisabledVlan; 1056 1057 /** @brief Gets the set status for the channel if it exists 1058 * Otherise populates and returns the default value. 1059 * 1060 * @param[in] channel - The channel id corresponding to an ethernet interface 1061 * @return A reference to the SetStatus for the channel 1062 */ 1063 SetStatus& getSetStatus(uint8_t channel) 1064 { 1065 auto it = setStatus.find(channel); 1066 if (it != setStatus.end()) 1067 { 1068 return it->second; 1069 } 1070 return setStatus[channel] = SetStatus::Complete; 1071 } 1072 1073 /** 1074 * Define placeholder command handlers for the OEM Extension bytes for the Set 1075 * LAN Configuration Parameters and Get LAN Configuration Parameters 1076 * commands. Using "weak" linking allows the placeholder setLanOem/getLanOem 1077 * functions below to be overridden. 1078 * To create handlers for your own proprietary command set: 1079 * Create/modify a phosphor-ipmi-host Bitbake append file within your Yocto 1080 * recipe 1081 * Create C++ file(s) that define IPMI handler functions matching the 1082 * function names below (i.e. setLanOem). The default name for the 1083 * transport IPMI commands is transporthandler_oem.cpp. 1084 * Add: 1085 * EXTRA_OECONF_append = " --enable-transport-oem=yes" 1086 * Create a do_compile_prepend()/do_install_append method in your 1087 * bbappend file to copy the file to the build directory. 1088 * Add: 1089 * PROJECT_SRC_DIR := "${THISDIR}/${PN}" 1090 * # Copy the "strong" functions into the working directory, overriding the 1091 * # placeholder functions. 1092 * do_compile_prepend(){ 1093 * cp -f ${PROJECT_SRC_DIR}/transporthandler_oem.cpp ${S} 1094 * } 1095 * 1096 * # Clean up after complilation has completed 1097 * do_install_append(){ 1098 * rm -f ${S}/transporthandler_oem.cpp 1099 * } 1100 * 1101 */ 1102 1103 /** 1104 * Define the placeholder OEM commands as having weak linkage. Create 1105 * setLanOem, and getLanOem functions in the transporthandler_oem.cpp 1106 * file. The functions defined there must not have the "weak" attribute 1107 * applied to them. 1108 */ 1109 RspType<> setLanOem(uint8_t channel, uint8_t parameter, message::Payload& req) 1110 __attribute__((weak)); 1111 RspType<message::Payload> getLanOem(uint8_t channel, uint8_t parameter, 1112 uint8_t set, uint8_t block) 1113 __attribute__((weak)); 1114 1115 RspType<> setLanOem(uint8_t channel, uint8_t parameter, message::Payload& req) 1116 { 1117 req.trailingOk = true; 1118 return response(ccParamNotSupported); 1119 } 1120 1121 RspType<message::Payload> getLanOem(uint8_t channel, uint8_t parameter, 1122 uint8_t set, uint8_t block) 1123 { 1124 return response(ccParamNotSupported); 1125 } 1126 1127 RspType<> setLan(uint4_t channelBits, uint4_t, uint8_t parameter, 1128 message::Payload& req) 1129 { 1130 auto channel = static_cast<uint8_t>(channelBits); 1131 if (!doesDeviceExist(channel)) 1132 { 1133 req.trailingOk = true; 1134 return responseInvalidFieldRequest(); 1135 } 1136 1137 switch (static_cast<LanParam>(parameter)) 1138 { 1139 case LanParam::SetStatus: 1140 { 1141 uint2_t flag; 1142 uint6_t rsvd; 1143 if (req.unpack(flag, rsvd) != 0 || !req.fullyUnpacked()) 1144 { 1145 return responseReqDataLenInvalid(); 1146 } 1147 auto status = static_cast<SetStatus>(static_cast<uint8_t>(flag)); 1148 switch (status) 1149 { 1150 case SetStatus::Complete: 1151 { 1152 getSetStatus(channel) = status; 1153 return responseSuccess(); 1154 } 1155 case SetStatus::InProgress: 1156 { 1157 auto& storedStatus = getSetStatus(channel); 1158 if (storedStatus == SetStatus::InProgress) 1159 { 1160 return response(ccParamSetLocked); 1161 } 1162 storedStatus = status; 1163 return responseSuccess(); 1164 } 1165 case SetStatus::Commit: 1166 if (getSetStatus(channel) != SetStatus::InProgress) 1167 { 1168 return responseInvalidFieldRequest(); 1169 } 1170 return responseSuccess(); 1171 } 1172 return response(ccParamNotSupported); 1173 } 1174 case LanParam::AuthSupport: 1175 { 1176 req.trailingOk = true; 1177 return response(ccParamReadOnly); 1178 } 1179 case LanParam::AuthEnables: 1180 { 1181 req.trailingOk = true; 1182 return response(ccParamNotSupported); 1183 } 1184 case LanParam::IP: 1185 { 1186 in_addr ip; 1187 std::array<uint8_t, sizeof(ip)> bytes; 1188 if (req.unpack(bytes) != 0 || !req.fullyUnpacked()) 1189 { 1190 return responseReqDataLenInvalid(); 1191 } 1192 copyInto(ip, bytes); 1193 channelCall<reconfigureIfAddr4>(channel, ip, std::nullopt); 1194 return responseSuccess(); 1195 } 1196 case LanParam::IPSrc: 1197 { 1198 uint4_t flag; 1199 uint4_t rsvd; 1200 if (req.unpack(flag, rsvd) != 0 || !req.fullyUnpacked()) 1201 { 1202 return responseReqDataLenInvalid(); 1203 } 1204 switch (static_cast<IPSrc>(static_cast<uint8_t>(flag))) 1205 { 1206 case IPSrc::DHCP: 1207 { 1208 channelCall<setDHCPProperty>(channel, true); 1209 return responseSuccess(); 1210 } 1211 case IPSrc::Unspecified: 1212 case IPSrc::Static: 1213 case IPSrc::BIOS: 1214 case IPSrc::BMC: 1215 { 1216 channelCall<setDHCPProperty>(channel, false); 1217 return responseSuccess(); 1218 } 1219 } 1220 return response(ccParamNotSupported); 1221 } 1222 case LanParam::MAC: 1223 { 1224 ether_addr mac; 1225 std::array<uint8_t, sizeof(mac)> bytes; 1226 if (req.unpack(bytes) != 0 || !req.fullyUnpacked()) 1227 { 1228 return responseReqDataLenInvalid(); 1229 } 1230 copyInto(mac, bytes); 1231 channelCall<setMACProperty>(channel, mac); 1232 return responseSuccess(); 1233 } 1234 case LanParam::SubnetMask: 1235 { 1236 in_addr netmask; 1237 std::array<uint8_t, sizeof(netmask)> bytes; 1238 if (req.unpack(bytes) != 0 || !req.fullyUnpacked()) 1239 { 1240 return responseReqDataLenInvalid(); 1241 } 1242 copyInto(netmask, bytes); 1243 channelCall<reconfigureIfAddr4>(channel, std::nullopt, 1244 netmaskToPrefix(netmask)); 1245 return responseSuccess(); 1246 } 1247 case LanParam::Gateway1: 1248 { 1249 in_addr gateway; 1250 std::array<uint8_t, sizeof(gateway)> bytes; 1251 if (req.unpack(bytes) != 0 || !req.fullyUnpacked()) 1252 { 1253 return responseReqDataLenInvalid(); 1254 } 1255 copyInto(gateway, bytes); 1256 channelCall<setGatewayProperty<AF_INET>>(channel, gateway); 1257 return responseSuccess(); 1258 } 1259 case LanParam::Gateway1MAC: 1260 { 1261 ether_addr gatewayMAC; 1262 std::array<uint8_t, sizeof(gatewayMAC)> bytes; 1263 if (req.unpack(bytes) != 0 || !req.fullyUnpacked()) 1264 { 1265 return responseReqDataLenInvalid(); 1266 } 1267 copyInto(gatewayMAC, bytes); 1268 channelCall<reconfigureGatewayMAC<AF_INET>>(channel, gatewayMAC); 1269 return responseSuccess(); 1270 } 1271 case LanParam::VLANId: 1272 { 1273 uint16_t vlanData; 1274 if (req.unpack(vlanData) != 0 || !req.fullyUnpacked()) 1275 { 1276 return responseReqDataLenInvalid(); 1277 } 1278 if ((vlanData & VLAN_ENABLE_FLAG) == 0) 1279 { 1280 lastDisabledVlan[channel] = vlanData & VLAN_VALUE_MASK; 1281 vlanData = 0; 1282 } 1283 channelCall<reconfigureVLAN>(channel, vlanData & VLAN_VALUE_MASK); 1284 return responseSuccess(); 1285 } 1286 case LanParam::CiphersuiteSupport: 1287 case LanParam::CiphersuiteEntries: 1288 { 1289 req.trailingOk = true; 1290 return response(ccParamReadOnly); 1291 } 1292 } 1293 1294 if ((parameter >= oemCmdStart) && (parameter <= oemCmdEnd)) 1295 { 1296 return setLanOem(channel, parameter, req); 1297 } 1298 1299 req.trailingOk = true; 1300 return response(ccParamNotSupported); 1301 } 1302 1303 RspType<message::Payload> getLan(uint4_t channelBits, uint3_t, bool revOnly, 1304 uint8_t parameter, uint8_t set, uint8_t block) 1305 { 1306 message::Payload ret; 1307 constexpr uint8_t current_revision = 0x11; 1308 ret.pack(current_revision); 1309 1310 if (revOnly) 1311 { 1312 return responseSuccess(std::move(ret)); 1313 } 1314 1315 auto channel = static_cast<uint8_t>(channelBits); 1316 if (!doesDeviceExist(channel)) 1317 { 1318 return responseInvalidFieldRequest(); 1319 } 1320 1321 static std::vector<uint8_t> cipherList; 1322 static bool listInit = false; 1323 if (!listInit) 1324 { 1325 try 1326 { 1327 cipherList = cipher::getCipherList(); 1328 listInit = true; 1329 } 1330 catch (const std::exception& e) 1331 { 1332 } 1333 } 1334 1335 switch (static_cast<LanParam>(parameter)) 1336 { 1337 case LanParam::SetStatus: 1338 { 1339 SetStatus status; 1340 try 1341 { 1342 status = setStatus.at(channel); 1343 } 1344 catch (const std::out_of_range&) 1345 { 1346 status = SetStatus::Complete; 1347 } 1348 ret.pack(static_cast<uint2_t>(status), uint6_t{}); 1349 return responseSuccess(std::move(ret)); 1350 } 1351 case LanParam::AuthSupport: 1352 { 1353 std::bitset<6> support; 1354 ret.pack(support, uint2_t{}); 1355 return responseSuccess(std::move(ret)); 1356 } 1357 case LanParam::AuthEnables: 1358 { 1359 std::bitset<6> enables; 1360 ret.pack(enables, uint2_t{}); // Callback 1361 ret.pack(enables, uint2_t{}); // User 1362 ret.pack(enables, uint2_t{}); // Operator 1363 ret.pack(enables, uint2_t{}); // Admin 1364 ret.pack(enables, uint2_t{}); // OEM 1365 return responseSuccess(std::move(ret)); 1366 } 1367 case LanParam::IP: 1368 { 1369 auto ifaddr = channelCall<getIfAddr4>(channel); 1370 in_addr addr{}; 1371 if (ifaddr) 1372 { 1373 addr = ifaddr->address; 1374 } 1375 ret.pack(dataRef(addr)); 1376 return responseSuccess(std::move(ret)); 1377 } 1378 case LanParam::IPSrc: 1379 { 1380 auto src = IPSrc::Static; 1381 if (channelCall<getDHCPProperty>(channel)) 1382 { 1383 src = IPSrc::DHCP; 1384 } 1385 ret.pack(static_cast<uint4_t>(src), uint4_t{}); 1386 return responseSuccess(std::move(ret)); 1387 } 1388 case LanParam::MAC: 1389 { 1390 ether_addr mac = channelCall<getMACProperty>(channel); 1391 ret.pack(dataRef(mac)); 1392 return responseSuccess(std::move(ret)); 1393 } 1394 case LanParam::SubnetMask: 1395 { 1396 auto ifaddr = channelCall<getIfAddr4>(channel); 1397 uint8_t prefix = AddrFamily<AF_INET>::defaultPrefix; 1398 if (ifaddr) 1399 { 1400 prefix = ifaddr->prefix; 1401 } 1402 in_addr netmask = prefixToNetmask(prefix); 1403 ret.pack(dataRef(netmask)); 1404 return responseSuccess(std::move(ret)); 1405 } 1406 case LanParam::Gateway1: 1407 { 1408 auto gateway = 1409 channelCall<getGatewayProperty<AF_INET>>(channel).value_or( 1410 in_addr{}); 1411 ret.pack(dataRef(gateway)); 1412 return responseSuccess(std::move(ret)); 1413 } 1414 case LanParam::Gateway1MAC: 1415 { 1416 ether_addr mac{}; 1417 auto neighbor = channelCall<getGatewayNeighbor<AF_INET>>(channel); 1418 if (neighbor) 1419 { 1420 mac = neighbor->mac; 1421 } 1422 ret.pack(dataRef(mac)); 1423 return responseSuccess(std::move(ret)); 1424 } 1425 case LanParam::VLANId: 1426 { 1427 uint16_t vlan = channelCall<getVLANProperty>(channel); 1428 if (vlan != 0) 1429 { 1430 vlan |= VLAN_ENABLE_FLAG; 1431 } 1432 else 1433 { 1434 vlan = lastDisabledVlan[channel]; 1435 } 1436 ret.pack(vlan); 1437 return responseSuccess(std::move(ret)); 1438 } 1439 case LanParam::CiphersuiteSupport: 1440 { 1441 if (!listInit) 1442 { 1443 return responseUnspecifiedError(); 1444 } 1445 ret.pack(static_cast<uint8_t>(cipherList.size() - 1)); 1446 return responseSuccess(std::move(ret)); 1447 } 1448 case LanParam::CiphersuiteEntries: 1449 { 1450 if (!listInit) 1451 { 1452 return responseUnspecifiedError(); 1453 } 1454 ret.pack(cipherList); 1455 return responseSuccess(std::move(ret)); 1456 } 1457 } 1458 1459 if ((parameter >= oemCmdStart) && (parameter <= oemCmdEnd)) 1460 { 1461 return getLanOem(channel, parameter, set, block); 1462 } 1463 1464 return response(ccParamNotSupported); 1465 } 1466 1467 } // namespace transport 1468 } // namespace ipmi 1469 1470 void register_netfn_transport_functions() __attribute__((constructor)); 1471 1472 void register_netfn_transport_functions() 1473 { 1474 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport, 1475 ipmi::transport::cmdSetLanConfigParameters, 1476 ipmi::Privilege::Admin, ipmi::transport::setLan); 1477 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport, 1478 ipmi::transport::cmdGetLanConfigParameters, 1479 ipmi::Privilege::Admin, ipmi::transport::getLan); 1480 } 1481