// Copyright 2021 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "nemora.hpp" #include "default_addresses.h" #include #include #include #include #include #include #include #include #include #include #include using phosphor::logging::level; using phosphor::logging::log; using sdbusplus::exception::SdBusError; constexpr auto MAC_FORMAT = "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx"; constexpr auto MAC_INTERFACE = "xyz.openbmc_project.Network.MACAddress"; constexpr auto NETWORK_INTERFACE = "xyz.openbmc_project.Network"; constexpr auto PROP_INTERFACE = "org.freedesktop.DBus.Properties"; constexpr auto IFACE_ROOT = "/xyz/openbmc_project/network/"; bool Nemora::ParseMac(const std::string& mac_addr, MacAddr* mac) { int ret = sscanf(mac_addr.c_str(), MAC_FORMAT, mac->octet, mac->octet + 1, mac->octet + 2, mac->octet + 3, mac->octet + 4, mac->octet + 5); return (ret == MAC_ADDR_SIZE); } bool Nemora::GetMacAddr(MacAddr* mac, const std::string& iface_path) { if (mac == nullptr) { log("Nemora::GetMacAddr MAC Address is nullptr"); return false; } auto dbus = sdbusplus::bus::new_default(); sdbusplus::message::message reply; try { auto networkd_call = dbus.new_method_call( NETWORK_INTERFACE, iface_path.c_str(), PROP_INTERFACE, "Get"); networkd_call.append(MAC_INTERFACE, "MACAddress"); reply = dbus.call(networkd_call); } catch (const SdBusError& e) { log( "Nemora::GetMacAddr failed to call Network D-Bus interface"); return false; } std::variant result; reply.read(result); auto mac_addr = std::get(result); if (!ParseMac(mac_addr, mac)) { log("Nemora::GetMacAddr Failed to parse MAC Address"); return false; } return true; } void Nemora::InitEventData() { event_data_.type = NemoraDatagramType::NemoraEvent; // UDP IPv4 addr for POST event_data_.destination.sin_family = AF_INET; event_data_.destination.sin_port = htons(DEFAULT_ADDRESSES_TARGET_PORT); // UDP IPv6 addr for POST event_data_.destination6.sin6_family = AF_INET6; event_data_.destination6.sin6_port = htons(DEFAULT_ADDRESSES_TARGET_PORT); } Nemora::Nemora() { InitEventData(); } Nemora::Nemora(const std::string& iface_name, const in_addr ipv4, const in6_addr ipv6) : socketManager_(), hostManager_(), iface_path_{std::string(IFACE_ROOT) + iface_name} { InitEventData(); event_data_.destination.sin_addr = ipv4; event_data_.destination6.sin6_addr = ipv6; } void Nemora::UdpPoll() { auto postcodes = hostManager_.DrainPostcodes(); // Don't bother updating if there is no POST code // EC supports a flag EC_NEMORA_UDP_CONFIG_MASK_PERIODIC to send // periodic updates, which is non-POR for gBMC for now. bool shouldBroadcast = !postcodes.empty(); UpdateEventData(std::move(postcodes)); log("UpdateEventData gets called."); if (shouldBroadcast) { log("Should broadcast"); std::lock_guard lock(event_data_mutex_); socketManager_.SendDatagram(static_cast(&event_data_)); } sleep(20); } void Nemora::UpdateEventData(std::vector&& postcodes) { MacAddr mac; GetMacAddr(&mac, iface_path_); std::lock_guard lock(event_data_mutex_); memcpy(event_data_.mac, mac.octet, sizeof(MacAddr)); event_data_.postcodes = std::move(postcodes); event_data_.sent_time_s = time(0); }