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
ParseMac(const std::string & mac_addr,MacAddr * mac)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
GetMacAddr(MacAddr * mac,const std::string & iface_path)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
InitEventData()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
Nemora()98 Nemora::Nemora()
99 {
100 InitEventData();
101 }
102
Nemora(const std::string & iface_name,const in_addr ipv4,const in6_addr ipv6)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
UdpPoll()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
UpdateEventData(std::vector<uint64_t> && postcodes)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