1*14fe6698SNan Zhou // Copyright 2021 Google LLC 2*14fe6698SNan Zhou // 3*14fe6698SNan Zhou // Licensed under the Apache License, Version 2.0 (the "License"); 4*14fe6698SNan Zhou // you may not use this file except in compliance with the License. 5*14fe6698SNan Zhou // You may obtain a copy of the License at 6*14fe6698SNan Zhou // 7*14fe6698SNan Zhou // http://www.apache.org/licenses/LICENSE-2.0 8*14fe6698SNan Zhou // 9*14fe6698SNan Zhou // Unless required by applicable law or agreed to in writing, software 10*14fe6698SNan Zhou // distributed under the License is distributed on an "AS IS" BASIS, 11*14fe6698SNan Zhou // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*14fe6698SNan Zhou // See the License for the specific language governing permissions and 13*14fe6698SNan Zhou // limitations under the License. 14*14fe6698SNan Zhou 15*14fe6698SNan Zhou #include "nemora.hpp" 16*14fe6698SNan Zhou 17*14fe6698SNan Zhou #include "default_addresses.h" 18*14fe6698SNan Zhou 19*14fe6698SNan Zhou #include <netinet/in.h> 20*14fe6698SNan Zhou #include <time.h> 21*14fe6698SNan Zhou #include <unistd.h> 22*14fe6698SNan Zhou 23*14fe6698SNan Zhou #include <phosphor-logging/log.hpp> 24*14fe6698SNan Zhou #include <sdbusplus/bus.hpp> 25*14fe6698SNan Zhou #include <sdbusplus/exception.hpp> 26*14fe6698SNan Zhou 27*14fe6698SNan Zhou #include <cstdint> 28*14fe6698SNan Zhou #include <cstring> 29*14fe6698SNan Zhou #include <functional> 30*14fe6698SNan Zhou #include <iostream> 31*14fe6698SNan Zhou #include <variant> 32*14fe6698SNan Zhou 33*14fe6698SNan Zhou using phosphor::logging::level; 34*14fe6698SNan Zhou using phosphor::logging::log; 35*14fe6698SNan Zhou using sdbusplus::exception::SdBusError; 36*14fe6698SNan Zhou 37*14fe6698SNan Zhou constexpr auto MAC_FORMAT = "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx"; 38*14fe6698SNan Zhou constexpr auto MAC_INTERFACE = "xyz.openbmc_project.Network.MACAddress"; 39*14fe6698SNan Zhou constexpr auto NETWORK_INTERFACE = "xyz.openbmc_project.Network"; 40*14fe6698SNan Zhou constexpr auto PROP_INTERFACE = "org.freedesktop.DBus.Properties"; 41*14fe6698SNan Zhou constexpr auto IFACE_ROOT = "/xyz/openbmc_project/network/"; 42*14fe6698SNan Zhou 43*14fe6698SNan Zhou bool Nemora::ParseMac(const std::string& mac_addr, MacAddr* mac) 44*14fe6698SNan Zhou { 45*14fe6698SNan Zhou int ret = 46*14fe6698SNan Zhou sscanf(mac_addr.c_str(), MAC_FORMAT, mac->octet, mac->octet + 1, 47*14fe6698SNan Zhou mac->octet + 2, mac->octet + 3, mac->octet + 4, mac->octet + 5); 48*14fe6698SNan Zhou return (ret == MAC_ADDR_SIZE); 49*14fe6698SNan Zhou } 50*14fe6698SNan Zhou 51*14fe6698SNan Zhou bool Nemora::GetMacAddr(MacAddr* mac, const std::string& iface_path) 52*14fe6698SNan Zhou { 53*14fe6698SNan Zhou if (mac == nullptr) 54*14fe6698SNan Zhou { 55*14fe6698SNan Zhou log<level::ERR>("Nemora::GetMacAddr MAC Address is nullptr"); 56*14fe6698SNan Zhou return false; 57*14fe6698SNan Zhou } 58*14fe6698SNan Zhou auto dbus = sdbusplus::bus::new_default(); 59*14fe6698SNan Zhou sdbusplus::message::message reply; 60*14fe6698SNan Zhou 61*14fe6698SNan Zhou try 62*14fe6698SNan Zhou { 63*14fe6698SNan Zhou auto networkd_call = dbus.new_method_call( 64*14fe6698SNan Zhou NETWORK_INTERFACE, iface_path.c_str(), PROP_INTERFACE, "Get"); 65*14fe6698SNan Zhou networkd_call.append(MAC_INTERFACE, "MACAddress"); 66*14fe6698SNan Zhou 67*14fe6698SNan Zhou reply = dbus.call(networkd_call); 68*14fe6698SNan Zhou } 69*14fe6698SNan Zhou catch (const SdBusError& e) 70*14fe6698SNan Zhou { 71*14fe6698SNan Zhou log<level::ERR>( 72*14fe6698SNan Zhou "Nemora::GetMacAddr failed to call Network D-Bus interface"); 73*14fe6698SNan Zhou return false; 74*14fe6698SNan Zhou } 75*14fe6698SNan Zhou 76*14fe6698SNan Zhou std::variant<std::string> result; 77*14fe6698SNan Zhou reply.read(result); 78*14fe6698SNan Zhou auto mac_addr = std::get<std::string>(result); 79*14fe6698SNan Zhou if (!ParseMac(mac_addr, mac)) 80*14fe6698SNan Zhou { 81*14fe6698SNan Zhou log<level::ERR>("Nemora::GetMacAddr Failed to parse MAC Address"); 82*14fe6698SNan Zhou return false; 83*14fe6698SNan Zhou } 84*14fe6698SNan Zhou return true; 85*14fe6698SNan Zhou } 86*14fe6698SNan Zhou 87*14fe6698SNan Zhou void Nemora::InitEventData() 88*14fe6698SNan Zhou { 89*14fe6698SNan Zhou event_data_.type = NemoraDatagramType::NemoraEvent; 90*14fe6698SNan Zhou 91*14fe6698SNan Zhou // UDP IPv4 addr for POST 92*14fe6698SNan Zhou event_data_.destination.sin_family = AF_INET; 93*14fe6698SNan Zhou event_data_.destination.sin_port = htons(DEFAULT_ADDRESSES_TARGET_PORT); 94*14fe6698SNan Zhou 95*14fe6698SNan Zhou // UDP IPv6 addr for POST 96*14fe6698SNan Zhou event_data_.destination6.sin6_family = AF_INET6; 97*14fe6698SNan Zhou event_data_.destination6.sin6_port = htons(DEFAULT_ADDRESSES_TARGET_PORT); 98*14fe6698SNan Zhou } 99*14fe6698SNan Zhou 100*14fe6698SNan Zhou Nemora::Nemora() 101*14fe6698SNan Zhou { 102*14fe6698SNan Zhou InitEventData(); 103*14fe6698SNan Zhou } 104*14fe6698SNan Zhou 105*14fe6698SNan Zhou Nemora::Nemora(const std::string& iface_name, const in_addr ipv4, 106*14fe6698SNan Zhou const in6_addr ipv6) : 107*14fe6698SNan Zhou socketManager_(), 108*14fe6698SNan Zhou hostManager_(), iface_path_{std::string(IFACE_ROOT) + iface_name} 109*14fe6698SNan Zhou { 110*14fe6698SNan Zhou InitEventData(); 111*14fe6698SNan Zhou event_data_.destination.sin_addr = ipv4; 112*14fe6698SNan Zhou event_data_.destination6.sin6_addr = ipv6; 113*14fe6698SNan Zhou } 114*14fe6698SNan Zhou 115*14fe6698SNan Zhou void Nemora::UdpPoll() 116*14fe6698SNan Zhou { 117*14fe6698SNan Zhou auto postcodes = hostManager_.DrainPostcodes(); 118*14fe6698SNan Zhou 119*14fe6698SNan Zhou // Don't bother updating if there is no POST code 120*14fe6698SNan Zhou // EC supports a flag EC_NEMORA_UDP_CONFIG_MASK_PERIODIC to send 121*14fe6698SNan Zhou // periodic updates, which is non-POR for gBMC for now. 122*14fe6698SNan Zhou bool shouldBroadcast = !postcodes.empty(); 123*14fe6698SNan Zhou 124*14fe6698SNan Zhou UpdateEventData(std::move(postcodes)); 125*14fe6698SNan Zhou 126*14fe6698SNan Zhou log<level::INFO>("UpdateEventData gets called."); 127*14fe6698SNan Zhou 128*14fe6698SNan Zhou if (shouldBroadcast) 129*14fe6698SNan Zhou { 130*14fe6698SNan Zhou log<level::INFO>("Should broadcast"); 131*14fe6698SNan Zhou std::lock_guard<std::mutex> lock(event_data_mutex_); 132*14fe6698SNan Zhou socketManager_.SendDatagram(static_cast<NemoraDatagram*>(&event_data_)); 133*14fe6698SNan Zhou } 134*14fe6698SNan Zhou 135*14fe6698SNan Zhou sleep(20); 136*14fe6698SNan Zhou } 137*14fe6698SNan Zhou 138*14fe6698SNan Zhou void Nemora::UpdateEventData(std::vector<uint64_t>&& postcodes) 139*14fe6698SNan Zhou { 140*14fe6698SNan Zhou MacAddr mac; 141*14fe6698SNan Zhou GetMacAddr(&mac, iface_path_); 142*14fe6698SNan Zhou 143*14fe6698SNan Zhou std::lock_guard<std::mutex> lock(event_data_mutex_); 144*14fe6698SNan Zhou 145*14fe6698SNan Zhou memcpy(event_data_.mac, mac.octet, sizeof(MacAddr)); 146*14fe6698SNan Zhou 147*14fe6698SNan Zhou event_data_.postcodes = std::move(postcodes); 148*14fe6698SNan Zhou event_data_.sent_time_s = time(0); 149*14fe6698SNan Zhou } 150