xref: /openbmc/google-misc/acpi-power-state-daemon/subprojects/nemora-postd/src/nemora.cpp (revision 14fe6698f5bb26245bb807eb041eaa7a3c29ac39)
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