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 // When calling setDHCPv4Property, requestedDhcp only has "v4" and "none". 190 // setDHCPv4Property is only for IPv4 management. It should not modify 191 // IPv6 state. 192 if (requestedDhcp == EthernetInterface::DHCPConf::v4) 193 { 194 if ((currentDhcp == EthernetInterface::DHCPConf::v6) || 195 (currentDhcp == EthernetInterface::DHCPConf::both)) 196 nextDhcp = EthernetInterface::DHCPConf::both; 197 else if ((currentDhcp == EthernetInterface::DHCPConf::v4) || 198 (currentDhcp == EthernetInterface::DHCPConf::none)) 199 nextDhcp = EthernetInterface::DHCPConf::v4; 200 } 201 else if (requestedDhcp == EthernetInterface::DHCPConf::none) 202 { 203 if ((currentDhcp == EthernetInterface::DHCPConf::v6) || 204 (currentDhcp == EthernetInterface::DHCPConf::both)) 205 nextDhcp = EthernetInterface::DHCPConf::v6; 206 else if ((currentDhcp == EthernetInterface::DHCPConf::v4) || 207 (currentDhcp == EthernetInterface::DHCPConf::none)) 208 nextDhcp = EthernetInterface::DHCPConf::none; 209 } 210 else // Stay the same. 211 { 212 nextDhcp = currentDhcp; 213 } 214 std::string newDhcp = 215 sdbusplus::xyz::openbmc_project::Network::server::convertForMessage( 216 nextDhcp); 217 setDbusProperty(bus, params.service, params.logicalPath, INTF_ETHERNET, 218 "DHCPEnabled", newDhcp); 219 } 220 221 void setDHCPv6Property(sdbusplus::bus::bus& bus, const ChannelParams& params, 222 const EthernetInterface::DHCPConf requestedDhcp, 223 const bool defaultMode = true) 224 { 225 EthernetInterface::DHCPConf currentDhcp = getDHCPProperty(bus, params); 226 EthernetInterface::DHCPConf nextDhcp = EthernetInterface::DHCPConf::none; 227 228 if (defaultMode) 229 { 230 // When calling setDHCPv6Property, requestedDhcp only has "v6" and 231 // "none". 232 // setDHCPv6Property is only for IPv6 management. It should not modify 233 // IPv4 state. 234 if (requestedDhcp == EthernetInterface::DHCPConf::v6) 235 { 236 if ((currentDhcp == EthernetInterface::DHCPConf::v4) || 237 (currentDhcp == EthernetInterface::DHCPConf::both)) 238 nextDhcp = EthernetInterface::DHCPConf::both; 239 else if ((currentDhcp == EthernetInterface::DHCPConf::v6) || 240 (currentDhcp == EthernetInterface::DHCPConf::none)) 241 nextDhcp = EthernetInterface::DHCPConf::v6; 242 } 243 else if (requestedDhcp == EthernetInterface::DHCPConf::none) 244 { 245 if ((currentDhcp == EthernetInterface::DHCPConf::v4) || 246 (currentDhcp == EthernetInterface::DHCPConf::both)) 247 nextDhcp = EthernetInterface::DHCPConf::v4; 248 else if ((currentDhcp == EthernetInterface::DHCPConf::v6) || 249 (currentDhcp == EthernetInterface::DHCPConf::none)) 250 nextDhcp = EthernetInterface::DHCPConf::none; 251 } 252 else // Stay the same. 253 { 254 nextDhcp = currentDhcp; 255 } 256 } 257 else 258 { 259 // allow the v6 call to set any value 260 nextDhcp = requestedDhcp; 261 } 262 263 std::string newDhcp = 264 sdbusplus::xyz::openbmc_project::Network::server::convertForMessage( 265 nextDhcp); 266 setDbusProperty(bus, params.service, params.logicalPath, INTF_ETHERNET, 267 "DHCPEnabled", newDhcp); 268 } 269 270 ether_addr stringToMAC(const char* mac) 271 { 272 const ether_addr* ret = ether_aton(mac); 273 if (ret == nullptr) 274 { 275 log<level::ERR>("Invalid MAC Address", entry("MAC=%s", mac)); 276 elog<InternalFailure>(); 277 } 278 return *ret; 279 } 280 281 /** @brief Determines the MAC of the ethernet interface 282 * 283 * @param[in] bus - The bus object used for lookups 284 * @param[in] params - The parameters for the channel 285 * @return The configured mac address 286 */ 287 ether_addr getMACProperty(sdbusplus::bus::bus& bus, const ChannelParams& params) 288 { 289 auto macStr = std::get<std::string>(getDbusProperty( 290 bus, params.service, params.ifPath, INTF_MAC, "MACAddress")); 291 return stringToMAC(macStr.c_str()); 292 } 293 294 /** @brief Sets the system value for MAC address on the given interface 295 * 296 * @param[in] bus - The bus object used for lookups 297 * @param[in] params - The parameters for the channel 298 * @param[in] mac - MAC address to apply 299 */ 300 void setMACProperty(sdbusplus::bus::bus& bus, const ChannelParams& params, 301 const ether_addr& mac) 302 { 303 std::string macStr = ether_ntoa(&mac); 304 setDbusProperty(bus, params.service, params.ifPath, INTF_MAC, "MACAddress", 305 macStr); 306 } 307 308 void deleteObjectIfExists(sdbusplus::bus::bus& bus, const std::string& service, 309 const std::string& path) 310 { 311 if (path.empty()) 312 { 313 return; 314 } 315 try 316 { 317 auto req = bus.new_method_call(service.c_str(), path.c_str(), 318 ipmi::DELETE_INTERFACE, "Delete"); 319 bus.call_noreply(req); 320 } 321 catch (const sdbusplus::exception::exception& e) 322 { 323 if (strcmp(e.name(), 324 "xyz.openbmc_project.Common.Error.InternalFailure") != 0 && 325 strcmp(e.name(), "org.freedesktop.DBus.Error.UnknownObject") != 0) 326 { 327 // We want to rethrow real errors 328 throw; 329 } 330 } 331 } 332 333 /** @brief Sets the address info configured for the interface 334 * If a previous address path exists then it will be removed 335 * before the new address is added. 336 * 337 * @param[in] bus - The bus object used for lookups 338 * @param[in] params - The parameters for the channel 339 * @param[in] address - The address of the new IP 340 * @param[in] prefix - The prefix of the new IP 341 */ 342 template <int family> 343 void createIfAddr(sdbusplus::bus::bus& bus, const ChannelParams& params, 344 const typename AddrFamily<family>::addr& address, 345 uint8_t prefix) 346 { 347 auto newreq = 348 bus.new_method_call(params.service.c_str(), params.logicalPath.c_str(), 349 INTF_IP_CREATE, "IP"); 350 std::string protocol = 351 sdbusplus::xyz::openbmc_project::Network::server::convertForMessage( 352 AddrFamily<family>::protocol); 353 newreq.append(protocol, addrToString<family>(address), prefix, ""); 354 bus.call_noreply(newreq); 355 } 356 357 /** @brief Trivial helper for getting the IPv4 address from getIfAddrs() 358 * 359 * @param[in] bus - The bus object used for lookups 360 * @param[in] params - The parameters for the channel 361 * @return The address and prefix if found 362 */ 363 auto getIfAddr4(sdbusplus::bus::bus& bus, const ChannelParams& params) 364 { 365 return getIfAddr<AF_INET>(bus, params, 0, originsV4); 366 } 367 368 /** @brief Reconfigures the IPv4 address info configured for the interface 369 * 370 * @param[in] bus - The bus object used for lookups 371 * @param[in] params - The parameters for the channel 372 * @param[in] address - The new address if specified 373 * @param[in] prefix - The new address prefix if specified 374 */ 375 void reconfigureIfAddr4(sdbusplus::bus::bus& bus, const ChannelParams& params, 376 const std::optional<in_addr>& address, 377 std::optional<uint8_t> prefix) 378 { 379 auto ifaddr = getIfAddr4(bus, params); 380 if (!ifaddr && !address) 381 { 382 log<level::ERR>("Missing address for IPv4 assignment"); 383 elog<InternalFailure>(); 384 } 385 uint8_t fallbackPrefix = AddrFamily<AF_INET>::defaultPrefix; 386 if (ifaddr) 387 { 388 fallbackPrefix = ifaddr->prefix; 389 deleteObjectIfExists(bus, params.service, ifaddr->path); 390 } 391 createIfAddr<AF_INET>(bus, params, address.value_or(ifaddr->address), 392 prefix.value_or(fallbackPrefix)); 393 } 394 395 template <int family> 396 std::optional<IfNeigh<family>> findGatewayNeighbor(sdbusplus::bus::bus& bus, 397 const ChannelParams& params, 398 ObjectLookupCache& neighbors) 399 { 400 auto gateway = getGatewayProperty<family>(bus, params); 401 if (!gateway) 402 { 403 return std::nullopt; 404 } 405 406 return findStaticNeighbor<family>(bus, params, *gateway, neighbors); 407 } 408 409 template <int family> 410 std::optional<IfNeigh<family>> getGatewayNeighbor(sdbusplus::bus::bus& bus, 411 const ChannelParams& params) 412 { 413 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR); 414 return findGatewayNeighbor<family>(bus, params, neighbors); 415 } 416 417 template <int family> 418 void reconfigureGatewayMAC(sdbusplus::bus::bus& bus, 419 const ChannelParams& params, const ether_addr& mac) 420 { 421 auto gateway = getGatewayProperty<family>(bus, params); 422 if (!gateway) 423 { 424 log<level::ERR>("Tried to set Gateway MAC without Gateway"); 425 elog<InternalFailure>(); 426 } 427 428 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR); 429 auto neighbor = 430 findStaticNeighbor<family>(bus, params, *gateway, neighbors); 431 if (neighbor) 432 { 433 deleteObjectIfExists(bus, params.service, neighbor->path); 434 } 435 436 createNeighbor<family>(bus, params, *gateway, mac); 437 } 438 439 /** @brief Deconfigures the IPv6 address info configured for the interface 440 * 441 * @param[in] bus - The bus object used for lookups 442 * @param[in] params - The parameters for the channel 443 * @param[in] idx - The address index to operate on 444 */ 445 void deconfigureIfAddr6(sdbusplus::bus::bus& bus, const ChannelParams& params, 446 uint8_t idx) 447 { 448 auto ifaddr = getIfAddr<AF_INET6>(bus, params, idx, originsV6Static); 449 if (ifaddr) 450 { 451 deleteObjectIfExists(bus, params.service, ifaddr->path); 452 } 453 } 454 455 /** @brief Reconfigures the IPv6 address info configured for the interface 456 * 457 * @param[in] bus - The bus object used for lookups 458 * @param[in] params - The parameters for the channel 459 * @param[in] idx - The address index to operate on 460 * @param[in] address - The new address 461 * @param[in] prefix - The new address prefix 462 */ 463 void reconfigureIfAddr6(sdbusplus::bus::bus& bus, const ChannelParams& params, 464 uint8_t idx, const in6_addr& address, uint8_t prefix) 465 { 466 deconfigureIfAddr6(bus, params, idx); 467 createIfAddr<AF_INET6>(bus, params, address, prefix); 468 } 469 470 /** @brief Converts the AddressOrigin into an IPv6Source 471 * 472 * @param[in] origin - The DBus Address Origin to convert 473 * @return The IPv6Source version of the origin 474 */ 475 IPv6Source originToSourceType(IP::AddressOrigin origin) 476 { 477 switch (origin) 478 { 479 case IP::AddressOrigin::Static: 480 return IPv6Source::Static; 481 case IP::AddressOrigin::DHCP: 482 return IPv6Source::DHCP; 483 case IP::AddressOrigin::SLAAC: 484 return IPv6Source::SLAAC; 485 default: 486 { 487 auto originStr = sdbusplus::xyz::openbmc_project::Network::server:: 488 convertForMessage(origin); 489 log<level::ERR>( 490 "Invalid IP::AddressOrigin conversion to IPv6Source", 491 entry("ORIGIN=%s", originStr.c_str())); 492 elog<InternalFailure>(); 493 } 494 } 495 } 496 497 /** @brief Packs the IPMI message response with IPv6 address data 498 * 499 * @param[out] ret - The IPMI response payload to be packed 500 * @param[in] channel - The channel id corresponding to an ethernet interface 501 * @param[in] set - The set selector for determining address index 502 * @param[in] origins - Set of valid origins for address filtering 503 */ 504 void getLanIPv6Address(message::Payload& ret, uint8_t channel, uint8_t set, 505 const std::unordered_set<IP::AddressOrigin>& origins) 506 { 507 auto source = IPv6Source::Static; 508 bool enabled = false; 509 in6_addr addr{}; 510 uint8_t prefix{}; 511 auto status = IPv6AddressStatus::Disabled; 512 513 auto ifaddr = channelCall<getIfAddr<AF_INET6>>(channel, set, origins); 514 if (ifaddr) 515 { 516 source = originToSourceType(ifaddr->origin); 517 enabled = (origins == originsV6Static); 518 addr = ifaddr->address; 519 prefix = ifaddr->prefix; 520 status = IPv6AddressStatus::Active; 521 } 522 523 ret.pack(set); 524 ret.pack(types::enum_cast<uint4_t>(source), uint3_t{}, enabled); 525 ret.pack(std::string_view(reinterpret_cast<char*>(&addr), sizeof(addr))); 526 ret.pack(prefix); 527 ret.pack(types::enum_cast<uint8_t>(status)); 528 } 529 530 /** @brief Gets the vlan ID configured on the interface 531 * 532 * @param[in] bus - The bus object used for lookups 533 * @param[in] params - The parameters for the channel 534 * @return VLAN id or the standard 0 for no VLAN 535 */ 536 uint16_t getVLANProperty(sdbusplus::bus::bus& bus, const ChannelParams& params) 537 { 538 // VLAN devices will always have a separate logical object 539 if (params.ifPath == params.logicalPath) 540 { 541 return 0; 542 } 543 544 auto vlan = std::get<uint32_t>(getDbusProperty( 545 bus, params.service, params.logicalPath, INTF_VLAN, "Id")); 546 if ((vlan & VLAN_VALUE_MASK) != vlan) 547 { 548 logWithChannel<level::ERR>(params, "networkd returned an invalid vlan", 549 entry("VLAN=%" PRIu32, vlan)); 550 elog<InternalFailure>(); 551 } 552 return vlan; 553 } 554 555 /** @brief Deletes all of the possible configuration parameters for a channel 556 * 557 * @param[in] bus - The bus object used for lookups 558 * @param[in] params - The parameters for the channel 559 */ 560 void deconfigureChannel(sdbusplus::bus::bus& bus, ChannelParams& params) 561 { 562 // Delete all objects associated with the interface 563 auto objreq = bus.new_method_call(MAPPER_BUS_NAME, MAPPER_OBJ, MAPPER_INTF, 564 "GetSubTree"); 565 objreq.append(PATH_ROOT, 0, std::vector<std::string>{DELETE_INTERFACE}); 566 auto objreply = bus.call(objreq); 567 ObjectTree objs; 568 objreply.read(objs); 569 for (const auto& [path, impls] : objs) 570 { 571 if (path.find(params.ifname) == path.npos) 572 { 573 continue; 574 } 575 for (const auto& [service, intfs] : impls) 576 { 577 deleteObjectIfExists(bus, service, path); 578 } 579 // Update params to reflect the deletion of vlan 580 if (path == params.logicalPath) 581 { 582 params.logicalPath = params.ifPath; 583 } 584 } 585 586 // Clear out any settings on the lower physical interface 587 setDHCPv6Property(bus, params, EthernetInterface::DHCPConf::none, false); 588 } 589 590 /** @brief Creates a new VLAN on the specified interface 591 * 592 * @param[in] bus - The bus object used for lookups 593 * @param[in] params - The parameters for the channel 594 * @param[in] vlan - The id of the new vlan 595 */ 596 void createVLAN(sdbusplus::bus::bus& bus, ChannelParams& params, uint16_t vlan) 597 { 598 if (vlan == 0) 599 { 600 return; 601 } 602 603 auto req = bus.new_method_call(params.service.c_str(), PATH_ROOT, 604 INTF_VLAN_CREATE, "VLAN"); 605 req.append(params.ifname, static_cast<uint32_t>(vlan)); 606 auto reply = bus.call(req); 607 sdbusplus::message::object_path newPath; 608 reply.read(newPath); 609 params.logicalPath = std::move(newPath); 610 } 611 612 /** @brief Performs the necessary reconfiguration to change the VLAN 613 * 614 * @param[in] bus - The bus object used for lookups 615 * @param[in] params - The parameters for the channel 616 * @param[in] vlan - The new vlan id to use 617 */ 618 void reconfigureVLAN(sdbusplus::bus::bus& bus, ChannelParams& params, 619 uint16_t vlan) 620 { 621 // Unfortunatetly we don't have built-in functions to migrate our interface 622 // customizations to new VLAN interfaces, or have some kind of decoupling. 623 // We therefore must retain all of our old information, setup the new VLAN 624 // configuration, then restore the old info. 625 626 // Save info from the old logical interface 627 ObjectLookupCache ips(bus, params, INTF_IP); 628 auto ifaddr4 = findIfAddr<AF_INET>(bus, params, 0, originsV4, ips); 629 std::vector<IfAddr<AF_INET6>> ifaddrs6; 630 for (uint8_t i = 0; i < MAX_IPV6_STATIC_ADDRESSES; ++i) 631 { 632 auto ifaddr6 = 633 findIfAddr<AF_INET6>(bus, params, i, originsV6Static, ips); 634 if (!ifaddr6) 635 { 636 break; 637 } 638 ifaddrs6.push_back(std::move(*ifaddr6)); 639 } 640 EthernetInterface::DHCPConf dhcp = getDHCPProperty(bus, params); 641 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR); 642 auto neighbor4 = findGatewayNeighbor<AF_INET>(bus, params, neighbors); 643 auto neighbor6 = findGatewayNeighbor<AF_INET6>(bus, params, neighbors); 644 645 deconfigureChannel(bus, params); 646 createVLAN(bus, params, vlan); 647 648 // Re-establish the saved settings 649 setDHCPv6Property(bus, params, dhcp, false); 650 if (ifaddr4) 651 { 652 createIfAddr<AF_INET>(bus, params, ifaddr4->address, ifaddr4->prefix); 653 } 654 for (const auto& ifaddr6 : ifaddrs6) 655 { 656 createIfAddr<AF_INET6>(bus, params, ifaddr6.address, ifaddr6.prefix); 657 } 658 if (neighbor4) 659 { 660 createNeighbor<AF_INET>(bus, params, neighbor4->ip, neighbor4->mac); 661 } 662 if (neighbor6) 663 { 664 createNeighbor<AF_INET6>(bus, params, neighbor6->ip, neighbor6->mac); 665 } 666 } 667 668 /** @brief Turns a prefix into a netmask 669 * 670 * @param[in] prefix - The prefix length 671 * @return The netmask 672 */ 673 in_addr prefixToNetmask(uint8_t prefix) 674 { 675 if (prefix > 32) 676 { 677 log<level::ERR>("Invalid prefix", entry("PREFIX=%" PRIu8, prefix)); 678 elog<InternalFailure>(); 679 } 680 if (prefix == 0) 681 { 682 // Avoids 32-bit lshift by 32 UB 683 return {}; 684 } 685 return {htobe32(~UINT32_C(0) << (32 - prefix))}; 686 } 687 688 /** @brief Turns a a netmask into a prefix length 689 * 690 * @param[in] netmask - The netmask in byte form 691 * @return The prefix length 692 */ 693 uint8_t netmaskToPrefix(in_addr netmask) 694 { 695 uint32_t x = be32toh(netmask.s_addr); 696 if ((~x & (~x + 1)) != 0) 697 { 698 char maskStr[INET_ADDRSTRLEN]; 699 inet_ntop(AF_INET, &netmask, maskStr, sizeof(maskStr)); 700 log<level::ERR>("Invalid netmask", entry("NETMASK=%s", maskStr)); 701 elog<InternalFailure>(); 702 } 703 return static_cast<bool>(x) 704 ? AddrFamily<AF_INET>::defaultPrefix - __builtin_ctz(x) 705 : 0; 706 } 707 708 // We need to store this value so it can be returned to the client 709 // It is volatile so safe to store in daemon memory. 710 static std::unordered_map<uint8_t, SetStatus> setStatus; 711 712 // Until we have good support for fixed versions of IPMI tool 713 // we need to return the VLAN id for disabled VLANs. The value is only 714 // used for verification that a disable operation succeeded and will only 715 // be sent if our system indicates that vlans are disabled. 716 static std::unordered_map<uint8_t, uint16_t> lastDisabledVlan; 717 718 /** @brief Gets the set status for the channel if it exists 719 * Otherise populates and returns the default value. 720 * 721 * @param[in] channel - The channel id corresponding to an ethernet interface 722 * @return A reference to the SetStatus for the channel 723 */ 724 SetStatus& getSetStatus(uint8_t channel) 725 { 726 auto it = setStatus.find(channel); 727 if (it != setStatus.end()) 728 { 729 return it->second; 730 } 731 return setStatus[channel] = SetStatus::Complete; 732 } 733 734 /** @brief Gets the IPv6 Router Advertisement value 735 * 736 * @param[in] bus - The bus object used for lookups 737 * @param[in] params - The parameters for the channel 738 * @return networkd IPV6AcceptRA value 739 */ 740 static bool getIPv6AcceptRA(sdbusplus::bus::bus& bus, 741 const ChannelParams& params) 742 { 743 auto raEnabled = 744 std::get<bool>(getDbusProperty(bus, params.service, params.logicalPath, 745 INTF_ETHERNET, "IPv6AcceptRA")); 746 return raEnabled; 747 } 748 749 /** @brief Sets the IPv6AcceptRA flag 750 * 751 * @param[in] bus - The bus object used for lookups 752 * @param[in] params - The parameters for the channel 753 * @param[in] ipv6AcceptRA - boolean to enable/disable IPv6 Routing 754 * Advertisement 755 */ 756 void setIPv6AcceptRA(sdbusplus::bus::bus& bus, const ChannelParams& params, 757 const bool ipv6AcceptRA) 758 { 759 setDbusProperty(bus, params.service, params.logicalPath, INTF_ETHERNET, 760 "IPv6AcceptRA", ipv6AcceptRA); 761 } 762 763 /** 764 * Define placeholder command handlers for the OEM Extension bytes for the Set 765 * LAN Configuration Parameters and Get LAN Configuration Parameters 766 * commands. Using "weak" linking allows the placeholder setLanOem/getLanOem 767 * functions below to be overridden. 768 * To create handlers for your own proprietary command set: 769 * Create/modify a phosphor-ipmi-host Bitbake append file within your Yocto 770 * recipe 771 * Create C++ file(s) that define IPMI handler functions matching the 772 * function names below (i.e. setLanOem). The default name for the 773 * transport IPMI commands is transporthandler_oem.cpp. 774 * Add: 775 * EXTRA_OECONF_append = " --enable-transport-oem=yes" 776 * Create a do_compile_prepend()/do_install_append method in your 777 * bbappend file to copy the file to the build directory. 778 * Add: 779 * PROJECT_SRC_DIR := "${THISDIR}/${PN}" 780 * # Copy the "strong" functions into the working directory, overriding the 781 * # placeholder functions. 782 * do_compile_prepend(){ 783 * cp -f ${PROJECT_SRC_DIR}/transporthandler_oem.cpp ${S} 784 * } 785 * 786 * # Clean up after complilation has completed 787 * do_install_append(){ 788 * rm -f ${S}/transporthandler_oem.cpp 789 * } 790 * 791 */ 792 793 /** 794 * Define the placeholder OEM commands as having weak linkage. Create 795 * setLanOem, and getLanOem functions in the transporthandler_oem.cpp 796 * file. The functions defined there must not have the "weak" attribute 797 * applied to them. 798 */ 799 RspType<> setLanOem(uint8_t channel, uint8_t parameter, message::Payload& req) 800 __attribute__((weak)); 801 RspType<message::Payload> getLanOem(uint8_t channel, uint8_t parameter, 802 uint8_t set, uint8_t block) 803 __attribute__((weak)); 804 805 RspType<> setLanOem(uint8_t channel, uint8_t parameter, message::Payload& req) 806 { 807 req.trailingOk = true; 808 return response(ccParamNotSupported); 809 } 810 811 RspType<message::Payload> getLanOem(uint8_t channel, uint8_t parameter, 812 uint8_t set, uint8_t block) 813 { 814 return response(ccParamNotSupported); 815 } 816 /** 817 * @brief is MAC address valid. 818 * 819 * This function checks whether the MAC address is valid or not. 820 * 821 * @param[in] mac - MAC address. 822 * @return true if MAC address is valid else retun false. 823 **/ 824 bool isValidMACAddress(const ether_addr& mac) 825 { 826 // check if mac address is empty 827 if (equal(mac, ether_addr{})) 828 { 829 return false; 830 } 831 // we accept only unicast MAC addresses and same thing has been checked in 832 // phosphor-network layer. If the least significant bit of the first octet 833 // is set to 1, it is multicast MAC else it is unicast MAC address. 834 if (mac.ether_addr_octet[0] & 1) 835 { 836 return false; 837 } 838 return true; 839 } 840 841 RspType<> setLan(Context::ptr ctx, uint4_t channelBits, uint4_t reserved1, 842 uint8_t parameter, message::Payload& req) 843 { 844 const uint8_t channel = convertCurrentChannelNum( 845 static_cast<uint8_t>(channelBits), ctx->channel); 846 if (reserved1 || !isValidChannel(channel)) 847 { 848 log<level::ERR>("Set Lan - Invalid field in request"); 849 req.trailingOk = true; 850 return responseInvalidFieldRequest(); 851 } 852 853 switch (static_cast<LanParam>(parameter)) 854 { 855 case LanParam::SetStatus: 856 { 857 uint2_t flag; 858 uint6_t rsvd; 859 if (req.unpack(flag, rsvd) != 0 || !req.fullyUnpacked()) 860 { 861 return responseReqDataLenInvalid(); 862 } 863 if (rsvd) 864 { 865 return responseInvalidFieldRequest(); 866 } 867 auto status = static_cast<SetStatus>(static_cast<uint8_t>(flag)); 868 switch (status) 869 { 870 case SetStatus::Complete: 871 { 872 getSetStatus(channel) = status; 873 return responseSuccess(); 874 } 875 case SetStatus::InProgress: 876 { 877 auto& storedStatus = getSetStatus(channel); 878 if (storedStatus == SetStatus::InProgress) 879 { 880 return response(ccParamSetLocked); 881 } 882 storedStatus = status; 883 return responseSuccess(); 884 } 885 case SetStatus::Commit: 886 if (getSetStatus(channel) != SetStatus::InProgress) 887 { 888 return responseInvalidFieldRequest(); 889 } 890 return responseSuccess(); 891 } 892 return response(ccParamNotSupported); 893 } 894 case LanParam::AuthSupport: 895 { 896 req.trailingOk = true; 897 return response(ccParamReadOnly); 898 } 899 case LanParam::AuthEnables: 900 { 901 req.trailingOk = true; 902 return response(ccParamReadOnly); 903 } 904 case LanParam::IP: 905 { 906 EthernetInterface::DHCPConf dhcp = 907 channelCall<getDHCPProperty>(channel); 908 if ((dhcp == EthernetInterface::DHCPConf::v4) || 909 (dhcp == EthernetInterface::DHCPConf::both)) 910 { 911 return responseCommandNotAvailable(); 912 } 913 in_addr ip; 914 std::array<uint8_t, sizeof(ip)> bytes; 915 if (req.unpack(bytes) != 0 || !req.fullyUnpacked()) 916 { 917 return responseReqDataLenInvalid(); 918 } 919 copyInto(ip, bytes); 920 channelCall<reconfigureIfAddr4>(channel, ip, std::nullopt); 921 return responseSuccess(); 922 } 923 case LanParam::IPSrc: 924 { 925 uint4_t flag; 926 uint4_t rsvd; 927 if (req.unpack(flag, rsvd) != 0 || !req.fullyUnpacked()) 928 { 929 return responseReqDataLenInvalid(); 930 } 931 if (rsvd) 932 { 933 return responseInvalidFieldRequest(); 934 } 935 switch (static_cast<IPSrc>(static_cast<uint8_t>(flag))) 936 { 937 case IPSrc::DHCP: 938 { 939 // The IPSrc IPMI command is only for IPv4 940 // management. Modifying IPv6 state is done using 941 // a completely different Set LAN Configuration 942 // subcommand. 943 channelCall<setDHCPv4Property>( 944 channel, EthernetInterface::DHCPConf::v4); 945 return responseSuccess(); 946 } 947 case IPSrc::Unspecified: 948 case IPSrc::Static: 949 { 950 channelCall<setDHCPv4Property>( 951 channel, EthernetInterface::DHCPConf::none); 952 return responseSuccess(); 953 } 954 case IPSrc::BIOS: 955 case IPSrc::BMC: 956 { 957 return responseInvalidFieldRequest(); 958 } 959 } 960 return response(ccParamNotSupported); 961 } 962 case LanParam::MAC: 963 { 964 ether_addr mac; 965 std::array<uint8_t, sizeof(mac)> bytes; 966 if (req.unpack(bytes) != 0 || !req.fullyUnpacked()) 967 { 968 return responseReqDataLenInvalid(); 969 } 970 copyInto(mac, bytes); 971 972 if (!isValidMACAddress(mac)) 973 { 974 return responseInvalidFieldRequest(); 975 } 976 channelCall<setMACProperty>(channel, mac); 977 return responseSuccess(); 978 } 979 case LanParam::SubnetMask: 980 { 981 EthernetInterface::DHCPConf dhcp = 982 channelCall<getDHCPProperty>(channel); 983 if ((dhcp == EthernetInterface::DHCPConf::v4) || 984 (dhcp == EthernetInterface::DHCPConf::both)) 985 { 986 return responseCommandNotAvailable(); 987 } 988 in_addr netmask; 989 std::array<uint8_t, sizeof(netmask)> bytes; 990 if (req.unpack(bytes) != 0 || !req.fullyUnpacked()) 991 { 992 return responseReqDataLenInvalid(); 993 } 994 copyInto(netmask, bytes); 995 uint8_t prefix = netmaskToPrefix(netmask); 996 if (prefix < MIN_IPV4_PREFIX_LENGTH) 997 { 998 return responseInvalidFieldRequest(); 999 } 1000 channelCall<reconfigureIfAddr4>(channel, std::nullopt, prefix); 1001 return responseSuccess(); 1002 } 1003 case LanParam::Gateway1: 1004 { 1005 EthernetInterface::DHCPConf dhcp = 1006 channelCall<getDHCPProperty>(channel); 1007 if ((dhcp == EthernetInterface::DHCPConf::v4) || 1008 (dhcp == EthernetInterface::DHCPConf::both)) 1009 { 1010 return responseCommandNotAvailable(); 1011 } 1012 in_addr gateway; 1013 std::array<uint8_t, sizeof(gateway)> bytes; 1014 if (req.unpack(bytes) != 0 || !req.fullyUnpacked()) 1015 { 1016 return responseReqDataLenInvalid(); 1017 } 1018 copyInto(gateway, bytes); 1019 channelCall<setGatewayProperty<AF_INET>>(channel, gateway); 1020 return responseSuccess(); 1021 } 1022 case LanParam::Gateway1MAC: 1023 { 1024 ether_addr gatewayMAC; 1025 std::array<uint8_t, sizeof(gatewayMAC)> bytes; 1026 if (req.unpack(bytes) != 0 || !req.fullyUnpacked()) 1027 { 1028 return responseReqDataLenInvalid(); 1029 } 1030 copyInto(gatewayMAC, bytes); 1031 channelCall<reconfigureGatewayMAC<AF_INET>>(channel, gatewayMAC); 1032 return responseSuccess(); 1033 } 1034 case LanParam::VLANId: 1035 { 1036 uint12_t vlanData = 0; 1037 uint3_t reserved = 0; 1038 bool vlanEnable = 0; 1039 1040 if (req.unpack(vlanData) || req.unpack(reserved) || 1041 req.unpack(vlanEnable) || !req.fullyUnpacked()) 1042 { 1043 return responseReqDataLenInvalid(); 1044 } 1045 1046 if (reserved) 1047 { 1048 return responseInvalidFieldRequest(); 1049 } 1050 1051 uint16_t vlan = static_cast<uint16_t>(vlanData); 1052 1053 if (!vlanEnable) 1054 { 1055 lastDisabledVlan[channel] = vlan; 1056 vlan = 0; 1057 } 1058 else if (vlan == 0 || vlan == VLAN_VALUE_MASK) 1059 { 1060 return responseInvalidFieldRequest(); 1061 } 1062 1063 channelCall<reconfigureVLAN>(channel, vlan); 1064 return responseSuccess(); 1065 } 1066 case LanParam::CiphersuiteSupport: 1067 case LanParam::CiphersuiteEntries: 1068 case LanParam::IPFamilySupport: 1069 { 1070 req.trailingOk = true; 1071 return response(ccParamReadOnly); 1072 } 1073 case LanParam::IPFamilyEnables: 1074 { 1075 uint8_t enables; 1076 if (req.unpack(enables) != 0 || !req.fullyUnpacked()) 1077 { 1078 return responseReqDataLenInvalid(); 1079 } 1080 switch (static_cast<IPFamilyEnables>(enables)) 1081 { 1082 case IPFamilyEnables::DualStack: 1083 return responseSuccess(); 1084 case IPFamilyEnables::IPv4Only: 1085 case IPFamilyEnables::IPv6Only: 1086 return response(ccParamNotSupported); 1087 } 1088 return response(ccParamNotSupported); 1089 } 1090 case LanParam::IPv6Status: 1091 { 1092 req.trailingOk = true; 1093 return response(ccParamReadOnly); 1094 } 1095 case LanParam::IPv6StaticAddresses: 1096 { 1097 uint8_t set; 1098 uint7_t rsvd; 1099 bool enabled; 1100 in6_addr ip; 1101 std::array<uint8_t, sizeof(ip)> ipbytes; 1102 uint8_t prefix; 1103 uint8_t status; 1104 if (req.unpack(set, rsvd, enabled, ipbytes, prefix, status) != 0 || 1105 !req.fullyUnpacked()) 1106 { 1107 return responseReqDataLenInvalid(); 1108 } 1109 if (rsvd) 1110 { 1111 return responseInvalidFieldRequest(); 1112 } 1113 copyInto(ip, ipbytes); 1114 if (enabled) 1115 { 1116 if (prefix < MIN_IPV6_PREFIX_LENGTH || 1117 prefix > MAX_IPV6_PREFIX_LENGTH) 1118 { 1119 return responseParmOutOfRange(); 1120 } 1121 try 1122 { 1123 channelCall<reconfigureIfAddr6>(channel, set, ip, prefix); 1124 } 1125 catch (const sdbusplus::exception::exception& e) 1126 { 1127 if (std::string_view err{ 1128 "xyz.openbmc_project.Common.Error.InvalidArgument"}; 1129 err == e.name()) 1130 { 1131 return responseInvalidFieldRequest(); 1132 } 1133 else 1134 { 1135 throw; 1136 } 1137 } 1138 } 1139 else 1140 { 1141 channelCall<deconfigureIfAddr6>(channel, set); 1142 } 1143 return responseSuccess(); 1144 } 1145 case LanParam::IPv6DynamicAddresses: 1146 { 1147 req.trailingOk = true; 1148 return response(ccParamReadOnly); 1149 } 1150 case LanParam::IPv6RouterControl: 1151 { 1152 std::bitset<8> control; 1153 constexpr uint8_t reservedRACCBits = 0xfc; 1154 if (req.unpack(control) != 0 || !req.fullyUnpacked()) 1155 { 1156 return responseReqDataLenInvalid(); 1157 } 1158 if (std::bitset<8> expected(control & 1159 std::bitset<8>(reservedRACCBits)); 1160 expected.any()) 1161 { 1162 return response(ccParamNotSupported); 1163 } 1164 1165 bool enableRA = control[IPv6RouterControlFlag::Dynamic]; 1166 channelCall<setIPv6AcceptRA>(channel, enableRA); 1167 return responseSuccess(); 1168 } 1169 case LanParam::IPv6StaticRouter1IP: 1170 { 1171 in6_addr gateway; 1172 std::array<uint8_t, sizeof(gateway)> bytes; 1173 if (req.unpack(bytes) != 0 || !req.fullyUnpacked()) 1174 { 1175 return responseReqDataLenInvalid(); 1176 } 1177 copyInto(gateway, bytes); 1178 channelCall<setGatewayProperty<AF_INET6>>(channel, gateway); 1179 return responseSuccess(); 1180 } 1181 case LanParam::IPv6StaticRouter1MAC: 1182 { 1183 ether_addr mac; 1184 std::array<uint8_t, sizeof(mac)> bytes; 1185 if (req.unpack(bytes) != 0 || !req.fullyUnpacked()) 1186 { 1187 return responseReqDataLenInvalid(); 1188 } 1189 copyInto(mac, bytes); 1190 channelCall<reconfigureGatewayMAC<AF_INET6>>(channel, mac); 1191 return responseSuccess(); 1192 } 1193 case LanParam::IPv6StaticRouter1PrefixLength: 1194 { 1195 uint8_t prefix; 1196 if (req.unpack(prefix) != 0 || !req.fullyUnpacked()) 1197 { 1198 return responseReqDataLenInvalid(); 1199 } 1200 if (prefix != 0) 1201 { 1202 return responseInvalidFieldRequest(); 1203 } 1204 return responseSuccess(); 1205 } 1206 case LanParam::IPv6StaticRouter1PrefixValue: 1207 { 1208 std::array<uint8_t, sizeof(in6_addr)> bytes; 1209 if (req.unpack(bytes) != 0 || !req.fullyUnpacked()) 1210 { 1211 return responseReqDataLenInvalid(); 1212 } 1213 // Accept any prefix value since our prefix length has to be 0 1214 return responseSuccess(); 1215 } 1216 case LanParam::cipherSuitePrivilegeLevels: 1217 { 1218 uint8_t reserved; 1219 std::array<uint4_t, ipmi::maxCSRecords> cipherSuitePrivs; 1220 1221 if (req.unpack(reserved, cipherSuitePrivs) || !req.fullyUnpacked()) 1222 { 1223 return responseReqDataLenInvalid(); 1224 } 1225 1226 if (reserved) 1227 { 1228 return responseInvalidFieldRequest(); 1229 } 1230 1231 uint8_t resp = 1232 getCipherConfigObject(csPrivFileName, csPrivDefaultFileName) 1233 .setCSPrivilegeLevels(channel, cipherSuitePrivs); 1234 if (!resp) 1235 { 1236 return responseSuccess(); 1237 } 1238 else 1239 { 1240 req.trailingOk = true; 1241 return response(resp); 1242 } 1243 } 1244 } 1245 1246 if ((parameter >= oemCmdStart) && (parameter <= oemCmdEnd)) 1247 { 1248 return setLanOem(channel, parameter, req); 1249 } 1250 1251 req.trailingOk = true; 1252 return response(ccParamNotSupported); 1253 } 1254 1255 RspType<message::Payload> getLan(Context::ptr ctx, uint4_t channelBits, 1256 uint3_t reserved, bool revOnly, 1257 uint8_t parameter, uint8_t set, uint8_t block) 1258 { 1259 message::Payload ret; 1260 constexpr uint8_t current_revision = 0x11; 1261 ret.pack(current_revision); 1262 1263 if (revOnly) 1264 { 1265 return responseSuccess(std::move(ret)); 1266 } 1267 1268 const uint8_t channel = convertCurrentChannelNum( 1269 static_cast<uint8_t>(channelBits), ctx->channel); 1270 if (reserved || !isValidChannel(channel)) 1271 { 1272 log<level::ERR>("Get Lan - Invalid field in request"); 1273 return responseInvalidFieldRequest(); 1274 } 1275 1276 static std::vector<uint8_t> cipherList; 1277 static bool listInit = false; 1278 if (!listInit) 1279 { 1280 try 1281 { 1282 cipherList = cipher::getCipherList(); 1283 listInit = true; 1284 } 1285 catch (const std::exception& e) 1286 { 1287 } 1288 } 1289 1290 switch (static_cast<LanParam>(parameter)) 1291 { 1292 case LanParam::SetStatus: 1293 { 1294 SetStatus status; 1295 try 1296 { 1297 status = setStatus.at(channel); 1298 } 1299 catch (const std::out_of_range&) 1300 { 1301 status = SetStatus::Complete; 1302 } 1303 ret.pack(types::enum_cast<uint2_t>(status), uint6_t{}); 1304 return responseSuccess(std::move(ret)); 1305 } 1306 case LanParam::AuthSupport: 1307 { 1308 std::bitset<6> support; 1309 ret.pack(support, uint2_t{}); 1310 return responseSuccess(std::move(ret)); 1311 } 1312 case LanParam::AuthEnables: 1313 { 1314 std::bitset<6> enables; 1315 ret.pack(enables, uint2_t{}); // Callback 1316 ret.pack(enables, uint2_t{}); // User 1317 ret.pack(enables, uint2_t{}); // Operator 1318 ret.pack(enables, uint2_t{}); // Admin 1319 ret.pack(enables, uint2_t{}); // OEM 1320 return responseSuccess(std::move(ret)); 1321 } 1322 case LanParam::IP: 1323 { 1324 auto ifaddr = channelCall<getIfAddr4>(channel); 1325 in_addr addr{}; 1326 if (ifaddr) 1327 { 1328 addr = ifaddr->address; 1329 } 1330 ret.pack(dataRef(addr)); 1331 return responseSuccess(std::move(ret)); 1332 } 1333 case LanParam::IPSrc: 1334 { 1335 auto src = IPSrc::Static; 1336 EthernetInterface::DHCPConf dhcp = 1337 channelCall<getDHCPProperty>(channel); 1338 if ((dhcp == EthernetInterface::DHCPConf::v4) || 1339 (dhcp == EthernetInterface::DHCPConf::both)) 1340 { 1341 src = IPSrc::DHCP; 1342 } 1343 ret.pack(types::enum_cast<uint4_t>(src), uint4_t{}); 1344 return responseSuccess(std::move(ret)); 1345 } 1346 case LanParam::MAC: 1347 { 1348 ether_addr mac = channelCall<getMACProperty>(channel); 1349 ret.pack(dataRef(mac)); 1350 return responseSuccess(std::move(ret)); 1351 } 1352 case LanParam::SubnetMask: 1353 { 1354 auto ifaddr = channelCall<getIfAddr4>(channel); 1355 uint8_t prefix = AddrFamily<AF_INET>::defaultPrefix; 1356 if (ifaddr) 1357 { 1358 prefix = ifaddr->prefix; 1359 } 1360 in_addr netmask = prefixToNetmask(prefix); 1361 ret.pack(dataRef(netmask)); 1362 return responseSuccess(std::move(ret)); 1363 } 1364 case LanParam::Gateway1: 1365 { 1366 auto gateway = 1367 channelCall<getGatewayProperty<AF_INET>>(channel).value_or( 1368 in_addr{}); 1369 ret.pack(dataRef(gateway)); 1370 return responseSuccess(std::move(ret)); 1371 } 1372 case LanParam::Gateway1MAC: 1373 { 1374 ether_addr mac{}; 1375 auto neighbor = channelCall<getGatewayNeighbor<AF_INET>>(channel); 1376 if (neighbor) 1377 { 1378 mac = neighbor->mac; 1379 } 1380 ret.pack(dataRef(mac)); 1381 return responseSuccess(std::move(ret)); 1382 } 1383 case LanParam::VLANId: 1384 { 1385 uint16_t vlan = channelCall<getVLANProperty>(channel); 1386 if (vlan != 0) 1387 { 1388 vlan |= VLAN_ENABLE_FLAG; 1389 } 1390 else 1391 { 1392 vlan = lastDisabledVlan[channel]; 1393 } 1394 ret.pack(vlan); 1395 return responseSuccess(std::move(ret)); 1396 } 1397 case LanParam::CiphersuiteSupport: 1398 { 1399 if (getChannelSessionSupport(channel) == 1400 EChannelSessSupported::none) 1401 { 1402 return responseInvalidFieldRequest(); 1403 } 1404 if (!listInit) 1405 { 1406 return responseUnspecifiedError(); 1407 } 1408 ret.pack(static_cast<uint8_t>(cipherList.size() - 1)); 1409 return responseSuccess(std::move(ret)); 1410 } 1411 case LanParam::CiphersuiteEntries: 1412 { 1413 if (getChannelSessionSupport(channel) == 1414 EChannelSessSupported::none) 1415 { 1416 return responseInvalidFieldRequest(); 1417 } 1418 if (!listInit) 1419 { 1420 return responseUnspecifiedError(); 1421 } 1422 ret.pack(cipherList); 1423 return responseSuccess(std::move(ret)); 1424 } 1425 case LanParam::IPFamilySupport: 1426 { 1427 std::bitset<8> support; 1428 support[IPFamilySupportFlag::IPv6Only] = 0; 1429 support[IPFamilySupportFlag::DualStack] = 1; 1430 support[IPFamilySupportFlag::IPv6Alerts] = 1; 1431 ret.pack(support); 1432 return responseSuccess(std::move(ret)); 1433 } 1434 case LanParam::IPFamilyEnables: 1435 { 1436 ret.pack(static_cast<uint8_t>(IPFamilyEnables::DualStack)); 1437 return responseSuccess(std::move(ret)); 1438 } 1439 case LanParam::IPv6Status: 1440 { 1441 ret.pack(MAX_IPV6_STATIC_ADDRESSES); 1442 ret.pack(MAX_IPV6_DYNAMIC_ADDRESSES); 1443 std::bitset<8> support; 1444 support[IPv6StatusFlag::DHCP] = 1; 1445 support[IPv6StatusFlag::SLAAC] = 1; 1446 ret.pack(support); 1447 return responseSuccess(std::move(ret)); 1448 } 1449 case LanParam::IPv6StaticAddresses: 1450 { 1451 if (set >= MAX_IPV6_STATIC_ADDRESSES) 1452 { 1453 return responseParmOutOfRange(); 1454 } 1455 getLanIPv6Address(ret, channel, set, originsV6Static); 1456 return responseSuccess(std::move(ret)); 1457 } 1458 case LanParam::IPv6DynamicAddresses: 1459 { 1460 if (set >= MAX_IPV6_DYNAMIC_ADDRESSES) 1461 { 1462 return responseParmOutOfRange(); 1463 } 1464 getLanIPv6Address(ret, channel, set, originsV6Dynamic); 1465 return responseSuccess(std::move(ret)); 1466 } 1467 case LanParam::IPv6RouterControl: 1468 { 1469 std::bitset<8> control; 1470 control[IPv6RouterControlFlag::Dynamic] = 1471 channelCall<getIPv6AcceptRA>(channel); 1472 control[IPv6RouterControlFlag::Static] = 1; 1473 ret.pack(control); 1474 return responseSuccess(std::move(ret)); 1475 } 1476 case LanParam::IPv6StaticRouter1IP: 1477 { 1478 in6_addr gateway{}; 1479 EthernetInterface::DHCPConf dhcp = 1480 channelCall<getDHCPProperty>(channel); 1481 if ((dhcp == EthernetInterface::DHCPConf::v4) || 1482 (dhcp == EthernetInterface::DHCPConf::none)) 1483 { 1484 gateway = 1485 channelCall<getGatewayProperty<AF_INET6>>(channel).value_or( 1486 in6_addr{}); 1487 } 1488 ret.pack(dataRef(gateway)); 1489 return responseSuccess(std::move(ret)); 1490 } 1491 case LanParam::IPv6StaticRouter1MAC: 1492 { 1493 ether_addr mac{}; 1494 auto neighbor = channelCall<getGatewayNeighbor<AF_INET6>>(channel); 1495 if (neighbor) 1496 { 1497 mac = neighbor->mac; 1498 } 1499 ret.pack(dataRef(mac)); 1500 return responseSuccess(std::move(ret)); 1501 } 1502 case LanParam::IPv6StaticRouter1PrefixLength: 1503 { 1504 ret.pack(UINT8_C(0)); 1505 return responseSuccess(std::move(ret)); 1506 } 1507 case LanParam::IPv6StaticRouter1PrefixValue: 1508 { 1509 in6_addr prefix{}; 1510 ret.pack(dataRef(prefix)); 1511 return responseSuccess(std::move(ret)); 1512 } 1513 case LanParam::cipherSuitePrivilegeLevels: 1514 { 1515 std::array<uint4_t, ipmi::maxCSRecords> csPrivilegeLevels; 1516 1517 uint8_t resp = 1518 getCipherConfigObject(csPrivFileName, csPrivDefaultFileName) 1519 .getCSPrivilegeLevels(channel, csPrivilegeLevels); 1520 if (!resp) 1521 { 1522 constexpr uint8_t reserved1 = 0x00; 1523 ret.pack(reserved1, csPrivilegeLevels); 1524 return responseSuccess(std::move(ret)); 1525 } 1526 else 1527 { 1528 return response(resp); 1529 } 1530 } 1531 } 1532 1533 if ((parameter >= oemCmdStart) && (parameter <= oemCmdEnd)) 1534 { 1535 return getLanOem(channel, parameter, set, block); 1536 } 1537 1538 return response(ccParamNotSupported); 1539 } 1540 1541 constexpr const char* solInterface = "xyz.openbmc_project.Ipmi.SOL"; 1542 constexpr const char* solPath = "/xyz/openbmc_project/ipmi/sol/"; 1543 constexpr const uint16_t solDefaultPort = 623; 1544 1545 RspType<> setSolConfParams(Context::ptr ctx, uint4_t channelBits, 1546 uint4_t reserved, uint8_t parameter, 1547 message::Payload& req) 1548 { 1549 const uint8_t channel = convertCurrentChannelNum( 1550 static_cast<uint8_t>(channelBits), ctx->channel); 1551 1552 if (!isValidChannel(channel)) 1553 { 1554 log<level::ERR>("Set Sol Config - Invalid channel in request"); 1555 return responseInvalidFieldRequest(); 1556 } 1557 1558 std::string solService{}; 1559 std::string solPathWitheEthName = solPath + ipmi::getChannelName(channel); 1560 1561 if (ipmi::getService(ctx, solInterface, solPathWitheEthName, solService)) 1562 { 1563 log<level::ERR>("Set Sol Config - Invalid solInterface", 1564 entry("SERVICE=%s", solService.c_str()), 1565 entry("OBJPATH=%s", solPathWitheEthName.c_str()), 1566 entry("INTERFACE=%s", solInterface)); 1567 return responseInvalidFieldRequest(); 1568 } 1569 1570 switch (static_cast<SolConfParam>(parameter)) 1571 { 1572 case SolConfParam::Progress: 1573 { 1574 uint8_t progress; 1575 if (req.unpack(progress) != 0 || !req.fullyUnpacked()) 1576 { 1577 return responseReqDataLenInvalid(); 1578 } 1579 1580 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName, 1581 solInterface, "Progress", progress)) 1582 { 1583 return responseUnspecifiedError(); 1584 } 1585 break; 1586 } 1587 case SolConfParam::Enable: 1588 { 1589 bool enable; 1590 uint7_t reserved2; 1591 1592 if (req.unpack(enable, reserved2) != 0 || !req.fullyUnpacked()) 1593 { 1594 return responseReqDataLenInvalid(); 1595 } 1596 1597 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName, 1598 solInterface, "Enable", enable)) 1599 { 1600 return responseUnspecifiedError(); 1601 } 1602 break; 1603 } 1604 case SolConfParam::Authentication: 1605 { 1606 uint4_t privilegeBits{}; 1607 uint2_t reserved2{}; 1608 bool forceAuth = false; 1609 bool forceEncrypt = false; 1610 1611 if (req.unpack(privilegeBits, reserved2, forceAuth, forceEncrypt) != 1612 0 || 1613 !req.fullyUnpacked()) 1614 { 1615 return responseReqDataLenInvalid(); 1616 } 1617 1618 uint8_t privilege = static_cast<uint8_t>(privilegeBits); 1619 if (privilege < static_cast<uint8_t>(Privilege::None) || 1620 privilege > static_cast<uint8_t>(Privilege::Oem)) 1621 { 1622 return ipmi::responseInvalidFieldRequest(); 1623 } 1624 1625 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName, 1626 solInterface, "Privilege", privilege)) 1627 { 1628 return responseUnspecifiedError(); 1629 } 1630 1631 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName, 1632 solInterface, "ForceEncryption", 1633 forceEncrypt)) 1634 { 1635 return responseUnspecifiedError(); 1636 } 1637 1638 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName, 1639 solInterface, "ForceAuthentication", 1640 forceAuth)) 1641 { 1642 return responseUnspecifiedError(); 1643 } 1644 break; 1645 } 1646 case SolConfParam::Accumulate: 1647 { 1648 uint8_t interval; 1649 uint8_t threshold; 1650 if (req.unpack(interval, threshold) != 0 || !req.fullyUnpacked()) 1651 { 1652 return responseReqDataLenInvalid(); 1653 } 1654 1655 if (threshold == 0) 1656 { 1657 return responseInvalidFieldRequest(); 1658 } 1659 1660 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName, 1661 solInterface, "AccumulateIntervalMS", 1662 interval)) 1663 { 1664 return responseUnspecifiedError(); 1665 } 1666 1667 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName, 1668 solInterface, "Threshold", threshold)) 1669 { 1670 return responseUnspecifiedError(); 1671 } 1672 break; 1673 } 1674 case SolConfParam::Retry: 1675 { 1676 uint3_t countBits; 1677 uint5_t reserved2; 1678 uint8_t interval; 1679 1680 if (req.unpack(countBits, reserved2, interval) != 0 || 1681 !req.fullyUnpacked()) 1682 { 1683 return responseReqDataLenInvalid(); 1684 } 1685 1686 uint8_t count = static_cast<uint8_t>(countBits); 1687 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName, 1688 solInterface, "RetryCount", count)) 1689 { 1690 return responseUnspecifiedError(); 1691 } 1692 1693 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName, 1694 solInterface, "RetryIntervalMS", 1695 interval)) 1696 { 1697 return responseUnspecifiedError(); 1698 } 1699 break; 1700 } 1701 case SolConfParam::Port: 1702 { 1703 return response(ipmiCCWriteReadParameter); 1704 } 1705 case SolConfParam::NonVbitrate: 1706 case SolConfParam::Vbitrate: 1707 case SolConfParam::Channel: 1708 default: 1709 return response(ipmiCCParamNotSupported); 1710 } 1711 return responseSuccess(); 1712 } 1713 1714 RspType<message::Payload> getSolConfParams(Context::ptr ctx, 1715 uint4_t channelBits, 1716 uint3_t reserved, bool revOnly, 1717 uint8_t parameter, uint8_t set, 1718 uint8_t block) 1719 { 1720 message::Payload ret; 1721 constexpr uint8_t current_revision = 0x11; 1722 ret.pack(current_revision); 1723 if (revOnly) 1724 { 1725 return responseSuccess(std::move(ret)); 1726 } 1727 1728 const uint8_t channel = convertCurrentChannelNum( 1729 static_cast<uint8_t>(channelBits), ctx->channel); 1730 1731 if (!isValidChannel(channel)) 1732 { 1733 log<level::ERR>("Get Sol Config - Invalid channel in request"); 1734 return responseInvalidFieldRequest(); 1735 } 1736 1737 std::string solService{}; 1738 std::string solPathWitheEthName = solPath + ipmi::getChannelName(channel); 1739 1740 if (ipmi::getService(ctx, solInterface, solPathWitheEthName, solService)) 1741 { 1742 log<level::ERR>("Set Sol Config - Invalid solInterface", 1743 entry("SERVICE=%s", solService.c_str()), 1744 entry("OBJPATH=%s", solPathWitheEthName.c_str()), 1745 entry("INTERFACE=%s", solInterface)); 1746 return responseInvalidFieldRequest(); 1747 } 1748 1749 switch (static_cast<SolConfParam>(parameter)) 1750 { 1751 case SolConfParam::Progress: 1752 { 1753 uint8_t progress; 1754 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName, 1755 solInterface, "Progress", progress)) 1756 { 1757 return responseUnspecifiedError(); 1758 } 1759 ret.pack(progress); 1760 return responseSuccess(std::move(ret)); 1761 } 1762 case SolConfParam::Enable: 1763 { 1764 bool enable{}; 1765 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName, 1766 solInterface, "Enable", enable)) 1767 { 1768 return responseUnspecifiedError(); 1769 } 1770 ret.pack(enable, uint7_t{}); 1771 return responseSuccess(std::move(ret)); 1772 } 1773 case SolConfParam::Authentication: 1774 { 1775 // 4bits, cast when pack 1776 uint8_t privilege; 1777 bool forceAuth = false; 1778 bool forceEncrypt = false; 1779 1780 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName, 1781 solInterface, "Privilege", privilege)) 1782 { 1783 return responseUnspecifiedError(); 1784 } 1785 1786 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName, 1787 solInterface, "ForceAuthentication", 1788 forceAuth)) 1789 { 1790 return responseUnspecifiedError(); 1791 } 1792 1793 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName, 1794 solInterface, "ForceEncryption", 1795 forceEncrypt)) 1796 { 1797 return responseUnspecifiedError(); 1798 } 1799 ret.pack(uint4_t{privilege}, uint2_t{}, forceAuth, forceEncrypt); 1800 return responseSuccess(std::move(ret)); 1801 } 1802 case SolConfParam::Accumulate: 1803 { 1804 uint8_t interval{}, threshold{}; 1805 1806 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName, 1807 solInterface, "AccumulateIntervalMS", 1808 interval)) 1809 { 1810 return responseUnspecifiedError(); 1811 } 1812 1813 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName, 1814 solInterface, "Threshold", threshold)) 1815 { 1816 return responseUnspecifiedError(); 1817 } 1818 ret.pack(interval, threshold); 1819 return responseSuccess(std::move(ret)); 1820 } 1821 case SolConfParam::Retry: 1822 { 1823 // 3bits, cast when cast 1824 uint8_t count{}; 1825 uint8_t interval{}; 1826 1827 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName, 1828 solInterface, "RetryCount", count)) 1829 { 1830 return responseUnspecifiedError(); 1831 } 1832 1833 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName, 1834 solInterface, "RetryIntervalMS", 1835 interval)) 1836 { 1837 return responseUnspecifiedError(); 1838 } 1839 ret.pack(uint3_t{count}, uint5_t{}, interval); 1840 return responseSuccess(std::move(ret)); 1841 } 1842 case SolConfParam::Port: 1843 { 1844 auto port = solDefaultPort; 1845 ret.pack(static_cast<uint16_t>(port)); 1846 return responseSuccess(std::move(ret)); 1847 } 1848 case SolConfParam::Channel: 1849 { 1850 ret.pack(channel); 1851 return responseSuccess(std::move(ret)); 1852 } 1853 case SolConfParam::NonVbitrate: 1854 case SolConfParam::Vbitrate: 1855 default: 1856 return response(ipmiCCParamNotSupported); 1857 } 1858 1859 return response(ccParamNotSupported); 1860 } 1861 1862 } // namespace transport 1863 } // namespace ipmi 1864 1865 void register_netfn_transport_functions() __attribute__((constructor)); 1866 1867 void register_netfn_transport_functions() 1868 { 1869 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport, 1870 ipmi::transport::cmdSetLanConfigParameters, 1871 ipmi::Privilege::Admin, ipmi::transport::setLan); 1872 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport, 1873 ipmi::transport::cmdGetLanConfigParameters, 1874 ipmi::Privilege::Operator, ipmi::transport::getLan); 1875 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport, 1876 ipmi::transport::cmdSetSolConfigParameters, 1877 ipmi::Privilege::Admin, 1878 ipmi::transport::setSolConfParams); 1879 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport, 1880 ipmi::transport::cmdGetSolConfigParameters, 1881 ipmi::Privilege::User, 1882 ipmi::transport::getSolConfParams); 1883 } 1884