]> git.ipfire.org Git - thirdparty/lldpd.git/blame - src/daemon/interfaces-linux.c
build: bump cross-platform-actions/action from 0.27.0 to 0.28.0
[thirdparty/lldpd.git] / src / daemon / interfaces-linux.c
CommitLineData
4b292b55 1/* -*- mode: c; c-file-style: "openbsd" -*- */
6e75df87
VB
2/*
3 * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
4 *
51434125 5 * Permission to use, copy, modify, and/or distribute this software for any
6e75df87
VB
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
6e75df87
VB
18#include "lldpd.h"
19
20#include <stdio.h>
21#include <unistd.h>
78c9dfde 22#include <inttypes.h>
6e75df87
VB
23#include <errno.h>
24#include <sys/ioctl.h>
d7460a6f 25#if defined(__clang__)
8b549648
VB
26# pragma clang diagnostic push
27# pragma clang diagnostic ignored "-Wdocumentation"
d7460a6f 28#endif
217b9531 29#include <netinet/in.h>
6e75df87
VB
30#include <linux/if_vlan.h>
31#include <linux/if_bonding.h>
32#include <linux/if_bridge.h>
33#include <linux/wireless.h>
34#include <linux/sockios.h>
6e75df87 35#include <linux/if_packet.h>
e12c2365 36#include <linux/ethtool.h>
d7460a6f 37#if defined(__clang__)
8b549648 38# pragma clang diagnostic pop
d7460a6f 39#endif
6e75df87
VB
40
41#define SYSFS_PATH_MAX 256
42#define MAX_PORTS 1024
43#define MAX_BRIDGES 1024
44
88bc404f
VB
45static int
46iflinux_eth_init(struct lldpd *cfg, struct lldpd_hardware *hardware)
47{
e735a319 48 int fd;
88bc404f 49
8b549648 50 log_debug("interfaces", "initialize ethernet device %s", hardware->h_ifname);
8b50be7f 51 if ((fd = priv_iface_init(hardware->h_ifindex, hardware->h_ifname)) == -1)
88bc404f
VB
52 return -1;
53 hardware->h_sendfd = fd; /* Send */
54
88bc404f
VB
55 interfaces_setup_multicast(cfg, hardware->h_ifname, 0);
56
57 levent_hardware_add_fd(hardware, fd); /* Receive */
58 log_debug("interfaces", "interface %s initialized (fd=%d)", hardware->h_ifname,
59 fd);
60 return 0;
61}
62
22e8cd65
VB
63/* Generic ethernet send/receive */
64static int
8b549648
VB
65iflinux_eth_send(struct lldpd *cfg, struct lldpd_hardware *hardware, char *buffer,
66 size_t size)
22e8cd65
VB
67{
68 log_debug("interfaces", "send PDU to ethernet device %s (fd=%d)",
69 hardware->h_ifname, hardware->h_sendfd);
8b549648 70 return write(hardware->h_sendfd, buffer, size);
22e8cd65
VB
71}
72
73static int
8b549648 74iflinux_generic_recv(struct lldpd_hardware *hardware, int fd, char *buffer, size_t size,
462ef2ce 75 struct sockaddr_ll *from)
22e8cd65 76{
54cccdd4
VB
77 int n, retry = 0;
78 socklen_t fromlen;
22e8cd65 79
54cccdd4
VB
80retry:
81 fromlen = sizeof(*from);
82 memset(from, 0, fromlen);
8b549648
VB
83 if ((n = recvfrom(fd, buffer, size, 0, (struct sockaddr *)from, &fromlen)) ==
84 -1) {
54cccdd4 85 if (errno == EAGAIN && retry == 0) {
8b549648
VB
86 /* There may be an error queued in the socket. Clear it and
87 * retry. */
6c3697f2 88 levent_recv_error(fd, hardware->h_ifname);
54cccdd4
VB
89 retry++;
90 goto retry;
91 }
afd49b83 92 if (errno == ENETDOWN) {
8b549648
VB
93 log_debug("interfaces",
94 "error while receiving frame on %s (network down)",
afd49b83
VB
95 hardware->h_ifname);
96 } else {
8b549648
VB
97 log_warn("interfaces",
98 "error while receiving frame on %s (retry: %d)",
afd49b83
VB
99 hardware->h_ifname, retry);
100 hardware->h_rx_discarded_cnt++;
101 }
22e8cd65
VB
102 return -1;
103 }
8b549648 104 if (from->sll_pkttype == PACKET_OUTGOING) return -1;
462ef2ce
VB
105 return n;
106}
107
108static int
8b549648
VB
109iflinux_eth_recv(struct lldpd *cfg, struct lldpd_hardware *hardware, int fd,
110 char *buffer, size_t size)
462ef2ce
VB
111{
112 int n;
54cccdd4 113 struct sockaddr_ll from;
462ef2ce
VB
114
115 log_debug("interfaces", "receive PDU from ethernet device %s",
116 hardware->h_ifname);
117 if ((n = iflinux_generic_recv(hardware, fd, buffer, size, &from)) == -1)
22e8cd65
VB
118 return -1;
119 return n;
120}
121
122static int
123iflinux_eth_close(struct lldpd *cfg, struct lldpd_hardware *hardware)
124{
8b549648 125 log_debug("interfaces", "close ethernet device %s", hardware->h_ifname);
22e8cd65
VB
126 interfaces_setup_multicast(cfg, hardware->h_ifname, 1);
127 return 0;
128}
129
130static struct lldpd_ops eth_ops = {
131 .send = iflinux_eth_send,
132 .recv = iflinux_eth_recv,
133 .cleanup = iflinux_eth_close,
134};
135
6e75df87 136static int
8b549648 137iflinux_is_bridge(struct lldpd *cfg, struct interfaces_device_list *interfaces,
adbb6e54 138 struct interfaces_device *iface)
6e75df87 139{
16eacc5b 140#ifdef ENABLE_OLDIES
adbb6e54 141 struct interfaces_device *port;
6e75df87
VB
142 char path[SYSFS_PATH_MAX];
143 int f;
144
8b549648
VB
145 if ((snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/" SYSFS_BRIDGE_FDB,
146 iface->name)) >= SYSFS_PATH_MAX)
6f8925be 147 log_warnx("interfaces", "path truncated");
8b549648 148 if ((f = priv_open(path)) < 0) return 0;
6e75df87 149 close(f);
adbb6e54
VB
150
151 /* Also grab all ports */
8b549648 152 TAILQ_FOREACH (port, interfaces, next) {
adbb6e54
VB
153 if (port->upper) continue;
154 if (snprintf(path, SYSFS_PATH_MAX,
155 SYSFS_CLASS_NET "%s/" SYSFS_BRIDGE_PORT_SUBDIR "/%s/port_no",
156 iface->name, port->name) >= SYSFS_PATH_MAX)
157 log_warnx("interfaces", "path truncated");
8b549648
VB
158 if ((f = priv_open(path)) < 0) continue;
159 log_debug("interfaces", "port %s is bridged to %s", port->name,
160 iface->name);
adbb6e54
VB
161 port->upper = iface;
162 close(f);
163 }
164
6e75df87 165 return 1;
16eacc5b
VB
166#else
167 return 0;
168#endif
6e75df87
VB
169}
170
171static int
8b549648 172iflinux_is_vlan(struct lldpd *cfg, struct interfaces_device_list *interfaces,
adbb6e54 173 struct interfaces_device *iface)
6e75df87 174{
16eacc5b 175#ifdef ENABLE_OLDIES
b0cb07f7 176 struct vlan_ioctl_args ifv = {};
6e75df87 177 ifv.cmd = GET_VLAN_REALDEV_NAME_CMD;
adbb6e54
VB
178 strlcpy(ifv.device1, iface->name, sizeof(ifv.device1));
179 if (ioctl(cfg->g_sock, SIOCGIFVLAN, &ifv) >= 0) {
180 /* This is a VLAN, get the lower interface and the VID */
181 struct interfaces_device *lower =
182 interfaces_nametointerface(interfaces, ifv.u.device2);
183 if (!lower) {
184 log_debug("interfaces",
8b549648 185 "unable to find lower interface for VLAN %s", iface->name);
adbb6e54
VB
186 return 0;
187 }
6e75df87 188
adbb6e54
VB
189 memset(&ifv, 0, sizeof(ifv));
190 ifv.cmd = GET_VLAN_VID_CMD;
191 strlcpy(ifv.device1, iface->name, sizeof(ifv.device1));
192 if (ioctl(cfg->g_sock, SIOCGIFVLAN, &ifv) < 0) {
8b549648 193 log_debug("interfaces", "unable to find VID for VLAN %s",
adbb6e54
VB
194 iface->name);
195 return 0;
196 }
6e75df87 197
adbb6e54 198 iface->lower = lower;
626ea361 199 bitmap_set(iface->vlan_bmap, ifv.u.VID);
6e75df87 200 return 1;
adbb6e54 201 }
16eacc5b 202#endif
6e75df87
VB
203 return 0;
204}
205
206static int
8b549648 207iflinux_is_bond(struct lldpd *cfg, struct interfaces_device_list *interfaces,
adbb6e54 208 struct interfaces_device *master)
6e75df87 209{
16eacc5b 210#ifdef ENABLE_OLDIES
f5a0a15e
VB
211 /* Shortcut if we detect the new team driver. Upper and lower links
212 * should already be set with netlink in this case. */
213 if (master->driver && !strcmp(master->driver, "team")) {
214 return 1;
215 }
216
b0cb07f7
VB
217 struct ifreq ifr = {};
218 struct ifbond ifb = {};
c557a63b 219 strlcpy(ifr.ifr_name, master->name, sizeof(ifr.ifr_name));
8f88ff70 220 ifr.ifr_data = (char *)&ifb;
6e75df87
VB
221 if (ioctl(cfg->g_sock, SIOCBONDINFOQUERY, &ifr) >= 0) {
222 while (ifb.num_slaves--) {
adbb6e54 223 struct ifslave ifs;
6e75df87
VB
224 memset(&ifr, 0, sizeof(ifr));
225 memset(&ifs, 0, sizeof(ifs));
c557a63b 226 strlcpy(ifr.ifr_name, master->name, sizeof(ifr.ifr_name));
8f88ff70 227 ifr.ifr_data = (char *)&ifs;
6e75df87 228 ifs.slave_id = ifb.num_slaves;
adbb6e54
VB
229 if (ioctl(cfg->g_sock, SIOCBONDSLAVEINFOQUERY, &ifr) >= 0) {
230 struct interfaces_device *slave =
231 interfaces_nametointerface(interfaces,
232 ifs.slave_name);
233 if (slave == NULL) continue;
234 if (slave->upper) continue;
235 log_debug("interfaces",
8b549648
VB
236 "interface %s is enslaved to %s", slave->name,
237 master->name);
adbb6e54 238 slave->upper = master;
6e75df87
VB
239 }
240 }
adbb6e54 241 return 1;
6e75df87 242 }
16eacc5b 243#endif
6e75df87
VB
244 return 0;
245}
246
2d8bd087
VB
247/**
248 * Get permanent MAC from ethtool.
249 *
250 * Return 0 on success, -1 on error.
251 */
252static int
253iflinux_get_permanent_mac_ethtool(struct lldpd *cfg,
8b549648 254 struct interfaces_device_list *interfaces, struct interfaces_device *iface)
2d8bd087 255{
8505c295 256 int ret = -1;
2d8bd087 257 struct ifreq ifr = {};
8b549648 258 struct ethtool_perm_addr *epaddr =
b116fa3e 259 calloc(1, sizeof(struct ethtool_perm_addr) + ETHER_ADDR_LEN);
8505c295 260 if (epaddr == NULL) goto end;
2d8bd087
VB
261
262 strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name));
8505c295
VB
263 epaddr->cmd = ETHTOOL_GPERMADDR;
264 epaddr->size = ETHER_ADDR_LEN;
265 ifr.ifr_data = (caddr_t)epaddr;
2d8bd087
VB
266 if (ioctl(cfg->g_sock, SIOCETHTOOL, &ifr) == -1) {
267 static int once = 0;
268 if (errno == EPERM && !once) {
822804ac 269 log_warnx("interfaces",
2d8bd087
VB
270 "no permission to get permanent MAC address for %s (requires 2.6.19+)",
271 iface->name);
272 once = 1;
8505c295 273 goto end;
2d8bd087
VB
274 }
275 if (errno != EPERM)
8b549648
VB
276 log_warn("interfaces",
277 "cannot get permanent MAC address for %s", iface->name);
8505c295 278 goto end;
2d8bd087 279 }
8b549648
VB
280 if (epaddr->data[0] != 0 || epaddr->data[1] != 0 || epaddr->data[2] != 0 ||
281 epaddr->data[3] != 0 || epaddr->data[4] != 0 || epaddr->data[5] != 0) {
8505c295
VB
282 memcpy(iface->address, epaddr->data, ETHER_ADDR_LEN);
283 ret = 0;
284 goto end;
2d8bd087 285 }
c4c9f15a 286 log_debug("interfaces", "cannot get permanent MAC for %s (all 0)", iface->name);
8b549648 287end:
8505c295
VB
288 free(epaddr);
289 return ret;
2d8bd087
VB
290}
291
292/**
293 * Get permanent MAC address for a bond device.
294 */
1a3ec373 295static void
2d8bd087 296iflinux_get_permanent_mac_bond(struct lldpd *cfg,
8b549648 297 struct interfaces_device_list *interfaces, struct interfaces_device *iface)
01293dc4 298{
2d8bd087 299 struct interfaces_device *master = iface->upper;
01293dc4
VB
300 int f, state = 0;
301 FILE *netbond;
302 const char *slaveif = "Slave Interface: ";
303 const char *hwaddr = "Permanent HW addr: ";
304 u_int8_t mac[ETHER_ADDR_LEN];
305 char path[SYSFS_PATH_MAX];
306 char line[100];
307
01293dc4 308 /* We have a bond, we need to query it to get real MAC addresses */
8b549648
VB
309 if (snprintf(path, SYSFS_PATH_MAX, "/proc/net/bonding/%s", master->name) >=
310 SYSFS_PATH_MAX) {
01293dc4
VB
311 log_warnx("interfaces", "path truncated");
312 return;
313 }
314 if ((f = priv_open(path)) < 0) {
315 if (snprintf(path, SYSFS_PATH_MAX, "/proc/self/net/bonding/%s",
316 master->name) >= SYSFS_PATH_MAX) {
317 log_warnx("interfaces", "path truncated");
318 return;
319 }
320 f = priv_open(path);
321 }
322 if (f < 0) {
8b549648 323 log_warnx("interfaces", "unable to get permanent MAC address for %s",
2d8bd087 324 iface->name);
01293dc4
VB
325 return;
326 }
327 if ((netbond = fdopen(f, "r")) == NULL) {
328 log_warn("interfaces", "unable to read stream from %s", path);
329 close(f);
330 return;
331 }
332 /* State 0:
333 We parse the file to search "Slave Interface: ". If found, go to
334 state 1.
335 State 1:
336 We parse the file to search "Permanent HW addr: ". If found, we get
337 the mac.
338 */
339 while (fgets(line, sizeof(line), netbond)) {
340 switch (state) {
341 case 0:
342 if (strncmp(line, slaveif, strlen(slaveif)) == 0) {
8b549648
VB
343 if (line[strlen(line) - 1] == '\n')
344 line[strlen(line) - 1] = '\0';
345 if (strcmp(iface->name, line + strlen(slaveif)) == 0)
01293dc4
VB
346 state++;
347 }
348 break;
349 case 1:
350 if (strncmp(line, hwaddr, strlen(hwaddr)) == 0) {
8b549648
VB
351 if (line[strlen(line) - 1] == '\n')
352 line[strlen(line) - 1] = '\0';
01293dc4
VB
353 if (sscanf(line + strlen(hwaddr),
354 "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
8b549648
VB
355 &mac[0], &mac[1], &mac[2], &mac[3], &mac[4],
356 &mac[5]) != ETHER_ADDR_LEN) {
01293dc4
VB
357 log_warn("interfaces", "unable to parse %s",
358 line + strlen(hwaddr));
359 fclose(netbond);
360 return;
361 }
8b549648 362 memcpy(iface->address, mac, ETHER_ADDR_LEN);
01293dc4
VB
363 fclose(netbond);
364 return;
365 }
366 break;
367 }
368 }
2d8bd087 369 log_warnx("interfaces", "unable to find real MAC address for enslaved %s",
01293dc4
VB
370 iface->name);
371 fclose(netbond);
372}
373
2d8bd087
VB
374/**
375 * Get permanent MAC.
376 */
377static void
8b549648 378iflinux_get_permanent_mac(struct lldpd *cfg, struct interfaces_device_list *interfaces,
2d8bd087
VB
379 struct interfaces_device *iface)
380{
381 struct interfaces_device *master = iface->upper;
382
8b549648 383 if (master == NULL || master->type != IFACE_BOND_T) return;
2d8bd087
VB
384 if (iflinux_get_permanent_mac_ethtool(cfg, interfaces, iface) == -1 &&
385 (master->driver == NULL || !strcmp(master->driver, "bonding")))
386 /* Fallback to old method for a bond */
387 iflinux_get_permanent_mac_bond(cfg, interfaces, iface);
388}
389
dd55e649 390#ifdef ENABLE_DOT3
8b549648
VB
391# define ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32 (SCHAR_MAX)
392# define ETHTOOL_DECLARE_LINK_MODE_MASK(name) \
a9e0c90c 393 uint32_t name[ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32]
78c9dfde
VB
394
395struct ethtool_link_usettings {
396 struct ethtool_link_settings base;
397 struct {
398 ETHTOOL_DECLARE_LINK_MODE_MASK(supported);
399 ETHTOOL_DECLARE_LINK_MODE_MASK(advertising);
400 ETHTOOL_DECLARE_LINK_MODE_MASK(lp_advertising);
401 } link_modes;
402};
403
e86777ab 404static int
38cbcf2b
VB
405iflinux_ethtool_link_mode_test_bit(unsigned int nr, const uint32_t *mask)
406{
8b549648 407 if (nr >= 32 * ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32) return 0;
38cbcf2b
VB
408 return !!(mask[nr / 32] & (1 << (nr % 32)));
409}
e86777ab 410static void
38cbcf2b
VB
411iflinux_ethtool_link_mode_unset_bit(unsigned int nr, uint32_t *mask)
412{
8b549648 413 if (nr >= 32 * ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32) return;
38cbcf2b
VB
414 mask[nr / 32] &= ~(1 << (nr % 32));
415}
e86777ab 416static int
38cbcf2b
VB
417iflinux_ethtool_link_mode_is_empty(const uint32_t *mask)
418{
8b549648
VB
419 for (unsigned int i = 0; i < ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32; ++i) {
420 if (mask[i] != 0) return 0;
38cbcf2b
VB
421 }
422
423 return 1;
424}
425
78c9dfde 426static int
8b549648
VB
427iflinux_ethtool_glink(struct lldpd *cfg, const char *ifname,
428 struct ethtool_link_usettings *uset)
429{
78c9dfde
VB
430 int rc;
431
432 /* Try with ETHTOOL_GLINKSETTINGS first */
433 struct {
434 struct ethtool_link_settings req;
435 uint32_t link_mode_data[3 * ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32];
436 } ecmd;
437 static int8_t nwords = 0;
438 struct ifreq ifr = {};
439 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
440
441 if (nwords == 0) {
442 /* Do a handshake first. We assume that this is device-independant. */
443 memset(&ecmd, 0, sizeof(ecmd));
444 ecmd.req.cmd = ETHTOOL_GLINKSETTINGS;
445 ifr.ifr_data = (caddr_t)&ecmd;
446 rc = ioctl(cfg->g_sock, SIOCETHTOOL, &ifr);
447 if (rc == 0) {
448 nwords = -ecmd.req.link_mode_masks_nwords;
8b549648
VB
449 log_debug("interfaces", "glinksettings nwords is %" PRId8,
450 nwords);
68caeec4
VB
451 } else {
452 static int once = 0;
453 if (errno == EPERM && !once) {
822804ac 454 log_warnx("interfaces",
68caeec4 455 "cannot get ethtool link information "
822804ac
VB
456 "with GLINKSETTINGS (requires 4.9+). "
457 "25G+ speeds may be missing in MAC/PHY TLVs");
68caeec4
VB
458 once = 1;
459 }
460 nwords = -1;
461 }
78c9dfde
VB
462 }
463 if (nwords > 0) {
464 memset(&ecmd, 0, sizeof(ecmd));
465 ecmd.req.cmd = ETHTOOL_GLINKSETTINGS;
466 ecmd.req.link_mode_masks_nwords = nwords;
467 ifr.ifr_data = (caddr_t)&ecmd;
468 rc = ioctl(cfg->g_sock, SIOCETHTOOL, &ifr);
469 if (rc == 0) {
8b549648
VB
470 log_debug("interfaces",
471 "got ethtool results for %s with GLINKSETTINGS", ifname);
78c9dfde
VB
472 memcpy(&uset->base, &ecmd.req, sizeof(uset->base));
473 unsigned int u32_offs = 0;
474 memcpy(uset->link_modes.supported,
475 &ecmd.link_mode_data[u32_offs],
476 4 * ecmd.req.link_mode_masks_nwords);
477 u32_offs += ecmd.req.link_mode_masks_nwords;
478 memcpy(uset->link_modes.advertising,
479 &ecmd.link_mode_data[u32_offs],
480 4 * ecmd.req.link_mode_masks_nwords);
481 u32_offs += ecmd.req.link_mode_masks_nwords;
482 memcpy(uset->link_modes.lp_advertising,
483 &ecmd.link_mode_data[u32_offs],
484 4 * ecmd.req.link_mode_masks_nwords);
485 goto end;
486 }
487 }
488
489 /* Try with ETHTOOL_GSET */
490 struct ethtool_cmd ethc;
491 memset(&ethc, 0, sizeof(ethc));
492 ethc.cmd = ETHTOOL_GSET;
493 ifr.ifr_data = (caddr_t)&ethc;
494 rc = ioctl(cfg->g_sock, SIOCETHTOOL, &ifr);
495 if (rc == 0) {
496 /* Do a partial copy (only what we need) */
8b549648 497 log_debug("interfaces", "got ethtool results for %s with GSET", ifname);
78c9dfde
VB
498 memset(uset, 0, sizeof(*uset));
499 uset->base.cmd = ETHTOOL_GSET;
500 uset->base.link_mode_masks_nwords = 1;
501 uset->link_modes.supported[0] = ethc.supported;
502 uset->link_modes.advertising[0] = ethc.advertising;
503 uset->link_modes.lp_advertising[0] = ethc.lp_advertising;
504 uset->base.speed = (ethc.speed_hi << 16) | ethc.speed;
505 uset->base.duplex = ethc.duplex;
506 uset->base.port = ethc.port;
507 uset->base.autoneg = ethc.autoneg;
68caeec4
VB
508 } else {
509 static int once = 0;
510 if (errno == EPERM && !once) {
822804ac 511 log_warnx("interfaces",
68caeec4 512 "cannot get ethtool link information "
822804ac
VB
513 "with GSET (requires 2.6.19+). "
514 "MAC/PHY TLV will be unavailable");
68caeec4
VB
515 once = 1;
516 }
78c9dfde
VB
517 }
518end:
519 return rc;
520}
38cbcf2b 521
6e75df87
VB
522/* Fill up MAC/PHY for a given hardware port */
523static void
78c9dfde 524iflinux_macphy(struct lldpd *cfg, struct lldpd_hardware *hardware)
6e75df87 525{
215d0420 526 struct ethtool_link_usettings uset = {};
6e75df87
VB
527 struct lldpd_port *port = &hardware->h_lport;
528 int j;
529 int advertised_ethtool_to_rfc3636[][2] = {
8b549648
VB
530 { ETHTOOL_LINK_MODE_10baseT_Half_BIT, LLDP_DOT3_LINK_AUTONEG_10BASE_T },
531 { ETHTOOL_LINK_MODE_10baseT_Full_BIT,
532 LLDP_DOT3_LINK_AUTONEG_10BASET_FD },
533 { ETHTOOL_LINK_MODE_100baseT_Half_BIT,
534 LLDP_DOT3_LINK_AUTONEG_100BASE_TX },
535 { ETHTOOL_LINK_MODE_100baseT_Full_BIT,
536 LLDP_DOT3_LINK_AUTONEG_100BASE_TXFD },
537 { ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
538 LLDP_DOT3_LINK_AUTONEG_1000BASE_T },
539 { ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
540 LLDP_DOT3_LINK_AUTONEG_1000BASE_TFD },
541 { ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
542 LLDP_DOT3_LINK_AUTONEG_1000BASE_XFD },
543 { ETHTOOL_LINK_MODE_Pause_BIT, LLDP_DOT3_LINK_AUTONEG_FDX_PAUSE },
544 { ETHTOOL_LINK_MODE_Asym_Pause_BIT, LLDP_DOT3_LINK_AUTONEG_FDX_APAUSE },
545 { -1, 0 }
546 };
6e75df87 547
6f8925be
VB
548 log_debug("interfaces", "ask ethtool for the appropriate MAC/PHY for %s",
549 hardware->h_ifname);
78c9dfde 550 if (iflinux_ethtool_glink(cfg, hardware->h_ifname, &uset) == 0) {
8b549648
VB
551 port->p_macphy.autoneg_support =
552 iflinux_ethtool_link_mode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
553 uset.link_modes.supported);
554 port->p_macphy.autoneg_enabled =
555 (uset.base.autoneg == AUTONEG_DISABLE) ? 0 : 1;
556 for (j = 0; advertised_ethtool_to_rfc3636[j][0] >= 0; j++) {
38cbcf2b 557 if (iflinux_ethtool_link_mode_test_bit(
8b549648
VB
558 advertised_ethtool_to_rfc3636[j][0],
559 uset.link_modes.advertising)) {
a97e3dfe 560 port->p_macphy.autoneg_advertised |=
6e75df87 561 advertised_ethtool_to_rfc3636[j][1];
38cbcf2b 562 iflinux_ethtool_link_mode_unset_bit(
8b549648
VB
563 advertised_ethtool_to_rfc3636[j][0],
564 uset.link_modes.advertising);
a97e3dfe 565 }
6e75df87 566 }
8b549648
VB
567 iflinux_ethtool_link_mode_unset_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
568 uset.link_modes.advertising);
569 iflinux_ethtool_link_mode_unset_bit(ETHTOOL_LINK_MODE_TP_BIT,
570 uset.link_modes.advertising);
571 iflinux_ethtool_link_mode_unset_bit(ETHTOOL_LINK_MODE_AUI_BIT,
572 uset.link_modes.advertising);
573 iflinux_ethtool_link_mode_unset_bit(ETHTOOL_LINK_MODE_MII_BIT,
574 uset.link_modes.advertising);
575 iflinux_ethtool_link_mode_unset_bit(ETHTOOL_LINK_MODE_FIBRE_BIT,
576 uset.link_modes.advertising);
577 iflinux_ethtool_link_mode_unset_bit(ETHTOOL_LINK_MODE_BNC_BIT,
578 uset.link_modes.advertising);
579 iflinux_ethtool_link_mode_unset_bit(ETHTOOL_LINK_MODE_Pause_BIT,
580 uset.link_modes.advertising);
581 iflinux_ethtool_link_mode_unset_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
582 uset.link_modes.advertising);
583 iflinux_ethtool_link_mode_unset_bit(ETHTOOL_LINK_MODE_Backplane_BIT,
584 uset.link_modes.advertising);
38cbcf2b 585 if (!iflinux_ethtool_link_mode_is_empty(uset.link_modes.advertising)) {
8b549648
VB
586 port->p_macphy.autoneg_advertised |=
587 LLDP_DOT3_LINK_AUTONEG_OTHER;
38cbcf2b
VB
588 }
589 switch (uset.base.speed) {
6e75df87 590 case SPEED_10:
8b549648
VB
591 port->p_macphy.mau_type = (uset.base.duplex == DUPLEX_FULL) ?
592 LLDP_DOT3_MAU_10BASETFD :
593 LLDP_DOT3_MAU_10BASETHD;
594 if (uset.base.port == PORT_BNC)
595 port->p_macphy.mau_type = LLDP_DOT3_MAU_10BASE2;
38cbcf2b 596 if (uset.base.port == PORT_FIBRE)
8b549648
VB
597 port->p_macphy.mau_type =
598 (uset.base.duplex == DUPLEX_FULL) ?
599 LLDP_DOT3_MAU_10BASEFLFD :
600 LLDP_DOT3_MAU_10BASEFLHD;
6e75df87
VB
601 break;
602 case SPEED_100:
8b549648
VB
603 port->p_macphy.mau_type = (uset.base.duplex == DUPLEX_FULL) ?
604 LLDP_DOT3_MAU_100BASETXFD :
605 LLDP_DOT3_MAU_100BASETXHD;
38cbcf2b 606 if (uset.base.port == PORT_BNC)
8b549648
VB
607 port->p_macphy.mau_type =
608 (uset.base.duplex == DUPLEX_FULL) ?
609 LLDP_DOT3_MAU_100BASET2FD :
610 LLDP_DOT3_MAU_100BASET2HD;
38cbcf2b 611 if (uset.base.port == PORT_FIBRE)
8b549648
VB
612 port->p_macphy.mau_type =
613 (uset.base.duplex == DUPLEX_FULL) ?
614 LLDP_DOT3_MAU_100BASEFXFD :
615 LLDP_DOT3_MAU_100BASEFXHD;
6e75df87
VB
616 break;
617 case SPEED_1000:
8b549648
VB
618 port->p_macphy.mau_type = (uset.base.duplex == DUPLEX_FULL) ?
619 LLDP_DOT3_MAU_1000BASETFD :
620 LLDP_DOT3_MAU_1000BASETHD;
38cbcf2b 621 if (uset.base.port == PORT_FIBRE)
8b549648
VB
622 port->p_macphy.mau_type =
623 (uset.base.duplex == DUPLEX_FULL) ?
624 LLDP_DOT3_MAU_1000BASEXFD :
625 LLDP_DOT3_MAU_1000BASEXHD;
6e75df87 626 break;
d5b5adba 627 case SPEED_2500:
628 port->p_macphy.mau_type = LLDP_DOT3_MAU_2P5GIGT;
629 break;
630 case SPEED_5000:
631 port->p_macphy.mau_type = LLDP_DOT3_MAU_5GIGT;
632 break;
6e75df87 633 case SPEED_10000:
d5b5adba 634 // Distinguish between RJ45 BaseT, DAC BaseCX4, or Fibre BaseLR
635 if (uset.base.port == PORT_TP) {
636 port->p_macphy.mau_type = LLDP_DOT3_MAU_10GBASET;
8b549648 637 } else if (uset.base.port == PORT_FIBRE) {
d5b5adba 638 port->p_macphy.mau_type = LLDP_DOT3_MAU_10GIGBASELR;
8b549648 639 } else if (uset.base.port == PORT_DA) {
d5b5adba 640 port->p_macphy.mau_type = LLDP_DOT3_MAU_10GIGBASECX4;
641 }
642 break;
643 case SPEED_25000:
644 // Distinguish between RJ45 BaseT, DAC BaseCR, or Fibre BaseLR
645 if (uset.base.port == PORT_TP) {
646 port->p_macphy.mau_type = LLDP_DOT3_MAU_25GBASET;
8b549648 647 } else if (uset.base.port == PORT_FIBRE) {
d5b5adba 648 port->p_macphy.mau_type = LLDP_DOT3_MAU_25GBASELR;
8b549648 649 } else if (uset.base.port == PORT_DA) {
d5b5adba 650 port->p_macphy.mau_type = LLDP_DOT3_MAU_25GBASECR;
651 }
6e75df87 652 break;
38cbcf2b
VB
653 case SPEED_40000:
654 // Same kind of approximation.
8b549648
VB
655 port->p_macphy.mau_type = (uset.base.port == PORT_FIBRE) ?
656 LLDP_DOT3_MAU_40GBASELR4 :
657 LLDP_DOT3_MAU_40GBASECR4;
3a59626a 658 break;
d5b5adba 659 case SPEED_50000:
660 // Same kind of approximation.
8b549648
VB
661 port->p_macphy.mau_type = (uset.base.port == PORT_FIBRE) ?
662 LLDP_DOT3_MAU_50GBASELR :
663 LLDP_DOT3_MAU_50GBASECR;
d5b5adba 664 break;
38cbcf2b
VB
665 case SPEED_100000:
666 // Ditto
8b549648
VB
667 port->p_macphy.mau_type = (uset.base.port == PORT_FIBRE) ?
668 LLDP_DOT3_MAU_100GBASELR4 :
669 LLDP_DOT3_MAU_100GBASECR4;
3a59626a 670 break;
6e75df87 671 }
8b549648
VB
672 if (uset.base.port == PORT_AUI)
673 port->p_macphy.mau_type = LLDP_DOT3_MAU_AUI;
6e75df87 674 }
6e75df87 675}
8b549648 676#else /* ENABLE_DOT3 */
dd55e649
VB
677static void
678iflinux_macphy(struct lldpd *cfg, struct lldpd_hardware *hardware)
679{
680}
681#endif /* ENABLE_DOT3 */
682
2f4ff307 683#ifdef ENABLE_OLDIES
e12c2365
VB
684struct bond_master {
685 char name[IFNAMSIZ];
8b549648 686 int index;
e12c2365
VB
687};
688
849954d7
VB
689static int
690iface_bond_init(struct lldpd *cfg, struct lldpd_hardware *hardware)
691{
e12c2365 692 struct bond_master *master = hardware->h_data;
e735a319 693 int fd;
849954d7
VB
694 int un = 1;
695
e12c2365 696 if (!master) return -1;
849954d7 697
8b549648 698 log_debug("interfaces", "initialize enslaved device %s", hardware->h_ifname);
6f8925be 699
849954d7 700 /* First, we get a socket to the raw physical interface */
8b549648 701 if ((fd = priv_iface_init(hardware->h_ifindex, hardware->h_ifname)) == -1)
849954d7
VB
702 return -1;
703 hardware->h_sendfd = fd;
adbb6e54 704 interfaces_setup_multicast(cfg, hardware->h_ifname, 0);
849954d7
VB
705
706 /* Then, we open a raw interface for the master */
0da01fd6 707 log_debug("interfaces", "enslaved device %s has master %s(%d)",
148a1efe 708 hardware->h_ifname, master->name, master->index);
8b50be7f 709 if ((fd = priv_iface_init(master->index, master->name)) == -1) {
849954d7
VB
710 close(hardware->h_sendfd);
711 return -1;
712 }
849954d7
VB
713 /* With bonding and older kernels (< 2.6.27) we need to listen
714 * to bond device. We use setsockopt() PACKET_ORIGDEV to get
715 * physical device instead of bond device (works with >=
716 * 2.6.24). */
8b549648
VB
717 if (setsockopt(fd, SOL_PACKET, PACKET_ORIGDEV, &un, sizeof(un)) == -1) {
718 log_info("interfaces",
719 "unable to setsockopt for master bonding device of %s. "
e12c2365
VB
720 "You will get inaccurate results",
721 hardware->h_ifname);
849954d7 722 }
adbb6e54 723 interfaces_setup_multicast(cfg, master->name, 0);
849954d7 724
ba93c521 725 levent_hardware_add_fd(hardware, hardware->h_sendfd);
d6e889b6 726 levent_hardware_add_fd(hardware, fd);
6f8925be 727 log_debug("interfaces", "interface %s initialized (fd=%d,master=%s[%d])",
8b549648 728 hardware->h_ifname, hardware->h_sendfd, master->name, fd);
849954d7
VB
729 return 0;
730}
731
849954d7 732static int
8b549648
VB
733iface_bond_recv(struct lldpd *cfg, struct lldpd_hardware *hardware, int fd,
734 char *buffer, size_t size)
849954d7
VB
735{
736 int n;
54cccdd4 737 struct sockaddr_ll from;
e12c2365 738 struct bond_master *master = hardware->h_data;
849954d7 739
0da01fd6 740 log_debug("interfaces", "receive PDU from enslaved device %s",
6f8925be 741 hardware->h_ifname);
462ef2ce 742 if ((n = iflinux_generic_recv(hardware, fd, buffer, size, &from)) == -1)
849954d7 743 return -1;
8b549648 744 if (fd == hardware->h_sendfd) /* We received this on the physical interface. */
849954d7
VB
745 return n;
746 /* We received this on the bonding interface. Is it really for us? */
8b549648 747 if (from.sll_ifindex == hardware->h_ifindex) /* This is for us */
849954d7 748 return n;
e12c2365 749 if (from.sll_ifindex == master->index)
849954d7
VB
750 /* We don't know from which physical interface it comes (kernel
751 * < 2.6.24). In doubt, this is for us. */
752 return n;
8b549648 753 return -1; /* Not for us */
849954d7
VB
754}
755
756static int
757iface_bond_close(struct lldpd *cfg, struct lldpd_hardware *hardware)
758{
e12c2365 759 struct bond_master *master = hardware->h_data;
8b549648 760 log_debug("interfaces", "closing enslaved device %s", hardware->h_ifname);
adbb6e54
VB
761 interfaces_setup_multicast(cfg, hardware->h_ifname, 1);
762 interfaces_setup_multicast(cfg, master->name, 1);
8b549648
VB
763 free(hardware->h_data);
764 hardware->h_data = NULL;
849954d7
VB
765 return 0;
766}
767
adbb6e54 768struct lldpd_ops bond_ops = {
5347914e 769 .send = iflinux_eth_send,
adbb6e54
VB
770 .recv = iface_bond_recv,
771 .cleanup = iface_bond_close,
772};
773
e12c2365 774static void
adbb6e54 775iflinux_handle_bond(struct lldpd *cfg, struct interfaces_device_list *interfaces)
849954d7 776{
adbb6e54
VB
777 struct interfaces_device *iface;
778 struct interfaces_device *master;
849954d7 779 struct lldpd_hardware *hardware;
c557a63b 780 struct bond_master *bmaster;
32945d6a 781 int created;
8b549648 782 TAILQ_FOREACH (iface, interfaces, next) {
adbb6e54 783 if (!(iface->type & IFACE_PHYSICAL_T)) continue;
0fa2254b 784 if (iface->ignore) continue;
adbb6e54 785 if (!iface->upper || !(iface->upper->type & IFACE_BOND_T)) continue;
849954d7 786
adbb6e54 787 master = iface->upper;
8b549648
VB
788 log_debug("interfaces",
789 "%s is an acceptable enslaved device (master=%s)", iface->name,
790 master->name);
32945d6a 791 created = 0;
8b549648
VB
792 if ((hardware = lldpd_get_hardware(cfg, iface->name, iface->index)) ==
793 NULL) {
794 if ((hardware = lldpd_alloc_hardware(cfg, iface->name,
795 iface->index)) == NULL) {
796 log_warnx("interfaces",
797 "Unable to allocate space for %s", iface->name);
e12c2365
VB
798 continue;
799 }
32945d6a
VB
800 created = 1;
801 }
802 if (hardware->h_flags) continue;
3d916d6d 803 if (hardware->h_ops != &bond_ops || hardware->h_ifindex_changed) {
32945d6a
VB
804 if (!created) {
805 log_debug("interfaces",
806 "bond %s is converted from another type of interface",
807 hardware->h_ifname);
808 if (hardware->h_ops && hardware->h_ops->cleanup)
809 hardware->h_ops->cleanup(cfg, hardware);
810 levent_hardware_release(hardware);
811 levent_hardware_init(hardware);
812 }
8b549648
VB
813 bmaster = hardware->h_data =
814 calloc(1, sizeof(struct bond_master));
08ced6b4 815 if (!bmaster) {
e12c2365
VB
816 log_warn("interfaces", "not enough memory");
817 lldpd_hardware_cleanup(cfg, hardware);
818 continue;
819 }
8b549648
VB
820 } else
821 bmaster = hardware->h_data;
32945d6a
VB
822 bmaster->index = master->index;
823 strlcpy(bmaster->name, master->name, IFNAMSIZ);
3d916d6d 824 if (hardware->h_ops != &bond_ops || hardware->h_ifindex_changed) {
849954d7 825 if (iface_bond_init(cfg, hardware) != 0) {
6f8925be 826 log_warn("interfaces", "unable to initialize %s",
849954d7
VB
827 hardware->h_ifname);
828 lldpd_hardware_cleanup(cfg, hardware);
829 continue;
830 }
831 hardware->h_ops = &bond_ops;
5347914e 832 hardware->h_mangle = 1;
32945d6a
VB
833 }
834 if (created)
bdfe4193 835 interfaces_helper_add_hardware(cfg, hardware);
32945d6a 836 else
4b292b55 837 lldpd_port_cleanup(&hardware->h_lport, 0);
e12c2365
VB
838
839 hardware->h_flags = iface->flags;
0fa2254b 840 iface->ignore = 1;
849954d7
VB
841
842 /* Get local address */
4e5f34c5 843 memcpy(&hardware->h_lladdr, iface->address, ETHER_ADDR_LEN);
e12c2365 844
36bd79e3 845 /* Fill information about port */
8fbd3195 846 interfaces_helper_port_name_desc(cfg, hardware, iface);
e12c2365 847
849954d7 848 /* Fill additional info */
8b549648 849# ifdef ENABLE_DOT3
e12c2365 850 hardware->h_lport.p_aggregid = master->index;
8b549648 851# endif
e12c2365 852 hardware->h_mtu = iface->mtu ? iface->mtu : 1500;
849954d7
VB
853 }
854}
2f4ff307 855#endif
849954d7 856
adbb6e54 857/* Query each interface to get the appropriate driver */
5994b27d 858static void
8b549648 859iflinux_add_driver(struct lldpd *cfg, struct interfaces_device_list *interfaces)
5994b27d 860{
adbb6e54 861 struct interfaces_device *iface;
8b549648
VB
862 TAILQ_FOREACH (iface, interfaces, next) {
863 struct ethtool_drvinfo ethc = { .cmd = ETHTOOL_GDRVINFO };
864 struct ifreq ifr = { .ifr_data = (caddr_t)&ethc };
adbb6e54
VB
865 if (iface->driver) continue;
866
867 strlcpy(ifr.ifr_name, iface->name, IFNAMSIZ);
868 if (ioctl(cfg->g_sock, SIOCETHTOOL, &ifr) == 0) {
869 iface->driver = strdup(ethc.driver);
8b549648
VB
870 log_debug("interfaces", "driver for %s is `%s`", iface->name,
871 iface->driver);
adbb6e54 872 }
5994b27d
VB
873 }
874}
875
adbb6e54 876/* Query each interface to see if it is a wireless one */
e12c2365 877static void
8b549648 878iflinux_add_wireless(struct lldpd *cfg, struct interfaces_device_list *interfaces)
f6c4ca4b 879{
389ec9d4 880#ifdef ENABLE_OLDIES
adbb6e54 881 struct interfaces_device *iface;
8b549648 882 TAILQ_FOREACH (iface, interfaces, next) {
389ec9d4
VB
883 if (iface->type &
884 (IFACE_VLAN_T | IFACE_BOND_T | IFACE_BRIDGE_T | IFACE_WIRELESS_T))
885 continue;
b0cb07f7 886 struct iwreq iwr = {};
adbb6e54
VB
887 strlcpy(iwr.ifr_name, iface->name, IFNAMSIZ);
888 if (ioctl(cfg->g_sock, SIOCGIWNAME, &iwr) >= 0) {
8b549648 889 log_debug("interfaces", "%s is wireless", iface->name);
adbb6e54 890 iface->type |= IFACE_WIRELESS_T | IFACE_PHYSICAL_T;
f6c4ca4b 891 }
f6c4ca4b 892 }
389ec9d4 893#endif
adbb6e54 894}
f6c4ca4b 895
adbb6e54
VB
896/* Query each interface to see if it is a bridge */
897static void
8b549648 898iflinux_add_bridge(struct lldpd *cfg, struct interfaces_device_list *interfaces)
adbb6e54
VB
899{
900 struct interfaces_device *iface;
f6c4ca4b 901
8b549648
VB
902 TAILQ_FOREACH (iface, interfaces, next) {
903 if (iface->type &
904 (IFACE_PHYSICAL_T | IFACE_VLAN_T | IFACE_BOND_T | IFACE_BRIDGE_T))
adbb6e54
VB
905 continue;
906 if (iflinux_is_bridge(cfg, interfaces, iface)) {
8b549648 907 log_debug("interfaces", "interface %s is a bridge",
adbb6e54
VB
908 iface->name);
909 iface->type |= IFACE_BRIDGE_T;
f6c4ca4b 910 }
f6c4ca4b 911 }
f6c4ca4b
VB
912}
913
adbb6e54 914/* Query each interface to see if it is a bond */
f6c4ca4b 915static void
8b549648 916iflinux_add_bond(struct lldpd *cfg, struct interfaces_device_list *interfaces)
6e75df87 917{
adbb6e54 918 struct interfaces_device *iface;
e12c2365 919
8b549648
VB
920 TAILQ_FOREACH (iface, interfaces, next) {
921 if (iface->type &
922 (IFACE_PHYSICAL_T | IFACE_VLAN_T | IFACE_BOND_T | IFACE_BRIDGE_T))
6e75df87 923 continue;
adbb6e54 924 if (iflinux_is_bond(cfg, interfaces, iface)) {
8b549648 925 log_debug("interfaces", "interface %s is a bond", iface->name);
adbb6e54 926 iface->type |= IFACE_BOND_T;
adbb6e54 927 }
6e75df87 928 }
6e75df87
VB
929}
930
adbb6e54 931/* Query each interface to see if it is a vlan */
e12c2365 932static void
8b549648 933iflinux_add_vlan(struct lldpd *cfg, struct interfaces_device_list *interfaces)
6e75df87 934{
adbb6e54 935 struct interfaces_device *iface;
d4e4c804 936
8b549648
VB
937 TAILQ_FOREACH (iface, interfaces, next) {
938 if (iface->type &
939 (IFACE_PHYSICAL_T | IFACE_VLAN_T | IFACE_BOND_T | IFACE_BRIDGE_T))
adbb6e54
VB
940 continue;
941 if (iflinux_is_vlan(cfg, interfaces, iface)) {
8b549648 942 log_debug("interfaces", "interface %s is a VLAN", iface->name);
adbb6e54 943 iface->type |= IFACE_VLAN_T;
6e75df87
VB
944 }
945 }
946}
31ee070d 947
e12c2365 948static void
8b549648 949iflinux_add_physical(struct lldpd *cfg, struct interfaces_device_list *interfaces)
b4ac8083 950{
adbb6e54 951 struct interfaces_device *iface;
28fb4885 952 /* Deny some drivers */
8b549648
VB
953 const char *const *rif;
954 const char *const denied_drivers[] = { "cdc_mbim", "vxlan", NULL };
b4ac8083 955
8b549648
VB
956 TAILQ_FOREACH (iface, interfaces, next) {
957 if (iface->type & (IFACE_VLAN_T | IFACE_BOND_T | IFACE_BRIDGE_T))
adbb6e54 958 continue;
b4ac8083 959
adbb6e54
VB
960 iface->type &= ~IFACE_PHYSICAL_T;
961
962 /* We request that the interface is able to do either multicast
963 * or broadcast to be able to send discovery frames. */
8b549648
VB
964 if (!(iface->flags & (IFF_MULTICAST | IFF_BROADCAST))) {
965 log_debug("interfaces",
966 "skip %s: not able to do multicast nor broadcast",
adbb6e54 967 iface->name);
b4ac8083 968 continue;
adbb6e54 969 }
b4ac8083 970
28fb4885 971 /* Check if the driver is not denied */
45369c0a
VB
972 if (iface->driver) {
973 int skip = 0;
28fb4885 974 for (rif = denied_drivers; *rif; rif++) {
45369c0a 975 if (strcmp(iface->driver, *rif) == 0) {
8b549648
VB
976 log_debug("interfaces",
977 "skip %s: denied driver", iface->name);
45369c0a
VB
978 skip = 1;
979 break;
980 }
981 }
982 if (skip) continue;
983 }
984
981ee4fe 985 /* If the interface is linked to another one, skip it too. */
8b549648
VB
986 if (iface->lower &&
987 (!iface->driver ||
988 (strcmp(iface->driver, "veth") &&
989 strcmp(iface->driver, "dsa")))) {
990 log_debug("interfaces",
991 "skip %s: there is a lower interface (%s)", iface->name,
992 iface->lower->name);
981ee4fe
VB
993 continue;
994 }
995
8b549648
VB
996 /* Get the real MAC address (for example, if the interface is enslaved)
997 */
12baf781
VB
998 iflinux_get_permanent_mac(cfg, interfaces, iface);
999
8b549648 1000 log_debug("interfaces", "%s is a physical interface", iface->name);
adbb6e54 1001 iface->type |= IFACE_PHYSICAL_T;
b4ac8083
VB
1002 }
1003}
1004
e12c2365
VB
1005void
1006interfaces_update(struct lldpd *cfg)
1007{
adbb6e54 1008 struct lldpd_hardware *hardware;
281a5cd4
VB
1009 struct interfaces_device_list *interfaces;
1010 struct interfaces_address_list *addresses;
13181ede
VB
1011 interfaces = netlink_get_interfaces(cfg);
1012 addresses = netlink_get_addresses(cfg);
e12c2365
VB
1013 if (interfaces == NULL || addresses == NULL) {
1014 log_warnx("interfaces", "cannot update the list of local interfaces");
0fa2254b 1015 return;
e12c2365
VB
1016 }
1017
adbb6e54
VB
1018 /* Add missing bits to list of interfaces */
1019 iflinux_add_driver(cfg, interfaces);
a2b113ef 1020 if (LOCAL_CHASSIS(cfg)->c_cap_available & LLDP_CAP_WLAN)
1021 iflinux_add_wireless(cfg, interfaces);
1022 if (LOCAL_CHASSIS(cfg)->c_cap_available & LLDP_CAP_BRIDGE)
1023 iflinux_add_bridge(cfg, interfaces);
adbb6e54
VB
1024 iflinux_add_bond(cfg, interfaces);
1025 iflinux_add_vlan(cfg, interfaces);
1026 iflinux_add_physical(cfg, interfaces);
1027
28fb4885 1028 interfaces_helper_allowlist(cfg, interfaces);
2f4ff307 1029#ifdef ENABLE_OLDIES
adbb6e54 1030 iflinux_handle_bond(cfg, interfaces);
2f4ff307 1031#endif
8b549648 1032 interfaces_helper_physical(cfg, interfaces, &eth_ops, iflinux_eth_init);
e12c2365 1033#ifdef ENABLE_DOT1
adbb6e54 1034 interfaces_helper_vlan(cfg, interfaces);
e12c2365 1035#endif
68bc4a4d 1036 interfaces_helper_mgmt(cfg, addresses, interfaces);
adbb6e54
VB
1037 interfaces_helper_chassis(cfg, interfaces);
1038
1039 /* Mac/PHY */
8b549648 1040 TAILQ_FOREACH (hardware, &cfg->g_hardware, h_entries) {
e99f4e1e 1041 if (!(hardware->h_flags & IFF_RUNNING)) continue;
78c9dfde 1042 iflinux_macphy(cfg, hardware);
f84199dd 1043 interfaces_helper_promisc(cfg, hardware);
adbb6e54 1044 }
e12c2365 1045}
13181ede
VB
1046
1047void
1048interfaces_cleanup(struct lldpd *cfg)
1049{
1050 netlink_cleanup(cfg);
1051}