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