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