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