blob: b01d644a0c284e83f058d1ec4506901ca5bdd5c8 [file] [log] [blame]
Ratan Gupta3681a502017-06-17 19:20:04 +05301#include "util.hpp"
Ratan Gupta11cef802017-05-29 08:41:48 +05302
Patrick Venture189d44e2018-07-09 12:30:59 -07003#include "config_parser.hpp"
4#include "types.hpp"
Ratan Gupta8804feb2017-05-25 10:49:57 +05305
Ratan Gupta3681a502017-06-17 19:20:04 +05306#include <arpa/inet.h>
7#include <dirent.h>
8#include <net/if.h>
Ratan Guptabc886292017-07-25 18:29:57 +05309#include <sys/wait.h>
Ratan Gupta3681a502017-06-17 19:20:04 +053010
Ratan Gupta8804feb2017-05-25 10:49:57 +053011#include <algorithm>
Ratan Gupta56187e72017-08-13 09:40:14 +053012#include <experimental/filesystem>
Patrick Venture189d44e2018-07-09 12:30:59 -070013#include <iostream>
14#include <list>
15#include <phosphor-logging/elog-errors.hpp>
16#include <phosphor-logging/log.hpp>
William A. Kennington III5058f572019-01-30 17:18:14 -080017#include <stdexcept>
Patrick Venture189d44e2018-07-09 12:30:59 -070018#include <string>
William A. Kennington III1137a972019-04-20 20:49:58 -070019#include <variant>
Patrick Venture189d44e2018-07-09 12:30:59 -070020#include <xyz/openbmc_project/Common/error.hpp>
Ratan Gupta8804feb2017-05-25 10:49:57 +053021
22namespace phosphor
23{
24namespace network
25{
Ratan Guptabc886292017-07-25 18:29:57 +053026
Ratan Gupta8804feb2017-05-25 10:49:57 +053027namespace
28{
29
30using namespace phosphor::logging;
Ratan Gupta11cef802017-05-29 08:41:48 +053031using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Ratan Gupta56187e72017-08-13 09:40:14 +053032namespace fs = std::experimental::filesystem;
Ratan Gupta8804feb2017-05-25 10:49:57 +053033
34uint8_t toV6Cidr(const std::string& subnetMask)
35{
36 uint8_t pos = 0;
37 uint8_t prevPos = 0;
38 uint8_t cidr = 0;
Gunnar Mills57d9c502018-09-14 14:42:34 -050039 uint16_t buff{};
Ratan Gupta8804feb2017-05-25 10:49:57 +053040 do
41 {
Gunnar Mills57d9c502018-09-14 14:42:34 -050042 // subnet mask look like ffff:ffff::
Ratan Gupta8804feb2017-05-25 10:49:57 +053043 // or ffff:c000::
Gunnar Mills57d9c502018-09-14 14:42:34 -050044 pos = subnetMask.find(":", prevPos);
Ratan Gupta8804feb2017-05-25 10:49:57 +053045 if (pos == std::string::npos)
46 {
47 break;
48 }
49
50 auto str = subnetMask.substr(prevPos, (pos - prevPos));
51 prevPos = pos + 1;
52
53 // String length is 0
54 if (!str.length())
55 {
56 return cidr;
57 }
Gunnar Mills57d9c502018-09-14 14:42:34 -050058 // converts it into number.
Ratan Gupta8804feb2017-05-25 10:49:57 +053059 if (sscanf(str.c_str(), "%hx", &buff) <= 0)
60 {
61 log<level::ERR>("Invalid Mask",
Joseph Reynolds02653ca2018-05-10 15:55:09 -050062 entry("SUBNETMASK=%s", subnetMask.c_str()));
Ratan Gupta8804feb2017-05-25 10:49:57 +053063
64 return 0;
65 }
66
67 // convert the number into bitset
68 // and check for how many ones are there.
69 // if we don't have all the ones then make
70 // sure that all the ones should be left justify.
71
72 if (__builtin_popcount(buff) != 16)
73 {
Gunnar Mills57d9c502018-09-14 14:42:34 -050074 if (((sizeof(buff) * 8) - (__builtin_ctz(buff))) !=
75 __builtin_popcount(buff))
Ratan Gupta8804feb2017-05-25 10:49:57 +053076 {
77 log<level::ERR>("Invalid Mask",
Joseph Reynolds02653ca2018-05-10 15:55:09 -050078 entry("SUBNETMASK=%s", subnetMask.c_str()));
Ratan Gupta8804feb2017-05-25 10:49:57 +053079
80 return 0;
81 }
82 cidr += __builtin_popcount(buff);
83 return cidr;
84 }
85
86 cidr += 16;
Gunnar Mills57d9c502018-09-14 14:42:34 -050087 } while (1);
Ratan Gupta8804feb2017-05-25 10:49:57 +053088
89 return cidr;
90}
Gunnar Mills57d9c502018-09-14 14:42:34 -050091} // anonymous namespace
Ratan Gupta8804feb2017-05-25 10:49:57 +053092
93uint8_t toCidr(int addressFamily, const std::string& subnetMask)
94{
95 if (addressFamily == AF_INET6)
96 {
97 return toV6Cidr(subnetMask);
98 }
99
100 uint32_t buff;
101
102 auto rc = inet_pton(addressFamily, subnetMask.c_str(), &buff);
103 if (rc <= 0)
104 {
105 log<level::ERR>("inet_pton failed:",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500106 entry("SUBNETMASK=%s", subnetMask.c_str()));
Ratan Gupta8804feb2017-05-25 10:49:57 +0530107 return 0;
108 }
109
110 buff = be32toh(buff);
111 // total no of bits - total no of leading zero == total no of ones
Gunnar Mills57d9c502018-09-14 14:42:34 -0500112 if (((sizeof(buff) * 8) - (__builtin_ctz(buff))) ==
113 __builtin_popcount(buff))
Ratan Gupta8804feb2017-05-25 10:49:57 +0530114 {
115 return __builtin_popcount(buff);
116 }
117 else
118 {
119 log<level::ERR>("Invalid Mask",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500120 entry("SUBNETMASK=%s", subnetMask.c_str()));
Ratan Gupta8804feb2017-05-25 10:49:57 +0530121 return 0;
122 }
123}
124
125std::string toMask(int addressFamily, uint8_t prefix)
126{
127 if (addressFamily == AF_INET6)
128 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500129 // TODO:- conversion for v6
Ratan Gupta8804feb2017-05-25 10:49:57 +0530130 return "";
131 }
132
133 if (prefix < 1 || prefix > 30)
134 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500135 log<level::ERR>("Invalid Prefix", entry("PREFIX=%d", prefix));
Ratan Gupta8804feb2017-05-25 10:49:57 +0530136 return "";
137 }
138 /* Create the netmask from the number of bits */
139 unsigned long mask = 0;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500140 for (auto i = 0; i < prefix; i++)
Ratan Gupta8804feb2017-05-25 10:49:57 +0530141 {
142 mask |= 1 << (31 - i);
143 }
144 struct in_addr netmask;
145 netmask.s_addr = htonl(mask);
146 return inet_ntoa(netmask);
147}
148
William A. Kennington IIIa00b1c32019-02-01 18:57:17 -0800149InAddrAny addrFromBuf(int addressFamily, std::string_view buf)
150{
151 if (addressFamily == AF_INET)
152 {
153 struct in_addr ret;
154 if (buf.size() != sizeof(ret))
155 {
156 throw std::runtime_error("Buf not in_addr sized");
157 }
158 memcpy(&ret, buf.data(), sizeof(ret));
159 return ret;
160 }
161 else if (addressFamily == AF_INET6)
162 {
163 struct in6_addr ret;
164 if (buf.size() != sizeof(ret))
165 {
166 throw std::runtime_error("Buf not in6_addr sized");
167 }
168 memcpy(&ret, buf.data(), sizeof(ret));
169 return ret;
170 }
171
172 throw std::runtime_error("Unsupported address family");
173}
174
William A. Kennington III5058f572019-01-30 17:18:14 -0800175std::string toString(const InAddrAny& addr)
176{
177 std::string ip;
178 if (std::holds_alternative<struct in_addr>(addr))
179 {
180 const auto& v = std::get<struct in_addr>(addr);
181 ip.resize(INET_ADDRSTRLEN);
182 if (inet_ntop(AF_INET, &v, ip.data(), ip.size()) == NULL)
183 {
184 throw std::runtime_error("Failed to convert IP4 to string");
185 }
186 }
187 else if (std::holds_alternative<struct in6_addr>(addr))
188 {
189 const auto& v = std::get<struct in6_addr>(addr);
190 ip.resize(INET6_ADDRSTRLEN);
191 if (inet_ntop(AF_INET6, &v, ip.data(), ip.size()) == NULL)
192 {
193 throw std::runtime_error("Failed to convert IP6 to string");
194 }
195 }
196 else
197 {
198 throw std::runtime_error("Invalid addr type");
199 }
200 ip.resize(strlen(ip.c_str()));
201 return ip;
202}
203
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500204bool isLinkLocalIP(const std::string& address)
Ratan Gupta8804feb2017-05-25 10:49:57 +0530205{
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500206 return address.find(IPV4_PREFIX) == 0 || address.find(IPV6_PREFIX) == 0;
207}
208
209bool isValidIP(int addressFamily, const std::string& address)
210{
211 unsigned char buf[sizeof(struct in6_addr)];
212
213 return inet_pton(addressFamily, address.c_str(), buf) > 0;
214}
215
216bool isValidPrefix(int addressFamily, uint8_t prefixLength)
217{
218 if (addressFamily == AF_INET)
219 {
220 if (prefixLength < IPV4_MIN_PREFIX_LENGTH ||
221 prefixLength > IPV4_MAX_PREFIX_LENGTH)
222 {
223 return false;
224 }
225 }
226
227 if (addressFamily == AF_INET6)
228 {
229 if (prefixLength < IPV4_MIN_PREFIX_LENGTH ||
230 prefixLength > IPV6_MAX_PREFIX_LENGTH)
231 {
232 return false;
233 }
234 }
235
236 return true;
Ratan Gupta8804feb2017-05-25 10:49:57 +0530237}
238
Ratan Gupta3681a502017-06-17 19:20:04 +0530239IntfAddrMap getInterfaceAddrs()
240{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500241 IntfAddrMap intfMap{};
Ratan Gupta3681a502017-06-17 19:20:04 +0530242 struct ifaddrs* ifaddr = nullptr;
243
244 // attempt to fill struct with ifaddrs
245 if (getifaddrs(&ifaddr) == -1)
246 {
247 auto error = errno;
248 log<level::ERR>("Error occurred during the getifaddrs call",
249 entry("ERRNO=%s", strerror(error)));
250 elog<InternalFailure>();
251 }
252
253 AddrPtr ifaddrPtr(ifaddr);
254 ifaddr = nullptr;
255
Gunnar Mills57d9c502018-09-14 14:42:34 -0500256 std::string intfName{};
Ratan Gupta3681a502017-06-17 19:20:04 +0530257
258 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
259 {
260 // walk interfaces
261 if (ifa->ifa_addr == nullptr)
262 {
263 continue;
264 }
265
266 // get only INET interfaces not ipv6
267 if (ifa->ifa_addr->sa_family == AF_INET ||
268 ifa->ifa_addr->sa_family == AF_INET6)
269 {
270 // if loopback, or not running ignore
271 if ((ifa->ifa_flags & IFF_LOOPBACK) ||
272 !(ifa->ifa_flags & IFF_RUNNING))
273 {
274 continue;
275 }
Ratan Gupta3681a502017-06-17 19:20:04 +0530276 intfName = ifa->ifa_name;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500277 AddrInfo info{};
278 char ip[INET6_ADDRSTRLEN] = {0};
279 char subnetMask[INET6_ADDRSTRLEN] = {0};
Ratan Gupta3681a502017-06-17 19:20:04 +0530280
281 if (ifa->ifa_addr->sa_family == AF_INET)
282 {
283
284 inet_ntop(ifa->ifa_addr->sa_family,
285 &(((struct sockaddr_in*)(ifa->ifa_addr))->sin_addr),
Gunnar Mills57d9c502018-09-14 14:42:34 -0500286 ip, sizeof(ip));
Ratan Gupta3681a502017-06-17 19:20:04 +0530287
Gunnar Mills57d9c502018-09-14 14:42:34 -0500288 inet_ntop(
289 ifa->ifa_addr->sa_family,
290 &(((struct sockaddr_in*)(ifa->ifa_netmask))->sin_addr),
291 subnetMask, sizeof(subnetMask));
Ratan Gupta3681a502017-06-17 19:20:04 +0530292 }
293 else
294 {
295 inet_ntop(ifa->ifa_addr->sa_family,
296 &(((struct sockaddr_in6*)(ifa->ifa_addr))->sin6_addr),
Gunnar Mills57d9c502018-09-14 14:42:34 -0500297 ip, sizeof(ip));
Ratan Gupta3681a502017-06-17 19:20:04 +0530298
Gunnar Mills57d9c502018-09-14 14:42:34 -0500299 inet_ntop(
300 ifa->ifa_addr->sa_family,
301 &(((struct sockaddr_in6*)(ifa->ifa_netmask))->sin6_addr),
302 subnetMask, sizeof(subnetMask));
Ratan Gupta3681a502017-06-17 19:20:04 +0530303 }
304
305 info.addrType = ifa->ifa_addr->sa_family;
306 info.ipaddress = ip;
307 info.prefix = toCidr(info.addrType, std::string(subnetMask));
David Cobbley269501c2018-05-25 15:55:56 -0700308 intfMap[intfName].push_back(info);
Ratan Gupta3681a502017-06-17 19:20:04 +0530309 }
310 }
Ratan Gupta3681a502017-06-17 19:20:04 +0530311 return intfMap;
312}
313
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530314InterfaceList getInterfaces()
315{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500316 InterfaceList interfaces{};
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530317 struct ifaddrs* ifaddr = nullptr;
318
319 // attempt to fill struct with ifaddrs
320 if (getifaddrs(&ifaddr) == -1)
321 {
322 auto error = errno;
323 log<level::ERR>("Error occurred during the getifaddrs call",
324 entry("ERRNO=%d", error));
325 elog<InternalFailure>();
326 }
327
328 AddrPtr ifaddrPtr(ifaddr);
329 ifaddr = nullptr;
330
331 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
332 {
333 // walk interfaces
William A. Kennington IIIf273d2b2019-03-21 14:38:36 -0700334 // if loopback ignore
335 if (ifa->ifa_flags & IFF_LOOPBACK)
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530336 {
337 continue;
338 }
339 interfaces.emplace(ifa->ifa_name);
340 }
341 return interfaces;
342}
343
Ratan Guptabc886292017-07-25 18:29:57 +0530344void deleteInterface(const std::string& intf)
345{
346 pid_t pid = fork();
Gunnar Mills57d9c502018-09-14 14:42:34 -0500347 int status{};
Ratan Guptabc886292017-07-25 18:29:57 +0530348
349 if (pid == 0)
350 {
351
352 execl("/sbin/ip", "ip", "link", "delete", "dev", intf.c_str(), nullptr);
353 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500354 log<level::ERR>("Couldn't delete the device", entry("ERRNO=%d", error),
Ratan Guptabc886292017-07-25 18:29:57 +0530355 entry("INTF=%s", intf.c_str()));
356 elog<InternalFailure>();
357 }
358 else if (pid < 0)
359 {
360 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500361 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
Ratan Guptabc886292017-07-25 18:29:57 +0530362 elog<InternalFailure>();
363 }
364 else if (pid > 0)
365 {
366 while (waitpid(pid, &status, 0) == -1)
367 {
368 if (errno != EINTR)
Gunnar Mills57d9c502018-09-14 14:42:34 -0500369 { /* Error other than EINTR */
Ratan Guptabc886292017-07-25 18:29:57 +0530370 status = -1;
371 break;
372 }
373 }
374
Gunnar Mills57d9c502018-09-14 14:42:34 -0500375 if (status < 0)
Ratan Guptabc886292017-07-25 18:29:57 +0530376 {
377 log<level::ERR>("Unable to delete the interface",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500378 entry("INTF=%s", intf.c_str()),
379 entry("STATUS=%d", status));
Ratan Guptabc886292017-07-25 18:29:57 +0530380 elog<InternalFailure>();
381 }
382 }
383}
384
Ratan Gupta56187e72017-08-13 09:40:14 +0530385bool getDHCPValue(const std::string& confDir, const std::string& intf)
386{
387 bool dhcp = false;
388 // Get the interface mode value from systemd conf
Gunnar Mills57d9c502018-09-14 14:42:34 -0500389 // using namespace std::string_literals;
Ratan Gupta56187e72017-08-13 09:40:14 +0530390 fs::path confPath = confDir;
391 std::string fileName = systemd::config::networkFilePrefix + intf +
392 systemd::config::networkFileSuffix;
393 confPath /= fileName;
394
Ratan Guptac27170a2017-11-22 15:44:42 +0530395 auto rc = config::ReturnCode::SUCCESS;
396 config::ValueList values;
397 config::Parser parser(confPath.string());
398
399 std::tie(rc, values) = parser.getValues("Network", "DHCP");
400 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta56187e72017-08-13 09:40:14 +0530401 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530402 log<level::DEBUG>("Unable to get the value for Network[DHCP]",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500403 entry("RC=%d", rc));
Ratan Guptac27170a2017-11-22 15:44:42 +0530404 return dhcp;
Ratan Gupta56187e72017-08-13 09:40:14 +0530405 }
Ratan Guptac27170a2017-11-22 15:44:42 +0530406 // There will be only single value for DHCP key.
407 if (values[0] == "true")
Ratan Gupta56187e72017-08-13 09:40:14 +0530408 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530409 dhcp = true;
Ratan Gupta56187e72017-08-13 09:40:14 +0530410 }
411 return dhcp;
412}
413
Ratan Guptabd303b12017-08-18 17:10:07 +0530414namespace internal
415{
Ratan Gupta56187e72017-08-13 09:40:14 +0530416
Ratan Guptabd303b12017-08-18 17:10:07 +0530417void executeCommandinChildProcess(const char* path, char** args)
418{
419 using namespace std::string_literals;
420 pid_t pid = fork();
Gunnar Mills57d9c502018-09-14 14:42:34 -0500421 int status{};
Ratan Guptabd303b12017-08-18 17:10:07 +0530422
423 if (pid == 0)
424 {
425 execv(path, args);
426 auto error = errno;
427 // create the command from var args.
428 std::string command = path + " "s;
429
Gunnar Mills57d9c502018-09-14 14:42:34 -0500430 for (int i = 0; args[i]; i++)
Ratan Guptabd303b12017-08-18 17:10:07 +0530431 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500432 command += args[i] + " "s;
Ratan Guptabd303b12017-08-18 17:10:07 +0530433 }
434
435 log<level::ERR>("Couldn't exceute the command",
436 entry("ERRNO=%d", error),
437 entry("CMD=%s", command.c_str()));
438 elog<InternalFailure>();
439 }
440 else if (pid < 0)
441 {
442 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500443 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
Ratan Guptabd303b12017-08-18 17:10:07 +0530444 elog<InternalFailure>();
445 }
446 else if (pid > 0)
447 {
448 while (waitpid(pid, &status, 0) == -1)
449 {
450 if (errno != EINTR)
Gunnar Mills57d9c502018-09-14 14:42:34 -0500451 { // Error other than EINTR
Ratan Guptabd303b12017-08-18 17:10:07 +0530452 status = -1;
453 break;
454 }
455 }
456
Gunnar Mills57d9c502018-09-14 14:42:34 -0500457 if (status < 0)
Ratan Guptabd303b12017-08-18 17:10:07 +0530458 {
459 std::string command = path + " "s;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500460 for (int i = 0; args[i]; i++)
Ratan Guptabd303b12017-08-18 17:10:07 +0530461 {
462 command += args[i] + " "s;
463 }
464
465 log<level::ERR>("Unable to execute the command",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500466 entry("CMD=%s", command.c_str()),
467 entry("STATUS=%d", status));
Ratan Guptabd303b12017-08-18 17:10:07 +0530468 elog<InternalFailure>();
469 }
470 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530471}
Gunnar Mills57d9c502018-09-14 14:42:34 -0500472} // namespace internal
Ratan Guptabd303b12017-08-18 17:10:07 +0530473
474namespace mac_address
475{
476
477constexpr auto mapperBus = "xyz.openbmc_project.ObjectMapper";
478constexpr auto mapperObj = "/xyz/openbmc_project/object_mapper";
479constexpr auto mapperIntf = "xyz.openbmc_project.ObjectMapper";
480constexpr auto propIntf = "org.freedesktop.DBus.Properties";
481constexpr auto methodGet = "Get";
482
483using DbusObjectPath = std::string;
484using DbusService = std::string;
485using DbusInterface = std::string;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500486using ObjectTree =
487 std::map<DbusObjectPath, std::map<DbusService, std::vector<DbusInterface>>>;
Ratan Guptabd303b12017-08-18 17:10:07 +0530488
489constexpr auto invBus = "xyz.openbmc_project.Inventory.Manager";
490constexpr auto invNetworkIntf =
Gunnar Mills57d9c502018-09-14 14:42:34 -0500491 "xyz.openbmc_project.Inventory.Item.NetworkInterface";
Ratan Guptabd303b12017-08-18 17:10:07 +0530492constexpr auto invRoot = "/xyz/openbmc_project/inventory";
493
William A. Kennington III1137a972019-04-20 20:49:58 -0700494ether_addr getfromInventory(sdbusplus::bus::bus& bus)
Ratan Guptabd303b12017-08-18 17:10:07 +0530495{
496 std::vector<DbusInterface> interfaces;
497 interfaces.emplace_back(invNetworkIntf);
498
499 auto depth = 0;
500
Gunnar Mills57d9c502018-09-14 14:42:34 -0500501 auto mapperCall =
502 bus.new_method_call(mapperBus, mapperObj, mapperIntf, "GetSubTree");
Ratan Guptabd303b12017-08-18 17:10:07 +0530503
504 mapperCall.append(invRoot, depth, interfaces);
505
506 auto mapperReply = bus.call(mapperCall);
507 if (mapperReply.is_method_error())
508 {
509 log<level::ERR>("Error in mapper call");
510 elog<InternalFailure>();
511 }
512
513 ObjectTree objectTree;
514 mapperReply.read(objectTree);
515
516 if (objectTree.empty())
517 {
518 log<level::ERR>("No Object has implemented the interface",
519 entry("INTERFACE=%s", invNetworkIntf));
520 elog<InternalFailure>();
521 }
522
Gunnar Millsa251a782017-09-26 16:49:08 -0500523 // It is expected that only one object has implemented this interface.
Ratan Guptabd303b12017-08-18 17:10:07 +0530524
525 auto objPath = objectTree.begin()->first;
526 auto service = objectTree.begin()->second.begin()->first;
527
Gunnar Mills57d9c502018-09-14 14:42:34 -0500528 auto method = bus.new_method_call(service.c_str(), objPath.c_str(),
529 propIntf, methodGet);
Ratan Guptabd303b12017-08-18 17:10:07 +0530530
531 method.append(invNetworkIntf, "MACAddress");
532
533 auto reply = bus.call(method);
534 if (reply.is_method_error())
535 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500536 log<level::ERR>("Failed to get MACAddress",
Ratan Guptabd303b12017-08-18 17:10:07 +0530537 entry("PATH=%s", objPath.c_str()),
538 entry("INTERFACE=%s", invNetworkIntf));
539 elog<InternalFailure>();
540 }
541
William A. Kennington III1137a972019-04-20 20:49:58 -0700542 std::variant<std::string> value;
Ratan Guptabd303b12017-08-18 17:10:07 +0530543 reply.read(value);
William A. Kennington III1137a972019-04-20 20:49:58 -0700544 return fromString(std::get<std::string>(value));
545}
546
547ether_addr fromString(const char* str)
548{
549 struct ether_addr* mac = ether_aton(str);
550 if (mac == nullptr)
551 {
552 throw std::runtime_error("Invalid mac address string");
553 }
554 return *mac;
Ratan Guptabd303b12017-08-18 17:10:07 +0530555}
556
William A. Kennington III6ca08d82019-04-20 16:04:18 -0700557std::string toString(const ether_addr& mac)
William A. Kennington IIIa14879e2019-02-01 21:43:11 -0800558{
William A. Kennington III6ca08d82019-04-20 16:04:18 -0700559 return ether_ntoa(&mac);
William A. Kennington IIId27410f2019-01-30 17:15:43 -0800560}
561
William A. Kennington III1137a972019-04-20 20:49:58 -0700562bool isEmpty(const ether_addr& mac)
563{
564 return equal(mac, ether_addr{});
565}
566
567bool isMulticast(const ether_addr& mac)
568{
569 return mac.ether_addr_octet[0] & 0b1;
570}
571
572bool isUnicast(const ether_addr& mac)
573{
574 return !isEmpty(mac) && !isMulticast(mac);
575}
576
577bool isLocalAdmin(const ether_addr& mac)
578{
579 return mac.ether_addr_octet[0] & 0b10;
580}
581
Gunnar Mills57d9c502018-09-14 14:42:34 -0500582} // namespace mac_address
583} // namespace network
584} // namespace phosphor