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 <functional> 30 #include <iostream> 31 #include <variant> 32 33 using phosphor::logging::level; 34 using phosphor::logging::log; 35 using sdbusplus::exception::SdBusError; 36 37 constexpr auto MAC_FORMAT = "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx"; 38 constexpr auto MAC_INTERFACE = "xyz.openbmc_project.Network.MACAddress"; 39 constexpr auto NETWORK_INTERFACE = "xyz.openbmc_project.Network"; 40 constexpr auto PROP_INTERFACE = "org.freedesktop.DBus.Properties"; 41 constexpr auto IFACE_ROOT = "/xyz/openbmc_project/network/"; 42 43 bool Nemora::ParseMac(const std::string& mac_addr, MacAddr* mac) 44 { 45 int ret = 46 sscanf(mac_addr.c_str(), MAC_FORMAT, mac->octet, mac->octet + 1, 47 mac->octet + 2, mac->octet + 3, mac->octet + 4, mac->octet + 5); 48 return (ret == MAC_ADDR_SIZE); 49 } 50 51 bool Nemora::GetMacAddr(MacAddr* mac, const std::string& iface_path) 52 { 53 if (mac == nullptr) 54 { 55 log<level::ERR>("Nemora::GetMacAddr MAC Address is nullptr"); 56 return false; 57 } 58 auto dbus = sdbusplus::bus::new_default(); 59 sdbusplus::message::message reply; 60 61 try 62 { 63 auto networkd_call = dbus.new_method_call( 64 NETWORK_INTERFACE, iface_path.c_str(), PROP_INTERFACE, "Get"); 65 networkd_call.append(MAC_INTERFACE, "MACAddress"); 66 67 reply = dbus.call(networkd_call); 68 } 69 catch (const SdBusError& e) 70 { 71 log<level::ERR>( 72 "Nemora::GetMacAddr failed to call Network D-Bus interface"); 73 return false; 74 } 75 76 std::variant<std::string> result; 77 reply.read(result); 78 auto mac_addr = std::get<std::string>(result); 79 if (!ParseMac(mac_addr, mac)) 80 { 81 log<level::ERR>("Nemora::GetMacAddr Failed to parse MAC Address"); 82 return false; 83 } 84 return true; 85 } 86 87 void Nemora::InitEventData() 88 { 89 event_data_.type = NemoraDatagramType::NemoraEvent; 90 91 // UDP IPv4 addr for POST 92 event_data_.destination.sin_family = AF_INET; 93 event_data_.destination.sin_port = htons(DEFAULT_ADDRESSES_TARGET_PORT); 94 95 // UDP IPv6 addr for POST 96 event_data_.destination6.sin6_family = AF_INET6; 97 event_data_.destination6.sin6_port = htons(DEFAULT_ADDRESSES_TARGET_PORT); 98 } 99 100 Nemora::Nemora() 101 { 102 InitEventData(); 103 } 104 105 Nemora::Nemora(const std::string& iface_name, const in_addr ipv4, 106 const in6_addr ipv6) : 107 socketManager_(), 108 hostManager_(), iface_path_{std::string(IFACE_ROOT) + iface_name} 109 { 110 InitEventData(); 111 event_data_.destination.sin_addr = ipv4; 112 event_data_.destination6.sin6_addr = ipv6; 113 } 114 115 void Nemora::UdpPoll() 116 { 117 auto postcodes = hostManager_.DrainPostcodes(); 118 119 // Don't bother updating if there is no POST code 120 // EC supports a flag EC_NEMORA_UDP_CONFIG_MASK_PERIODIC to send 121 // periodic updates, which is non-POR for gBMC for now. 122 bool shouldBroadcast = !postcodes.empty(); 123 124 UpdateEventData(std::move(postcodes)); 125 126 log<level::INFO>("UpdateEventData gets called."); 127 128 if (shouldBroadcast) 129 { 130 log<level::INFO>("Should broadcast"); 131 std::lock_guard<std::mutex> lock(event_data_mutex_); 132 socketManager_.SendDatagram(static_cast<NemoraDatagram*>(&event_data_)); 133 } 134 135 sleep(20); 136 } 137 138 void Nemora::UpdateEventData(std::vector<uint64_t>&& postcodes) 139 { 140 MacAddr mac; 141 GetMacAddr(&mac, iface_path_); 142 143 std::lock_guard<std::mutex> lock(event_data_mutex_); 144 145 memcpy(event_data_.mac, mac.octet, sizeof(MacAddr)); 146 147 event_data_.postcodes = std::move(postcodes); 148 event_data_.sent_time_s = time(0); 149 } 150