114fe6698SNan Zhou // Copyright 2021 Google LLC 214fe6698SNan Zhou // 314fe6698SNan Zhou // Licensed under the Apache License, Version 2.0 (the "License"); 414fe6698SNan Zhou // you may not use this file except in compliance with the License. 514fe6698SNan Zhou // You may obtain a copy of the License at 614fe6698SNan Zhou // 714fe6698SNan Zhou // http://www.apache.org/licenses/LICENSE-2.0 814fe6698SNan Zhou // 914fe6698SNan Zhou // Unless required by applicable law or agreed to in writing, software 1014fe6698SNan Zhou // distributed under the License is distributed on an "AS IS" BASIS, 1114fe6698SNan Zhou // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1214fe6698SNan Zhou // See the License for the specific language governing permissions and 1314fe6698SNan Zhou // limitations under the License. 1414fe6698SNan Zhou 1514fe6698SNan Zhou #include "nemora.hpp" 1614fe6698SNan Zhou 1714fe6698SNan Zhou #include "default_addresses.h" 1814fe6698SNan Zhou 1914fe6698SNan Zhou #include <netinet/in.h> 2014fe6698SNan Zhou #include <time.h> 2114fe6698SNan Zhou #include <unistd.h> 2214fe6698SNan Zhou 2314fe6698SNan Zhou #include <phosphor-logging/log.hpp> 2414fe6698SNan Zhou #include <sdbusplus/bus.hpp> 2514fe6698SNan Zhou #include <sdbusplus/exception.hpp> 2614fe6698SNan Zhou 2714fe6698SNan Zhou #include <cstdint> 2814fe6698SNan Zhou #include <cstring> 2914fe6698SNan Zhou #include <variant> 3014fe6698SNan Zhou 3114fe6698SNan Zhou using phosphor::logging::level; 3214fe6698SNan Zhou using phosphor::logging::log; 3314fe6698SNan Zhou using sdbusplus::exception::SdBusError; 3414fe6698SNan Zhou 3514fe6698SNan Zhou constexpr auto MAC_FORMAT = "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx"; 3614fe6698SNan Zhou constexpr auto MAC_INTERFACE = "xyz.openbmc_project.Network.MACAddress"; 3714fe6698SNan Zhou constexpr auto NETWORK_INTERFACE = "xyz.openbmc_project.Network"; 3814fe6698SNan Zhou constexpr auto PROP_INTERFACE = "org.freedesktop.DBus.Properties"; 3914fe6698SNan Zhou constexpr auto IFACE_ROOT = "/xyz/openbmc_project/network/"; 4014fe6698SNan Zhou 4114fe6698SNan Zhou bool Nemora::ParseMac(const std::string& mac_addr, MacAddr* mac) 4214fe6698SNan Zhou { 432be45238SPatrick Williams int ret = sscanf(mac_addr.c_str(), MAC_FORMAT, mac->octet, mac->octet + 1, 442be45238SPatrick Williams mac->octet + 2, mac->octet + 3, mac->octet + 4, 452be45238SPatrick Williams mac->octet + 5); 4614fe6698SNan Zhou return (ret == MAC_ADDR_SIZE); 4714fe6698SNan Zhou } 4814fe6698SNan Zhou 4914fe6698SNan Zhou bool Nemora::GetMacAddr(MacAddr* mac, const std::string& iface_path) 5014fe6698SNan Zhou { 5114fe6698SNan Zhou if (mac == nullptr) 5214fe6698SNan Zhou { 5314fe6698SNan Zhou log<level::ERR>("Nemora::GetMacAddr MAC Address is nullptr"); 5414fe6698SNan Zhou return false; 5514fe6698SNan Zhou } 5614fe6698SNan Zhou auto dbus = sdbusplus::bus::new_default(); 5759ac2c2dSPatrick Williams sdbusplus::message_t reply; 5814fe6698SNan Zhou 5914fe6698SNan Zhou try 6014fe6698SNan Zhou { 6114fe6698SNan Zhou auto networkd_call = dbus.new_method_call( 6214fe6698SNan Zhou NETWORK_INTERFACE, iface_path.c_str(), PROP_INTERFACE, "Get"); 6314fe6698SNan Zhou networkd_call.append(MAC_INTERFACE, "MACAddress"); 6414fe6698SNan Zhou 6514fe6698SNan Zhou reply = dbus.call(networkd_call); 6614fe6698SNan Zhou } 6714fe6698SNan Zhou catch (const SdBusError& e) 6814fe6698SNan Zhou { 6914fe6698SNan Zhou log<level::ERR>( 7014fe6698SNan Zhou "Nemora::GetMacAddr failed to call Network D-Bus interface"); 7114fe6698SNan Zhou return false; 7214fe6698SNan Zhou } 7314fe6698SNan Zhou 7414fe6698SNan Zhou std::variant<std::string> result; 7514fe6698SNan Zhou reply.read(result); 7614fe6698SNan Zhou auto mac_addr = std::get<std::string>(result); 7714fe6698SNan Zhou if (!ParseMac(mac_addr, mac)) 7814fe6698SNan Zhou { 7914fe6698SNan Zhou log<level::ERR>("Nemora::GetMacAddr Failed to parse MAC Address"); 8014fe6698SNan Zhou return false; 8114fe6698SNan Zhou } 8214fe6698SNan Zhou return true; 8314fe6698SNan Zhou } 8414fe6698SNan Zhou 8514fe6698SNan Zhou void Nemora::InitEventData() 8614fe6698SNan Zhou { 8714fe6698SNan Zhou event_data_.type = NemoraDatagramType::NemoraEvent; 8814fe6698SNan Zhou 8914fe6698SNan Zhou // UDP IPv4 addr for POST 9014fe6698SNan Zhou event_data_.destination.sin_family = AF_INET; 9114fe6698SNan Zhou event_data_.destination.sin_port = htons(DEFAULT_ADDRESSES_TARGET_PORT); 9214fe6698SNan Zhou 9314fe6698SNan Zhou // UDP IPv6 addr for POST 9414fe6698SNan Zhou event_data_.destination6.sin6_family = AF_INET6; 9514fe6698SNan Zhou event_data_.destination6.sin6_port = htons(DEFAULT_ADDRESSES_TARGET_PORT); 9614fe6698SNan Zhou } 9714fe6698SNan Zhou 9814fe6698SNan Zhou Nemora::Nemora() 9914fe6698SNan Zhou { 10014fe6698SNan Zhou InitEventData(); 10114fe6698SNan Zhou } 10214fe6698SNan Zhou 10314fe6698SNan Zhou Nemora::Nemora(const std::string& iface_name, const in_addr ipv4, 10414fe6698SNan Zhou const in6_addr ipv6) : 105*c66ebc35SPatrick Williams socketManager_(), hostManager_(), 106*c66ebc35SPatrick Williams iface_path_{std::string(IFACE_ROOT) + iface_name} 10714fe6698SNan Zhou { 10814fe6698SNan Zhou InitEventData(); 10914fe6698SNan Zhou event_data_.destination.sin_addr = ipv4; 11014fe6698SNan Zhou event_data_.destination6.sin6_addr = ipv6; 11114fe6698SNan Zhou } 11214fe6698SNan Zhou 11314fe6698SNan Zhou void Nemora::UdpPoll() 11414fe6698SNan Zhou { 11514fe6698SNan Zhou auto postcodes = hostManager_.DrainPostcodes(); 11614fe6698SNan Zhou 11714fe6698SNan Zhou // Don't bother updating if there is no POST code 11814fe6698SNan Zhou // EC supports a flag EC_NEMORA_UDP_CONFIG_MASK_PERIODIC to send 11914fe6698SNan Zhou // periodic updates, which is non-POR for gBMC for now. 12014fe6698SNan Zhou bool shouldBroadcast = !postcodes.empty(); 12114fe6698SNan Zhou 12214fe6698SNan Zhou UpdateEventData(std::move(postcodes)); 12314fe6698SNan Zhou 12414fe6698SNan Zhou log<level::INFO>("UpdateEventData gets called."); 12514fe6698SNan Zhou 12614fe6698SNan Zhou if (shouldBroadcast) 12714fe6698SNan Zhou { 12814fe6698SNan Zhou log<level::INFO>("Should broadcast"); 12914fe6698SNan Zhou std::lock_guard<std::mutex> lock(event_data_mutex_); 13014fe6698SNan Zhou socketManager_.SendDatagram(static_cast<NemoraDatagram*>(&event_data_)); 13114fe6698SNan Zhou } 13214fe6698SNan Zhou 13314fe6698SNan Zhou sleep(20); 13414fe6698SNan Zhou } 13514fe6698SNan Zhou 13614fe6698SNan Zhou void Nemora::UpdateEventData(std::vector<uint64_t>&& postcodes) 13714fe6698SNan Zhou { 13814fe6698SNan Zhou MacAddr mac; 13914fe6698SNan Zhou GetMacAddr(&mac, iface_path_); 14014fe6698SNan Zhou 14114fe6698SNan Zhou std::lock_guard<std::mutex> lock(event_data_mutex_); 14214fe6698SNan Zhou 14314fe6698SNan Zhou memcpy(event_data_.mac, mac.octet, sizeof(MacAddr)); 14414fe6698SNan Zhou 14514fe6698SNan Zhou event_data_.postcodes = std::move(postcodes); 14614fe6698SNan Zhou event_data_.sent_time_s = time(0); 14714fe6698SNan Zhou } 148