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 <functional> 3014fe6698SNan Zhou #include <iostream> 3114fe6698SNan Zhou #include <variant> 3214fe6698SNan Zhou 3314fe6698SNan Zhou using phosphor::logging::level; 3414fe6698SNan Zhou using phosphor::logging::log; 3514fe6698SNan Zhou using sdbusplus::exception::SdBusError; 3614fe6698SNan Zhou 3714fe6698SNan Zhou constexpr auto MAC_FORMAT = "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx"; 3814fe6698SNan Zhou constexpr auto MAC_INTERFACE = "xyz.openbmc_project.Network.MACAddress"; 3914fe6698SNan Zhou constexpr auto NETWORK_INTERFACE = "xyz.openbmc_project.Network"; 4014fe6698SNan Zhou constexpr auto PROP_INTERFACE = "org.freedesktop.DBus.Properties"; 4114fe6698SNan Zhou constexpr auto IFACE_ROOT = "/xyz/openbmc_project/network/"; 4214fe6698SNan Zhou 4314fe6698SNan Zhou bool Nemora::ParseMac(const std::string& mac_addr, MacAddr* mac) 4414fe6698SNan Zhou { 4514fe6698SNan Zhou int ret = 4614fe6698SNan Zhou sscanf(mac_addr.c_str(), MAC_FORMAT, mac->octet, mac->octet + 1, 4714fe6698SNan Zhou mac->octet + 2, mac->octet + 3, mac->octet + 4, mac->octet + 5); 4814fe6698SNan Zhou return (ret == MAC_ADDR_SIZE); 4914fe6698SNan Zhou } 5014fe6698SNan Zhou 5114fe6698SNan Zhou bool Nemora::GetMacAddr(MacAddr* mac, const std::string& iface_path) 5214fe6698SNan Zhou { 5314fe6698SNan Zhou if (mac == nullptr) 5414fe6698SNan Zhou { 5514fe6698SNan Zhou log<level::ERR>("Nemora::GetMacAddr MAC Address is nullptr"); 5614fe6698SNan Zhou return false; 5714fe6698SNan Zhou } 5814fe6698SNan Zhou auto dbus = sdbusplus::bus::new_default(); 59*59ac2c2dSPatrick Williams sdbusplus::message_t reply; 6014fe6698SNan Zhou 6114fe6698SNan Zhou try 6214fe6698SNan Zhou { 6314fe6698SNan Zhou auto networkd_call = dbus.new_method_call( 6414fe6698SNan Zhou NETWORK_INTERFACE, iface_path.c_str(), PROP_INTERFACE, "Get"); 6514fe6698SNan Zhou networkd_call.append(MAC_INTERFACE, "MACAddress"); 6614fe6698SNan Zhou 6714fe6698SNan Zhou reply = dbus.call(networkd_call); 6814fe6698SNan Zhou } 6914fe6698SNan Zhou catch (const SdBusError& e) 7014fe6698SNan Zhou { 7114fe6698SNan Zhou log<level::ERR>( 7214fe6698SNan Zhou "Nemora::GetMacAddr failed to call Network D-Bus interface"); 7314fe6698SNan Zhou return false; 7414fe6698SNan Zhou } 7514fe6698SNan Zhou 7614fe6698SNan Zhou std::variant<std::string> result; 7714fe6698SNan Zhou reply.read(result); 7814fe6698SNan Zhou auto mac_addr = std::get<std::string>(result); 7914fe6698SNan Zhou if (!ParseMac(mac_addr, mac)) 8014fe6698SNan Zhou { 8114fe6698SNan Zhou log<level::ERR>("Nemora::GetMacAddr Failed to parse MAC Address"); 8214fe6698SNan Zhou return false; 8314fe6698SNan Zhou } 8414fe6698SNan Zhou return true; 8514fe6698SNan Zhou } 8614fe6698SNan Zhou 8714fe6698SNan Zhou void Nemora::InitEventData() 8814fe6698SNan Zhou { 8914fe6698SNan Zhou event_data_.type = NemoraDatagramType::NemoraEvent; 9014fe6698SNan Zhou 9114fe6698SNan Zhou // UDP IPv4 addr for POST 9214fe6698SNan Zhou event_data_.destination.sin_family = AF_INET; 9314fe6698SNan Zhou event_data_.destination.sin_port = htons(DEFAULT_ADDRESSES_TARGET_PORT); 9414fe6698SNan Zhou 9514fe6698SNan Zhou // UDP IPv6 addr for POST 9614fe6698SNan Zhou event_data_.destination6.sin6_family = AF_INET6; 9714fe6698SNan Zhou event_data_.destination6.sin6_port = htons(DEFAULT_ADDRESSES_TARGET_PORT); 9814fe6698SNan Zhou } 9914fe6698SNan Zhou 10014fe6698SNan Zhou Nemora::Nemora() 10114fe6698SNan Zhou { 10214fe6698SNan Zhou InitEventData(); 10314fe6698SNan Zhou } 10414fe6698SNan Zhou 10514fe6698SNan Zhou Nemora::Nemora(const std::string& iface_name, const in_addr ipv4, 10614fe6698SNan Zhou const in6_addr ipv6) : 10714fe6698SNan Zhou socketManager_(), 10814fe6698SNan Zhou hostManager_(), iface_path_{std::string(IFACE_ROOT) + iface_name} 10914fe6698SNan Zhou { 11014fe6698SNan Zhou InitEventData(); 11114fe6698SNan Zhou event_data_.destination.sin_addr = ipv4; 11214fe6698SNan Zhou event_data_.destination6.sin6_addr = ipv6; 11314fe6698SNan Zhou } 11414fe6698SNan Zhou 11514fe6698SNan Zhou void Nemora::UdpPoll() 11614fe6698SNan Zhou { 11714fe6698SNan Zhou auto postcodes = hostManager_.DrainPostcodes(); 11814fe6698SNan Zhou 11914fe6698SNan Zhou // Don't bother updating if there is no POST code 12014fe6698SNan Zhou // EC supports a flag EC_NEMORA_UDP_CONFIG_MASK_PERIODIC to send 12114fe6698SNan Zhou // periodic updates, which is non-POR for gBMC for now. 12214fe6698SNan Zhou bool shouldBroadcast = !postcodes.empty(); 12314fe6698SNan Zhou 12414fe6698SNan Zhou UpdateEventData(std::move(postcodes)); 12514fe6698SNan Zhou 12614fe6698SNan Zhou log<level::INFO>("UpdateEventData gets called."); 12714fe6698SNan Zhou 12814fe6698SNan Zhou if (shouldBroadcast) 12914fe6698SNan Zhou { 13014fe6698SNan Zhou log<level::INFO>("Should broadcast"); 13114fe6698SNan Zhou std::lock_guard<std::mutex> lock(event_data_mutex_); 13214fe6698SNan Zhou socketManager_.SendDatagram(static_cast<NemoraDatagram*>(&event_data_)); 13314fe6698SNan Zhou } 13414fe6698SNan Zhou 13514fe6698SNan Zhou sleep(20); 13614fe6698SNan Zhou } 13714fe6698SNan Zhou 13814fe6698SNan Zhou void Nemora::UpdateEventData(std::vector<uint64_t>&& postcodes) 13914fe6698SNan Zhou { 14014fe6698SNan Zhou MacAddr mac; 14114fe6698SNan Zhou GetMacAddr(&mac, iface_path_); 14214fe6698SNan Zhou 14314fe6698SNan Zhou std::lock_guard<std::mutex> lock(event_data_mutex_); 14414fe6698SNan Zhou 14514fe6698SNan Zhou memcpy(event_data_.mac, mac.octet, sizeof(MacAddr)); 14614fe6698SNan Zhou 14714fe6698SNan Zhou event_data_.postcodes = std::move(postcodes); 14814fe6698SNan Zhou event_data_.sent_time_s = time(0); 14914fe6698SNan Zhou } 150