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