blob: afbc229d31ca10078e0418bda22be8697752bc3d [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>
William A. Kennington III7b9e8bd2019-04-23 19:31:31 -070012#include <cstdlib>
13#include <cstring>
Ratan Gupta56187e72017-08-13 09:40:14 +053014#include <experimental/filesystem>
Patrick Venture189d44e2018-07-09 12:30:59 -070015#include <iostream>
16#include <list>
17#include <phosphor-logging/elog-errors.hpp>
18#include <phosphor-logging/log.hpp>
William A. Kennington III5058f572019-01-30 17:18:14 -080019#include <stdexcept>
Patrick Venture189d44e2018-07-09 12:30:59 -070020#include <string>
William A. Kennington III1137a972019-04-20 20:49:58 -070021#include <variant>
Patrick Venture189d44e2018-07-09 12:30:59 -070022#include <xyz/openbmc_project/Common/error.hpp>
Ratan Gupta8804feb2017-05-25 10:49:57 +053023
24namespace phosphor
25{
26namespace network
27{
Ratan Guptabc886292017-07-25 18:29:57 +053028
Ratan Gupta8804feb2017-05-25 10:49:57 +053029namespace
30{
31
32using namespace phosphor::logging;
Ratan Gupta11cef802017-05-29 08:41:48 +053033using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Ratan Gupta56187e72017-08-13 09:40:14 +053034namespace fs = std::experimental::filesystem;
Ratan Gupta8804feb2017-05-25 10:49:57 +053035
36uint8_t toV6Cidr(const std::string& subnetMask)
37{
38 uint8_t pos = 0;
39 uint8_t prevPos = 0;
40 uint8_t cidr = 0;
Gunnar Mills57d9c502018-09-14 14:42:34 -050041 uint16_t buff{};
Ratan Gupta8804feb2017-05-25 10:49:57 +053042 do
43 {
Gunnar Mills57d9c502018-09-14 14:42:34 -050044 // subnet mask look like ffff:ffff::
Ratan Gupta8804feb2017-05-25 10:49:57 +053045 // or ffff:c000::
Gunnar Mills57d9c502018-09-14 14:42:34 -050046 pos = subnetMask.find(":", prevPos);
Ratan Gupta8804feb2017-05-25 10:49:57 +053047 if (pos == std::string::npos)
48 {
49 break;
50 }
51
52 auto str = subnetMask.substr(prevPos, (pos - prevPos));
53 prevPos = pos + 1;
54
55 // String length is 0
56 if (!str.length())
57 {
58 return cidr;
59 }
Gunnar Mills57d9c502018-09-14 14:42:34 -050060 // converts it into number.
Ratan Gupta8804feb2017-05-25 10:49:57 +053061 if (sscanf(str.c_str(), "%hx", &buff) <= 0)
62 {
63 log<level::ERR>("Invalid Mask",
Joseph Reynolds02653ca2018-05-10 15:55:09 -050064 entry("SUBNETMASK=%s", subnetMask.c_str()));
Ratan Gupta8804feb2017-05-25 10:49:57 +053065
66 return 0;
67 }
68
69 // convert the number into bitset
70 // and check for how many ones are there.
71 // if we don't have all the ones then make
72 // sure that all the ones should be left justify.
73
74 if (__builtin_popcount(buff) != 16)
75 {
Gunnar Mills57d9c502018-09-14 14:42:34 -050076 if (((sizeof(buff) * 8) - (__builtin_ctz(buff))) !=
77 __builtin_popcount(buff))
Ratan Gupta8804feb2017-05-25 10:49:57 +053078 {
79 log<level::ERR>("Invalid Mask",
Joseph Reynolds02653ca2018-05-10 15:55:09 -050080 entry("SUBNETMASK=%s", subnetMask.c_str()));
Ratan Gupta8804feb2017-05-25 10:49:57 +053081
82 return 0;
83 }
84 cidr += __builtin_popcount(buff);
85 return cidr;
86 }
87
88 cidr += 16;
Gunnar Mills57d9c502018-09-14 14:42:34 -050089 } while (1);
Ratan Gupta8804feb2017-05-25 10:49:57 +053090
91 return cidr;
92}
Gunnar Mills57d9c502018-09-14 14:42:34 -050093} // anonymous namespace
Ratan Gupta8804feb2017-05-25 10:49:57 +053094
95uint8_t toCidr(int addressFamily, const std::string& subnetMask)
96{
97 if (addressFamily == AF_INET6)
98 {
99 return toV6Cidr(subnetMask);
100 }
101
102 uint32_t buff;
103
104 auto rc = inet_pton(addressFamily, subnetMask.c_str(), &buff);
105 if (rc <= 0)
106 {
107 log<level::ERR>("inet_pton failed:",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500108 entry("SUBNETMASK=%s", subnetMask.c_str()));
Ratan Gupta8804feb2017-05-25 10:49:57 +0530109 return 0;
110 }
111
112 buff = be32toh(buff);
113 // total no of bits - total no of leading zero == total no of ones
Gunnar Mills57d9c502018-09-14 14:42:34 -0500114 if (((sizeof(buff) * 8) - (__builtin_ctz(buff))) ==
115 __builtin_popcount(buff))
Ratan Gupta8804feb2017-05-25 10:49:57 +0530116 {
117 return __builtin_popcount(buff);
118 }
119 else
120 {
121 log<level::ERR>("Invalid Mask",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500122 entry("SUBNETMASK=%s", subnetMask.c_str()));
Ratan Gupta8804feb2017-05-25 10:49:57 +0530123 return 0;
124 }
125}
126
127std::string toMask(int addressFamily, uint8_t prefix)
128{
129 if (addressFamily == AF_INET6)
130 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500131 // TODO:- conversion for v6
Ratan Gupta8804feb2017-05-25 10:49:57 +0530132 return "";
133 }
134
135 if (prefix < 1 || prefix > 30)
136 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500137 log<level::ERR>("Invalid Prefix", entry("PREFIX=%d", prefix));
Ratan Gupta8804feb2017-05-25 10:49:57 +0530138 return "";
139 }
140 /* Create the netmask from the number of bits */
141 unsigned long mask = 0;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500142 for (auto i = 0; i < prefix; i++)
Ratan Gupta8804feb2017-05-25 10:49:57 +0530143 {
144 mask |= 1 << (31 - i);
145 }
146 struct in_addr netmask;
147 netmask.s_addr = htonl(mask);
148 return inet_ntoa(netmask);
149}
150
William A. Kennington IIIa00b1c32019-02-01 18:57:17 -0800151InAddrAny addrFromBuf(int addressFamily, std::string_view buf)
152{
153 if (addressFamily == AF_INET)
154 {
155 struct in_addr ret;
156 if (buf.size() != sizeof(ret))
157 {
158 throw std::runtime_error("Buf not in_addr sized");
159 }
160 memcpy(&ret, buf.data(), sizeof(ret));
161 return ret;
162 }
163 else if (addressFamily == AF_INET6)
164 {
165 struct in6_addr ret;
166 if (buf.size() != sizeof(ret))
167 {
168 throw std::runtime_error("Buf not in6_addr sized");
169 }
170 memcpy(&ret, buf.data(), sizeof(ret));
171 return ret;
172 }
173
174 throw std::runtime_error("Unsupported address family");
175}
176
William A. Kennington III5058f572019-01-30 17:18:14 -0800177std::string toString(const InAddrAny& addr)
178{
179 std::string ip;
180 if (std::holds_alternative<struct in_addr>(addr))
181 {
182 const auto& v = std::get<struct in_addr>(addr);
183 ip.resize(INET_ADDRSTRLEN);
184 if (inet_ntop(AF_INET, &v, ip.data(), ip.size()) == NULL)
185 {
186 throw std::runtime_error("Failed to convert IP4 to string");
187 }
188 }
189 else if (std::holds_alternative<struct in6_addr>(addr))
190 {
191 const auto& v = std::get<struct in6_addr>(addr);
192 ip.resize(INET6_ADDRSTRLEN);
193 if (inet_ntop(AF_INET6, &v, ip.data(), ip.size()) == NULL)
194 {
195 throw std::runtime_error("Failed to convert IP6 to string");
196 }
197 }
198 else
199 {
200 throw std::runtime_error("Invalid addr type");
201 }
202 ip.resize(strlen(ip.c_str()));
203 return ip;
204}
205
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500206bool isLinkLocalIP(const std::string& address)
Ratan Gupta8804feb2017-05-25 10:49:57 +0530207{
Nagaraju Goruganti66b974d2017-10-03 08:43:08 -0500208 return address.find(IPV4_PREFIX) == 0 || address.find(IPV6_PREFIX) == 0;
209}
210
211bool isValidIP(int addressFamily, const std::string& address)
212{
213 unsigned char buf[sizeof(struct in6_addr)];
214
215 return inet_pton(addressFamily, address.c_str(), buf) > 0;
216}
217
218bool isValidPrefix(int addressFamily, uint8_t prefixLength)
219{
220 if (addressFamily == AF_INET)
221 {
222 if (prefixLength < IPV4_MIN_PREFIX_LENGTH ||
223 prefixLength > IPV4_MAX_PREFIX_LENGTH)
224 {
225 return false;
226 }
227 }
228
229 if (addressFamily == AF_INET6)
230 {
231 if (prefixLength < IPV4_MIN_PREFIX_LENGTH ||
232 prefixLength > IPV6_MAX_PREFIX_LENGTH)
233 {
234 return false;
235 }
236 }
237
238 return true;
Ratan Gupta8804feb2017-05-25 10:49:57 +0530239}
240
Ratan Gupta3681a502017-06-17 19:20:04 +0530241IntfAddrMap getInterfaceAddrs()
242{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500243 IntfAddrMap intfMap{};
Ratan Gupta3681a502017-06-17 19:20:04 +0530244 struct ifaddrs* ifaddr = nullptr;
245
246 // attempt to fill struct with ifaddrs
247 if (getifaddrs(&ifaddr) == -1)
248 {
249 auto error = errno;
250 log<level::ERR>("Error occurred during the getifaddrs call",
251 entry("ERRNO=%s", strerror(error)));
252 elog<InternalFailure>();
253 }
254
255 AddrPtr ifaddrPtr(ifaddr);
256 ifaddr = nullptr;
257
Gunnar Mills57d9c502018-09-14 14:42:34 -0500258 std::string intfName{};
Ratan Gupta3681a502017-06-17 19:20:04 +0530259
260 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
261 {
262 // walk interfaces
263 if (ifa->ifa_addr == nullptr)
264 {
265 continue;
266 }
267
268 // get only INET interfaces not ipv6
269 if (ifa->ifa_addr->sa_family == AF_INET ||
270 ifa->ifa_addr->sa_family == AF_INET6)
271 {
272 // if loopback, or not running ignore
273 if ((ifa->ifa_flags & IFF_LOOPBACK) ||
274 !(ifa->ifa_flags & IFF_RUNNING))
275 {
276 continue;
277 }
Ratan Gupta3681a502017-06-17 19:20:04 +0530278 intfName = ifa->ifa_name;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500279 AddrInfo info{};
280 char ip[INET6_ADDRSTRLEN] = {0};
281 char subnetMask[INET6_ADDRSTRLEN] = {0};
Ratan Gupta3681a502017-06-17 19:20:04 +0530282
283 if (ifa->ifa_addr->sa_family == AF_INET)
284 {
285
286 inet_ntop(ifa->ifa_addr->sa_family,
287 &(((struct sockaddr_in*)(ifa->ifa_addr))->sin_addr),
Gunnar Mills57d9c502018-09-14 14:42:34 -0500288 ip, sizeof(ip));
Ratan Gupta3681a502017-06-17 19:20:04 +0530289
Gunnar Mills57d9c502018-09-14 14:42:34 -0500290 inet_ntop(
291 ifa->ifa_addr->sa_family,
292 &(((struct sockaddr_in*)(ifa->ifa_netmask))->sin_addr),
293 subnetMask, sizeof(subnetMask));
Ratan Gupta3681a502017-06-17 19:20:04 +0530294 }
295 else
296 {
297 inet_ntop(ifa->ifa_addr->sa_family,
298 &(((struct sockaddr_in6*)(ifa->ifa_addr))->sin6_addr),
Gunnar Mills57d9c502018-09-14 14:42:34 -0500299 ip, sizeof(ip));
Ratan Gupta3681a502017-06-17 19:20:04 +0530300
Gunnar Mills57d9c502018-09-14 14:42:34 -0500301 inet_ntop(
302 ifa->ifa_addr->sa_family,
303 &(((struct sockaddr_in6*)(ifa->ifa_netmask))->sin6_addr),
304 subnetMask, sizeof(subnetMask));
Ratan Gupta3681a502017-06-17 19:20:04 +0530305 }
306
307 info.addrType = ifa->ifa_addr->sa_family;
308 info.ipaddress = ip;
309 info.prefix = toCidr(info.addrType, std::string(subnetMask));
David Cobbley269501c2018-05-25 15:55:56 -0700310 intfMap[intfName].push_back(info);
Ratan Gupta3681a502017-06-17 19:20:04 +0530311 }
312 }
Ratan Gupta3681a502017-06-17 19:20:04 +0530313 return intfMap;
314}
315
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530316InterfaceList getInterfaces()
317{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500318 InterfaceList interfaces{};
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530319 struct ifaddrs* ifaddr = nullptr;
320
321 // attempt to fill struct with ifaddrs
322 if (getifaddrs(&ifaddr) == -1)
323 {
324 auto error = errno;
325 log<level::ERR>("Error occurred during the getifaddrs call",
326 entry("ERRNO=%d", error));
327 elog<InternalFailure>();
328 }
329
330 AddrPtr ifaddrPtr(ifaddr);
331 ifaddr = nullptr;
332
333 for (ifaddrs* ifa = ifaddrPtr.get(); ifa != nullptr; ifa = ifa->ifa_next)
334 {
335 // walk interfaces
William A. Kennington IIIf273d2b2019-03-21 14:38:36 -0700336 // if loopback ignore
337 if (ifa->ifa_flags & IFF_LOOPBACK)
Ratan Guptafd4b0f02017-09-16 06:01:24 +0530338 {
339 continue;
340 }
341 interfaces.emplace(ifa->ifa_name);
342 }
343 return interfaces;
344}
345
Ratan Guptabc886292017-07-25 18:29:57 +0530346void deleteInterface(const std::string& intf)
347{
348 pid_t pid = fork();
Gunnar Mills57d9c502018-09-14 14:42:34 -0500349 int status{};
Ratan Guptabc886292017-07-25 18:29:57 +0530350
351 if (pid == 0)
352 {
353
354 execl("/sbin/ip", "ip", "link", "delete", "dev", intf.c_str(), nullptr);
355 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500356 log<level::ERR>("Couldn't delete the device", entry("ERRNO=%d", error),
Ratan Guptabc886292017-07-25 18:29:57 +0530357 entry("INTF=%s", intf.c_str()));
358 elog<InternalFailure>();
359 }
360 else if (pid < 0)
361 {
362 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500363 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
Ratan Guptabc886292017-07-25 18:29:57 +0530364 elog<InternalFailure>();
365 }
366 else if (pid > 0)
367 {
368 while (waitpid(pid, &status, 0) == -1)
369 {
370 if (errno != EINTR)
Gunnar Mills57d9c502018-09-14 14:42:34 -0500371 { /* Error other than EINTR */
Ratan Guptabc886292017-07-25 18:29:57 +0530372 status = -1;
373 break;
374 }
375 }
376
Gunnar Mills57d9c502018-09-14 14:42:34 -0500377 if (status < 0)
Ratan Guptabc886292017-07-25 18:29:57 +0530378 {
379 log<level::ERR>("Unable to delete the interface",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500380 entry("INTF=%s", intf.c_str()),
381 entry("STATUS=%d", status));
Ratan Guptabc886292017-07-25 18:29:57 +0530382 elog<InternalFailure>();
383 }
384 }
385}
386
William A. Kennington III7b9e8bd2019-04-23 19:31:31 -0700387std::optional<std::string> interfaceToUbootEthAddr(const char* intf)
388{
389 constexpr char ethPrefix[] = "eth";
390 constexpr size_t ethPrefixLen = sizeof(ethPrefix) - 1;
391 if (strncmp(ethPrefix, intf, ethPrefixLen) != 0)
392 {
393 return std::nullopt;
394 }
395 const auto intfSuffix = intf + ethPrefixLen;
396 if (intfSuffix[0] == '\0')
397 {
398 return std::nullopt;
399 }
400 char* end;
401 unsigned long idx = strtoul(intfSuffix, &end, 10);
402 if (end[0] != '\0')
403 {
404 return std::nullopt;
405 }
406 if (idx == 0)
407 {
408 return "ethaddr";
409 }
410 return "eth" + std::to_string(idx) + "addr";
411}
412
Ratan Gupta56187e72017-08-13 09:40:14 +0530413bool getDHCPValue(const std::string& confDir, const std::string& intf)
414{
415 bool dhcp = false;
416 // Get the interface mode value from systemd conf
Gunnar Mills57d9c502018-09-14 14:42:34 -0500417 // using namespace std::string_literals;
Ratan Gupta56187e72017-08-13 09:40:14 +0530418 fs::path confPath = confDir;
419 std::string fileName = systemd::config::networkFilePrefix + intf +
420 systemd::config::networkFileSuffix;
421 confPath /= fileName;
422
Ratan Guptac27170a2017-11-22 15:44:42 +0530423 auto rc = config::ReturnCode::SUCCESS;
424 config::ValueList values;
425 config::Parser parser(confPath.string());
426
427 std::tie(rc, values) = parser.getValues("Network", "DHCP");
428 if (rc != config::ReturnCode::SUCCESS)
Ratan Gupta56187e72017-08-13 09:40:14 +0530429 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530430 log<level::DEBUG>("Unable to get the value for Network[DHCP]",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500431 entry("RC=%d", rc));
Ratan Guptac27170a2017-11-22 15:44:42 +0530432 return dhcp;
Ratan Gupta56187e72017-08-13 09:40:14 +0530433 }
Ratan Guptac27170a2017-11-22 15:44:42 +0530434 // There will be only single value for DHCP key.
435 if (values[0] == "true")
Ratan Gupta56187e72017-08-13 09:40:14 +0530436 {
Ratan Guptac27170a2017-11-22 15:44:42 +0530437 dhcp = true;
Ratan Gupta56187e72017-08-13 09:40:14 +0530438 }
439 return dhcp;
440}
441
Ratan Guptabd303b12017-08-18 17:10:07 +0530442namespace internal
443{
Ratan Gupta56187e72017-08-13 09:40:14 +0530444
Ratan Guptabd303b12017-08-18 17:10:07 +0530445void executeCommandinChildProcess(const char* path, char** args)
446{
447 using namespace std::string_literals;
448 pid_t pid = fork();
Gunnar Mills57d9c502018-09-14 14:42:34 -0500449 int status{};
Ratan Guptabd303b12017-08-18 17:10:07 +0530450
451 if (pid == 0)
452 {
453 execv(path, args);
454 auto error = errno;
455 // create the command from var args.
456 std::string command = path + " "s;
457
Gunnar Mills57d9c502018-09-14 14:42:34 -0500458 for (int i = 0; args[i]; i++)
Ratan Guptabd303b12017-08-18 17:10:07 +0530459 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500460 command += args[i] + " "s;
Ratan Guptabd303b12017-08-18 17:10:07 +0530461 }
462
463 log<level::ERR>("Couldn't exceute the command",
464 entry("ERRNO=%d", error),
465 entry("CMD=%s", command.c_str()));
466 elog<InternalFailure>();
467 }
468 else if (pid < 0)
469 {
470 auto error = errno;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500471 log<level::ERR>("Error occurred during fork", entry("ERRNO=%d", error));
Ratan Guptabd303b12017-08-18 17:10:07 +0530472 elog<InternalFailure>();
473 }
474 else if (pid > 0)
475 {
476 while (waitpid(pid, &status, 0) == -1)
477 {
478 if (errno != EINTR)
Gunnar Mills57d9c502018-09-14 14:42:34 -0500479 { // Error other than EINTR
Ratan Guptabd303b12017-08-18 17:10:07 +0530480 status = -1;
481 break;
482 }
483 }
484
Gunnar Mills57d9c502018-09-14 14:42:34 -0500485 if (status < 0)
Ratan Guptabd303b12017-08-18 17:10:07 +0530486 {
487 std::string command = path + " "s;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500488 for (int i = 0; args[i]; i++)
Ratan Guptabd303b12017-08-18 17:10:07 +0530489 {
490 command += args[i] + " "s;
491 }
492
493 log<level::ERR>("Unable to execute the command",
Joseph Reynolds02653ca2018-05-10 15:55:09 -0500494 entry("CMD=%s", command.c_str()),
495 entry("STATUS=%d", status));
Ratan Guptabd303b12017-08-18 17:10:07 +0530496 elog<InternalFailure>();
497 }
498 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530499}
Gunnar Mills57d9c502018-09-14 14:42:34 -0500500} // namespace internal
Ratan Guptabd303b12017-08-18 17:10:07 +0530501
502namespace mac_address
503{
504
505constexpr auto mapperBus = "xyz.openbmc_project.ObjectMapper";
506constexpr auto mapperObj = "/xyz/openbmc_project/object_mapper";
507constexpr auto mapperIntf = "xyz.openbmc_project.ObjectMapper";
508constexpr auto propIntf = "org.freedesktop.DBus.Properties";
509constexpr auto methodGet = "Get";
510
511using DbusObjectPath = std::string;
512using DbusService = std::string;
513using DbusInterface = std::string;
Gunnar Mills57d9c502018-09-14 14:42:34 -0500514using ObjectTree =
515 std::map<DbusObjectPath, std::map<DbusService, std::vector<DbusInterface>>>;
Ratan Guptabd303b12017-08-18 17:10:07 +0530516
517constexpr auto invBus = "xyz.openbmc_project.Inventory.Manager";
518constexpr auto invNetworkIntf =
Gunnar Mills57d9c502018-09-14 14:42:34 -0500519 "xyz.openbmc_project.Inventory.Item.NetworkInterface";
Ratan Guptabd303b12017-08-18 17:10:07 +0530520constexpr auto invRoot = "/xyz/openbmc_project/inventory";
521
Alvin Wang38a63c32019-08-29 22:56:46 +0800522ether_addr getfromInventory(sdbusplus::bus::bus& bus,
523 const std::string& intfName)
Ratan Guptabd303b12017-08-18 17:10:07 +0530524{
525 std::vector<DbusInterface> interfaces;
526 interfaces.emplace_back(invNetworkIntf);
527
528 auto depth = 0;
529
Gunnar Mills57d9c502018-09-14 14:42:34 -0500530 auto mapperCall =
531 bus.new_method_call(mapperBus, mapperObj, mapperIntf, "GetSubTree");
Ratan Guptabd303b12017-08-18 17:10:07 +0530532
533 mapperCall.append(invRoot, depth, interfaces);
534
535 auto mapperReply = bus.call(mapperCall);
536 if (mapperReply.is_method_error())
537 {
538 log<level::ERR>("Error in mapper call");
539 elog<InternalFailure>();
540 }
541
542 ObjectTree objectTree;
543 mapperReply.read(objectTree);
544
545 if (objectTree.empty())
546 {
547 log<level::ERR>("No Object has implemented the interface",
548 entry("INTERFACE=%s", invNetworkIntf));
549 elog<InternalFailure>();
550 }
551
Alvin Wang38a63c32019-08-29 22:56:46 +0800552 DbusObjectPath objPath;
553 DbusService service;
Ratan Guptabd303b12017-08-18 17:10:07 +0530554
Alvin Wang38a63c32019-08-29 22:56:46 +0800555 if (1 == objectTree.size())
556 {
557 objPath = objectTree.begin()->first;
558 service = objectTree.begin()->second.begin()->first;
559 }
560 else
561 {
562 // If there are more than 2 objects, object path must contain the
563 // interface name
564 for (auto const& object : objectTree)
565 {
566 log<level::INFO>("interface", entry("INT=%s", intfName.c_str()));
567 log<level::INFO>("object", entry("OBJ=%s", object.first.c_str()));
568 if (std::string::npos != object.first.find(intfName))
569 {
570 objPath = object.first;
571 service = object.second.begin()->first;
572 break;
573 }
574 }
575
576 if (objPath.empty())
577 {
578 log<level::ERR>("Can't find the object for the interface",
579 entry("intfName=%s", intfName.c_str()));
580 elog<InternalFailure>();
581 }
582 }
Ratan Guptabd303b12017-08-18 17:10:07 +0530583
Gunnar Mills57d9c502018-09-14 14:42:34 -0500584 auto method = bus.new_method_call(service.c_str(), objPath.c_str(),
585 propIntf, methodGet);
Ratan Guptabd303b12017-08-18 17:10:07 +0530586
587 method.append(invNetworkIntf, "MACAddress");
588
589 auto reply = bus.call(method);
590 if (reply.is_method_error())
591 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500592 log<level::ERR>("Failed to get MACAddress",
Ratan Guptabd303b12017-08-18 17:10:07 +0530593 entry("PATH=%s", objPath.c_str()),
594 entry("INTERFACE=%s", invNetworkIntf));
595 elog<InternalFailure>();
596 }
597
William A. Kennington III1137a972019-04-20 20:49:58 -0700598 std::variant<std::string> value;
Ratan Guptabd303b12017-08-18 17:10:07 +0530599 reply.read(value);
William A. Kennington III1137a972019-04-20 20:49:58 -0700600 return fromString(std::get<std::string>(value));
601}
602
603ether_addr fromString(const char* str)
604{
605 struct ether_addr* mac = ether_aton(str);
606 if (mac == nullptr)
607 {
608 throw std::runtime_error("Invalid mac address string");
609 }
610 return *mac;
Ratan Guptabd303b12017-08-18 17:10:07 +0530611}
612
William A. Kennington III6ca08d82019-04-20 16:04:18 -0700613std::string toString(const ether_addr& mac)
William A. Kennington IIIa14879e2019-02-01 21:43:11 -0800614{
William A. Kennington III6ca08d82019-04-20 16:04:18 -0700615 return ether_ntoa(&mac);
William A. Kennington IIId27410f2019-01-30 17:15:43 -0800616}
617
William A. Kennington III1137a972019-04-20 20:49:58 -0700618bool isEmpty(const ether_addr& mac)
619{
620 return equal(mac, ether_addr{});
621}
622
623bool isMulticast(const ether_addr& mac)
624{
625 return mac.ether_addr_octet[0] & 0b1;
626}
627
628bool isUnicast(const ether_addr& mac)
629{
630 return !isEmpty(mac) && !isMulticast(mac);
631}
632
633bool isLocalAdmin(const ether_addr& mac)
634{
635 return mac.ether_addr_octet[0] & 0b10;
636}
637
Gunnar Mills57d9c502018-09-14 14:42:34 -0500638} // namespace mac_address
639} // namespace network
640} // namespace phosphor