1 /* -*- mode: c; c-file-style: "openbsd" -*- */
3 * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
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.
18 #define INCLUDE_LINUX_IF_H
26 #include <sys/ioctl.h>
27 #include <sys/types.h>
31 #include <arpa/inet.h>
32 #include <net/if_arp.h>
33 #include <linux/if_vlan.h>
34 #include <linux/if_bonding.h>
35 #include <linux/if_bridge.h>
36 #include <linux/wireless.h>
37 #include <linux/sockios.h>
38 #include <linux/filter.h>
39 #include <linux/if_packet.h>
41 #define SYSFS_PATH_MAX 256
42 #define MAX_PORTS 1024
43 #define MAX_BRIDGES 1024
45 /* BPF filter to get revelant information from interfaces */
46 /* LLDP: "ether proto 0x88cc and ether dst 01:80:c2:00:00:0e" */
47 /* FDP: "ether dst 01:e0:52:cc:cc:cc" */
48 /* CDP: "ether dst 01:00:0c:cc:cc:cc" */
49 /* SONMP: "ether dst 01:00:81:00:01:00" */
50 /* EDP: "ether dst 00:e0:2b:00:00:00" */
51 /* For optimization purpose, we first check if the first bit of the
52 first byte is 1. if not, this can only be an EDP packet:
54 tcpdump -dd "(ether[0] & 1 = 1 and
55 ((ether proto 0x88cc and ether dst 01:80:c2:00:00:0e) or
56 (ether dst 01:e0:52:cc:cc:cc) or
57 (ether dst 01:00:0c:cc:cc:cc) or
58 (ether dst 01:00:81:00:01:00))) or
59 (ether dst 00:e0:2b:00:00:00)"
62 #define LLDPD_FILTER_F \
63 { 0x30, 0, 0, 0x00000000 }, \
64 { 0x54, 0, 0, 0x00000001 }, \
65 { 0x15, 0, 14, 0x00000001 }, \
66 { 0x28, 0, 0, 0x0000000c }, \
67 { 0x15, 0, 4, 0x000088cc }, \
68 { 0x20, 0, 0, 0x00000002 }, \
69 { 0x15, 0, 2, 0xc200000e }, \
70 { 0x28, 0, 0, 0x00000000 }, \
71 { 0x15, 12, 13, 0x00000180 }, \
72 { 0x20, 0, 0, 0x00000002 }, \
73 { 0x15, 0, 2, 0x52cccccc }, \
74 { 0x28, 0, 0, 0x00000000 }, \
75 { 0x15, 8, 9, 0x000001e0 }, \
76 { 0x15, 1, 0, 0x0ccccccc }, \
77 { 0x15, 0, 2, 0x81000100 }, \
78 { 0x28, 0, 0, 0x00000000 }, \
79 { 0x15, 4, 5, 0x00000100 }, \
80 { 0x20, 0, 0, 0x00000002 }, \
81 { 0x15, 0, 3, 0x2b000000 }, \
82 { 0x28, 0, 0, 0x00000000 }, \
83 { 0x15, 0, 1, 0x000000e0 }, \
84 { 0x6, 0, 0, 0x0000ffff }, \
85 { 0x6, 0, 0, 0x00000000 },
87 static struct sock_filter lldpd_filter_f
[] = { LLDPD_FILTER_F
};
90 extern unsigned int if_nametoindex (__const
char *__ifname
) __THROW
;
91 extern char *if_indextoname (unsigned int __ifindex
, char *__ifname
) __THROW
;
93 struct lldpd_ops eth_ops
;
94 struct lldpd_ops bond_ops
;
97 pattern_match(char *iface
, char *list
, int found
)
99 char *interfaces
= NULL
;
102 if ((interfaces
= strdup(list
)) == NULL
) {
103 LLOG_WARNX("unable to allocate memory");
107 for (pattern
= strtok(interfaces
, ",");
109 pattern
= strtok(NULL
, ",")) {
110 if ((pattern
[0] == '!') &&
111 ((fnmatch(pattern
+ 1, iface
, 0) == 0))) {
112 /* Blacklisted. No need to search further. */
116 if (fnmatch(pattern
, iface
, 0) == 0)
125 old_iface_is_bridge(struct lldpd
*cfg
, const char *name
)
127 int ifindices
[MAX_BRIDGES
];
128 char ifname
[IFNAMSIZ
];
130 unsigned long args
[3] = { BRCTL_GET_BRIDGES
,
131 (unsigned long)ifindices
, MAX_BRIDGES
};
132 if ((num
= ioctl(cfg
->g_sock
, SIOCGIFBR
, args
)) < 0)
133 /* This can happen with a 64bit kernel and 32bit
134 userland, don't output anything about this to avoid
137 for (i
= 0; i
< num
; i
++) {
138 if (if_indextoname(ifindices
[i
], ifname
) == NULL
)
139 LLOG_INFO("unable to get name of interface %d",
141 else if (strncmp(name
, ifname
, IFNAMSIZ
) == 0)
148 iface_is_bridge(struct lldpd
*cfg
, const char *name
)
150 #ifdef SYSFS_BRIDGE_FDB
151 char path
[SYSFS_PATH_MAX
];
154 if ((snprintf(path
, SYSFS_PATH_MAX
,
155 SYSFS_CLASS_NET
"%s/" SYSFS_BRIDGE_FDB
, name
)) >= SYSFS_PATH_MAX
)
156 LLOG_WARNX("path truncated");
157 if ((f
= priv_open(path
)) < 0) {
158 return old_iface_is_bridge(cfg
, name
);
163 return old_iface_is_bridge(cfg
, name
);
169 old_iface_is_bridged_to(struct lldpd
*cfg
, const char *slave
, const char *master
)
171 int j
, index
= if_nametoindex(slave
);
172 int ifptindices
[MAX_PORTS
];
173 unsigned long args2
[4] = { BRCTL_GET_PORT_LIST
,
174 (unsigned long)ifptindices
, MAX_PORTS
, 0 };
177 strncpy(ifr
.ifr_name
, master
, IFNAMSIZ
);
178 memset(ifptindices
, 0, sizeof(ifptindices
));
179 ifr
.ifr_data
= (char *)&args2
;
181 if (ioctl(cfg
->g_sock
, SIOCDEVPRIVATE
, &ifr
) < 0)
182 /* This can happen with a 64bit kernel and 32bit
183 userland, don't output anything about this to avoid
187 for (j
= 0; j
< MAX_PORTS
; j
++) {
188 if (ifptindices
[j
] == index
)
196 iface_is_bridged_to(struct lldpd
*cfg
, const char *slave
, const char *master
)
198 #ifdef SYSFS_BRIDGE_PORT_SUBDIR
199 char path
[SYSFS_PATH_MAX
];
202 /* Master should be a bridge, first */
203 if (!iface_is_bridge(cfg
, master
)) return 0;
205 if (snprintf(path
, SYSFS_PATH_MAX
,
206 SYSFS_CLASS_NET
"%s/" SYSFS_BRIDGE_PORT_SUBDIR
"/%s/port_no",
207 master
, slave
) >= SYSFS_PATH_MAX
)
208 LLOG_WARNX("path truncated");
209 if ((f
= priv_open(path
)) < 0) {
210 return old_iface_is_bridged_to(cfg
, slave
, master
);
215 return old_iface_is_bridged_to(cfg
, slave
, master
);
221 iface_is_vlan(struct lldpd
*cfg
, const char *name
)
223 struct vlan_ioctl_args ifv
;
224 memset(&ifv
, 0, sizeof(ifv
));
225 ifv
.cmd
= GET_VLAN_REALDEV_NAME_CMD
;
226 if ((strlcpy(ifv
.device1
, name
, sizeof(ifv
.device1
))) >=
228 LLOG_WARNX("device name truncated");
229 if (ioctl(cfg
->g_sock
, SIOCGIFVLAN
, &ifv
) >= 0)
235 iface_is_wireless(struct lldpd
*cfg
, const char *name
)
238 strlcpy(iwr
.ifr_name
, name
, IFNAMSIZ
);
239 if (ioctl(cfg
->g_sock
, SIOCGIWNAME
, &iwr
) >= 0)
245 iface_is_bond(struct lldpd
*cfg
, const char *name
)
249 memset(&ifr
, 0, sizeof(ifr
));
250 memset(&ifb
, 0, sizeof(ifb
));
251 strlcpy(ifr
.ifr_name
, name
, sizeof(ifr
.ifr_name
));
252 ifr
.ifr_data
= (char *)&ifb
;
253 if (ioctl(cfg
->g_sock
, SIOCBONDINFOQUERY
, &ifr
) >= 0)
259 iface_is_bond_slave(struct lldpd
*cfg
, const char *slave
, const char *master
,
265 memset(&ifr
, 0, sizeof(ifr
));
266 memset(&ifb
, 0, sizeof(ifb
));
267 strlcpy(ifr
.ifr_name
, master
, sizeof(ifr
.ifr_name
));
268 ifr
.ifr_data
= (char *)&ifb
;
269 if (ioctl(cfg
->g_sock
, SIOCBONDINFOQUERY
, &ifr
) >= 0) {
270 while (ifb
.num_slaves
--) {
271 memset(&ifr
, 0, sizeof(ifr
));
272 memset(&ifs
, 0, sizeof(ifs
));
273 strlcpy(ifr
.ifr_name
, master
, sizeof(ifr
.ifr_name
));
274 ifr
.ifr_data
= (char *)&ifs
;
275 ifs
.slave_id
= ifb
.num_slaves
;
276 if ((ioctl(cfg
->g_sock
, SIOCBONDSLAVEINFOQUERY
, &ifr
) >= 0) &&
277 (strncmp(ifs
.slave_name
, slave
, sizeof(ifs
.slave_name
)) == 0)) {
288 iface_is_enslaved(struct lldpd
*cfg
, const char *name
)
290 struct ifaddrs
*ifap
, *ifa
;
293 if (getifaddrs(&ifap
) != 0) {
294 LLOG_WARN("unable to get interface list");
297 for (ifa
= ifap
; ifa
!= NULL
; ifa
= ifa
->ifa_next
) {
298 if (iface_is_bond_slave(cfg
, name
, ifa
->ifa_name
, NULL
)) {
299 master
= if_nametoindex(ifa
->ifa_name
);
309 iface_get_permanent_mac(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
)
311 int master
, f
, state
= 0;
313 const char *slaveif
= "Slave Interface: ";
314 const char *hwaddr
= "Permanent HW addr: ";
315 u_int8_t mac
[ETHER_ADDR_LEN
];
317 char path
[SYSFS_PATH_MAX
];
319 if ((master
= iface_is_enslaved(cfg
, hardware
->h_ifname
)) == -1)
321 /* We have a bond, we need to query it to get real MAC addresses */
322 if ((if_indextoname(master
, bond
)) == NULL
) {
323 LLOG_WARNX("unable to get bond name");
327 if (snprintf(path
, SYSFS_PATH_MAX
, "/proc/net/bonding/%s",
328 bond
) >= SYSFS_PATH_MAX
) {
329 LLOG_WARNX("path truncated");
332 if ((f
= priv_open(path
)) < 0) {
333 if (snprintf(path
, SYSFS_PATH_MAX
, "/proc/self/net/bonding/%s",
334 bond
) >= SYSFS_PATH_MAX
) {
335 LLOG_WARNX("path truncated");
341 LLOG_WARNX("unable to find %s in /proc/net/bonding or /proc/self/net/bonding",
345 if ((netbond
= fdopen(f
, "r")) == NULL
) {
346 LLOG_WARN("unable to read stream from %s", path
);
351 We parse the file to search "Slave Interface: ". If found, go to
354 We parse the file to search "Permanent HW addr: ". If found, we get
357 while (fgets(line
, sizeof(line
), netbond
)) {
360 if (strncmp(line
, slaveif
, strlen(slaveif
)) == 0) {
361 if (line
[strlen(line
)-1] == '\n')
362 line
[strlen(line
)-1] = '\0';
363 if (strncmp(hardware
->h_ifname
,
364 line
+ strlen(slaveif
),
365 sizeof(hardware
->h_ifname
)) == 0)
370 if (strncmp(line
, hwaddr
, strlen(hwaddr
)) == 0) {
371 if (line
[strlen(line
)-1] == '\n')
372 line
[strlen(line
)-1] = '\0';
373 if (sscanf(line
+ strlen(hwaddr
),
374 "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
375 &mac
[0], &mac
[1], &mac
[2],
376 &mac
[3], &mac
[4], &mac
[5]) !=
378 LLOG_WARN("unable to parse %s",
379 line
+ strlen(hwaddr
));
383 memcpy(hardware
->h_lladdr
, mac
,
391 LLOG_WARNX("unable to find real mac address for %s",
396 /* Generic minimal checks to handle a given interface. */
398 iface_minimal_checks(struct lldpd
*cfg
, struct ifaddrs
*ifa
)
400 struct sockaddr_ll sdl
;
402 struct ethtool_drvinfo ethc
;
403 const char * const *rif
;
405 /* White-list some drivers */
406 const char * const regular_interfaces
[] = {
412 int is_bridge
= iface_is_bridge(cfg
, ifa
->ifa_name
);
414 if (!(LOCAL_CHASSIS(cfg
)->c_cap_enabled
& LLDP_CAP_BRIDGE
) &&
416 LOCAL_CHASSIS(cfg
)->c_cap_enabled
|= LLDP_CAP_BRIDGE
;
420 if (!(LOCAL_CHASSIS(cfg
)->c_cap_enabled
& LLDP_CAP_WLAN
) &&
421 iface_is_wireless(cfg
, ifa
->ifa_name
))
422 LOCAL_CHASSIS(cfg
)->c_cap_enabled
|= LLDP_CAP_WLAN
;
424 /* First, check if this interface has already been handled */
428 if (ifa
->ifa_addr
== NULL
||
429 ifa
->ifa_addr
->sa_family
!= PF_PACKET
)
432 memcpy(&sdl
, ifa
->ifa_addr
, sizeof(struct sockaddr_ll
));
433 if (sdl
.sll_hatype
!= ARPHRD_ETHER
|| !sdl
.sll_halen
)
436 /* We request that the interface is able to do either multicast
437 * or broadcast to be able to send discovery frames. */
438 if (!(ifa
->ifa_flags
& (IFF_MULTICAST
|IFF_BROADCAST
)))
441 /* Check if the driver is whitelisted */
442 memset(&ifr
, 0, sizeof(ifr
));
443 strcpy(ifr
.ifr_name
, ifa
->ifa_name
);
444 memset(ðc
, 0, sizeof(ethc
));
445 ifr
.ifr_data
= (caddr_t
) ðc
;
446 ethc
.cmd
= ETHTOOL_GDRVINFO
;
447 if (ioctl(cfg
->g_sock
, SIOCETHTOOL
, &ifr
) == 0) {
448 for (rif
= regular_interfaces
; *rif
; rif
++) {
449 if (strcmp(ethc
.driver
, *rif
) == 0) {
456 /* Check queue len. If no queue, this usually means that this
457 is not a "real" interface. */
458 memset(&ifr
, 0, sizeof(ifr
));
459 strcpy(ifr
.ifr_name
, ifa
->ifa_name
);
460 if ((ioctl(cfg
->g_sock
, SIOCGIFTXQLEN
, &ifr
) < 0) || !ifr
.ifr_qlen
)
463 /* Don't handle bond and VLAN, nor bridge */
464 if ((iface_is_vlan(cfg
, ifa
->ifa_name
)) ||
465 (iface_is_bond(cfg
, ifa
->ifa_name
)) ||
473 iface_set_filter(const char *name
, int fd
)
475 struct sock_fprog prog
;
476 memset(&prog
, 0, sizeof(struct sock_fprog
));
477 prog
.filter
= lldpd_filter_f
;
478 prog
.len
= sizeof(lldpd_filter_f
) / sizeof(struct sock_filter
);
480 if (setsockopt(fd
, SOL_SOCKET
, SO_ATTACH_FILTER
,
481 &prog
, sizeof(prog
)) < 0) {
482 LLOG_WARN("unable to change filter for %s", name
);
488 /* Fill up port name and description */
490 iface_port_name_desc(struct lldpd_hardware
*hardware
)
492 struct lldpd_port
*port
= &hardware
->h_lport
;
493 char buffer
[256]; /* 256 = IFALIASZ */
494 char path
[SYSFS_PATH_MAX
];
497 /* There are two cases:
499 1. We have a kernel recent enough to support ifAlias
500 _and_ a non empty ifAlias, then we will use it for
501 description and use ifname for port ID.
503 2. Otherwise, we will use the MAC address as ID and the
504 port name in description.
507 if ((snprintf(path
, SYSFS_PATH_MAX
,
508 SYSFS_CLASS_NET
"%s/ifalias", hardware
->h_ifname
)) >= SYSFS_PATH_MAX
)
509 LLOG_WARNX("path truncated");
510 memset(buffer
, 0, sizeof(buffer
));
511 if (((f
= priv_open(path
)) < 0) || (read(f
, buffer
, sizeof(buffer
)-1) < 1)) {
512 /* Case 2: MAC address and port name */
514 port
->p_id_subtype
= LLDP_PORTID_SUBTYPE_LLADDR
;
516 calloc(1, sizeof(hardware
->h_lladdr
))) == NULL
)
518 memcpy(port
->p_id
, hardware
->h_lladdr
,
519 sizeof(hardware
->h_lladdr
));
520 port
->p_id_len
= sizeof(hardware
->h_lladdr
);
521 port
->p_descr
= strdup(hardware
->h_ifname
);
524 /* Case 1: port name and port description */
526 port
->p_id_subtype
= LLDP_PORTID_SUBTYPE_IFNAME
;
527 port
->p_id_len
= strlen(hardware
->h_ifname
);
529 calloc(1, port
->p_id_len
)) == NULL
)
531 memcpy(port
->p_id
, hardware
->h_ifname
, port
->p_id_len
);
532 if (buffer
[strlen(buffer
) - 1] == '\n')
533 buffer
[strlen(buffer
) - 1] = '\0';
534 port
->p_descr
= strdup(buffer
);
537 /* Fill up MAC/PHY for a given hardware port */
539 iface_macphy(struct lldpd_hardware
*hardware
)
542 struct ethtool_cmd ethc
;
543 struct lldpd_port
*port
= &hardware
->h_lport
;
545 int advertised_ethtool_to_rfc3636
[][2] = {
546 {ADVERTISED_10baseT_Half
, LLDP_DOT3_LINK_AUTONEG_10BASE_T
},
547 {ADVERTISED_10baseT_Full
, LLDP_DOT3_LINK_AUTONEG_10BASET_FD
},
548 {ADVERTISED_100baseT_Half
, LLDP_DOT3_LINK_AUTONEG_100BASE_TX
},
549 {ADVERTISED_100baseT_Full
, LLDP_DOT3_LINK_AUTONEG_100BASE_TXFD
},
550 {ADVERTISED_1000baseT_Half
, LLDP_DOT3_LINK_AUTONEG_1000BASE_T
},
551 {ADVERTISED_1000baseT_Full
, LLDP_DOT3_LINK_AUTONEG_1000BASE_TFD
},
552 {ADVERTISED_10000baseT_Full
, LLDP_DOT3_LINK_AUTONEG_OTHER
},
553 {ADVERTISED_Pause
, LLDP_DOT3_LINK_AUTONEG_FDX_PAUSE
},
554 {ADVERTISED_Asym_Pause
, LLDP_DOT3_LINK_AUTONEG_FDX_APAUSE
},
555 {ADVERTISED_2500baseX_Full
, LLDP_DOT3_LINK_AUTONEG_OTHER
},
558 if (priv_ethtool(hardware
->h_ifname
, ðc
) == 0) {
559 port
->p_macphy
.autoneg_support
= (ethc
.supported
& SUPPORTED_Autoneg
) ? 1 : 0;
560 port
->p_macphy
.autoneg_enabled
= (ethc
.autoneg
== AUTONEG_DISABLE
) ? 0 : 1;
561 for (j
=0; advertised_ethtool_to_rfc3636
[j
][0]; j
++) {
562 if (ethc
.advertising
& advertised_ethtool_to_rfc3636
[j
][0])
563 port
->p_macphy
.autoneg_advertised
|=
564 advertised_ethtool_to_rfc3636
[j
][1];
566 switch (ethc
.speed
) {
568 port
->p_macphy
.mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
569 LLDP_DOT3_MAU_10BASETFD
: LLDP_DOT3_MAU_10BASETHD
;
570 if (ethc
.port
== PORT_BNC
) port
->p_macphy
.mau_type
= LLDP_DOT3_MAU_10BASE2
;
571 if (ethc
.port
== PORT_FIBRE
)
572 port
->p_macphy
.mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
573 LLDP_DOT3_MAU_10BASEFLDF
: LLDP_DOT3_MAU_10BASEFLHD
;
576 port
->p_macphy
.mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
577 LLDP_DOT3_MAU_100BASETXFD
: LLDP_DOT3_MAU_100BASETXHD
;
578 if (ethc
.port
== PORT_BNC
)
579 port
->p_macphy
.mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
580 LLDP_DOT3_MAU_100BASET2DF
: LLDP_DOT3_MAU_100BASET2HD
;
581 if (ethc
.port
== PORT_FIBRE
)
582 port
->p_macphy
.mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
583 LLDP_DOT3_MAU_100BASEFXFD
: LLDP_DOT3_MAU_100BASEFXHD
;
586 port
->p_macphy
.mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
587 LLDP_DOT3_MAU_1000BASETFD
: LLDP_DOT3_MAU_1000BASETHD
;
588 if (ethc
.port
== PORT_FIBRE
)
589 port
->p_macphy
.mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
590 LLDP_DOT3_MAU_1000BASEXFD
: LLDP_DOT3_MAU_1000BASEXHD
;
593 port
->p_macphy
.mau_type
= (ethc
.port
== PORT_FIBRE
) ? \
594 LLDP_DOT3_MAU_10GIGBASEX
: LLDP_DOT3_MAU_10GIGBASER
;
597 if (ethc
.port
== PORT_AUI
) port
->p_macphy
.mau_type
= LLDP_DOT3_MAU_AUI
;
603 iface_mtu(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
)
608 memset(&ifr
, 0, sizeof(ifr
));
609 strlcpy(ifr
.ifr_name
, hardware
->h_ifname
, sizeof(ifr
.ifr_name
));
610 if (ioctl(cfg
->g_sock
, SIOCGIFMTU
, (char*)&ifr
) == -1) {
611 LLOG_WARN("unable to get MTU of %s, using 1500", hardware
->h_ifname
);
612 hardware
->h_mtu
= 1500;
614 hardware
->h_mtu
= ifr
.ifr_mtu
;
618 iface_multicast(struct lldpd
*cfg
, const char *name
, int remove
)
622 for (i
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
623 if (!cfg
->g_protocols
[i
].enabled
) continue;
624 if ((rc
= priv_iface_multicast(name
,
625 cfg
->g_protocols
[i
].mac
, !remove
)) != 0) {
628 LLOG_INFO("unable to %s %s address to multicast filter for %s",
629 (remove
)?"delete":"add",
630 cfg
->g_protocols
[i
].name
,
637 iface_eth_init(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
)
641 if ((fd
= priv_iface_init(hardware
->h_ifname
)) == -1)
643 hardware
->h_sendfd
= fd
; /* Send */
646 if ((status
= iface_set_filter(hardware
->h_ifname
, fd
)) != 0) {
651 iface_multicast(cfg
, hardware
->h_ifname
, 0);
653 levent_hardware_add_fd(hardware
, fd
); /* Receive */
654 LLOG_DEBUG("interface %s initialized (fd=%d)", hardware
->h_ifname
,
660 iface_eth_send(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
,
661 char *buffer
, size_t size
)
663 return write(hardware
->h_sendfd
,
668 iface_eth_recv(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
,
669 int fd
, char *buffer
, size_t size
)
672 struct sockaddr_ll from
;
675 fromlen
= sizeof(from
);
676 if ((n
= recvfrom(fd
,
679 (struct sockaddr
*)&from
,
681 LLOG_WARN("error while receiving frame on %s",
683 hardware
->h_rx_discarded_cnt
++;
686 if (from
.sll_pkttype
== PACKET_OUTGOING
)
692 iface_eth_close(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
)
694 iface_multicast(cfg
, hardware
->h_ifname
, 1);
699 lldpd_ifh_eth(struct lldpd
*cfg
, struct ifaddrs
*ifap
)
702 struct lldpd_hardware
*hardware
;
704 for (ifa
= ifap
; ifa
!= NULL
; ifa
= ifa
->ifa_next
) {
705 if (!iface_minimal_checks(cfg
, ifa
))
708 if ((hardware
= lldpd_get_hardware(cfg
,
710 if_nametoindex(ifa
->ifa_name
),
711 ð_ops
)) == NULL
) {
712 if ((hardware
= lldpd_alloc_hardware(cfg
,
713 ifa
->ifa_name
)) == NULL
) {
714 LLOG_WARNX("Unable to allocate space for %s",
718 if (iface_eth_init(cfg
, hardware
) != 0) {
719 LLOG_WARN("unable to initialize %s", hardware
->h_ifname
);
720 lldpd_hardware_cleanup(cfg
, hardware
);
723 hardware
->h_ops
= ð_ops
;
724 hardware
->h_ifindex
= if_nametoindex(ifa
->ifa_name
);
725 TAILQ_INSERT_TAIL(&cfg
->g_hardware
, hardware
, h_entries
);
727 if (hardware
->h_flags
) continue; /* Already seen this time */
728 lldpd_port_cleanup(&hardware
->h_lport
, 0);
731 hardware
->h_flags
= ifa
->ifa_flags
; /* Should be non-zero */
732 ifa
->ifa_flags
= 0; /* Future handlers
737 /* Get local address */
738 memcpy(&hardware
->h_lladdr
,
739 (u_int8_t
*)((u_int8_t
*)ifa
->ifa_addr
+
740 offsetof(struct sockaddr_ll
, sll_addr
)),
741 sizeof(hardware
->h_lladdr
));
743 /* Fill information about port */
744 iface_port_name_desc(hardware
);
746 /* Fill additional info */
747 iface_macphy(hardware
);
748 iface_mtu(cfg
, hardware
);
753 lldpd_ifh_whitelist(struct lldpd
*cfg
, struct ifaddrs
*ifap
)
757 if (!cfg
->g_interfaces
)
760 for (ifa
= ifap
; ifa
!= NULL
; ifa
= ifa
->ifa_next
) {
761 if (ifa
->ifa_flags
== 0) continue; /* Already handled by someone else */
762 if (!pattern_match(ifa
->ifa_name
, cfg
->g_interfaces
, 0)) {
763 /* This interface was not found. We flag it. */
764 LLOG_DEBUG("blacklist %s", ifa
->ifa_name
);
771 iface_bond_init(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
)
773 char *mastername
= (char *)hardware
->h_data
; /* Master name */
777 if (!mastername
) return -1;
779 /* First, we get a socket to the raw physical interface */
780 if ((fd
= priv_iface_init(hardware
->h_ifname
)) == -1)
782 hardware
->h_sendfd
= fd
;
783 levent_hardware_add_fd(hardware
, fd
);
784 if ((status
= iface_set_filter(hardware
->h_ifname
, fd
)) != 0) {
788 iface_multicast(cfg
, hardware
->h_ifname
, 0);
790 /* Then, we open a raw interface for the master */
791 if ((fd
= priv_iface_init(mastername
)) == -1) {
792 close(hardware
->h_sendfd
);
795 if ((status
= iface_set_filter(mastername
, fd
)) != 0) {
796 close(hardware
->h_sendfd
);
800 /* With bonding and older kernels (< 2.6.27) we need to listen
801 * to bond device. We use setsockopt() PACKET_ORIGDEV to get
802 * physical device instead of bond device (works with >=
804 if (setsockopt(fd
, SOL_PACKET
,
805 PACKET_ORIGDEV
, &un
, sizeof(un
)) == -1) {
806 LLOG_DEBUG("[priv]: unable to setsockopt for master bonding device of %s. "
807 "You will get inaccurate results",
810 iface_multicast(cfg
, mastername
, 0);
812 levent_hardware_add_fd(hardware
, fd
);
813 LLOG_DEBUG("interface %s initialized (fd=%d,master=%s[%d])",
821 iface_bond_send(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
,
822 char *buffer
, size_t size
)
824 /* With bonds, we have duplicate MAC address on different physical
825 * interfaces. We need to alter the source MAC address when we send on
826 * an inactive slave. */
827 char *master
= (char*)hardware
->h_data
;
829 if (!iface_is_bond_slave(cfg
, hardware
->h_ifname
, master
, &active
)) {
830 LLOG_WARNX("%s seems to not be enslaved anymore?",
835 /* We need to modify the source MAC address */
836 if (size
< 2 * ETH_ALEN
) {
837 LLOG_WARNX("packet to send on %s is too small!",
841 memset(buffer
+ ETH_ALEN
, 0, ETH_ALEN
);
843 return write(hardware
->h_sendfd
,
848 iface_bond_recv(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
,
849 int fd
, char *buffer
, size_t size
)
852 struct sockaddr_ll from
;
855 fromlen
= sizeof(from
);
856 if ((n
= recvfrom(fd
, buffer
, size
, 0,
857 (struct sockaddr
*)&from
,
859 LLOG_WARN("error while receiving frame on %s",
861 hardware
->h_rx_discarded_cnt
++;
864 if (from
.sll_pkttype
== PACKET_OUTGOING
)
866 if (fd
== hardware
->h_sendfd
)
867 /* We received this on the physical interface. */
869 /* We received this on the bonding interface. Is it really for us? */
870 if (from
.sll_ifindex
== hardware
->h_ifindex
)
873 if (from
.sll_ifindex
== if_nametoindex((char*)hardware
->h_data
))
874 /* We don't know from which physical interface it comes (kernel
875 * < 2.6.24). In doubt, this is for us. */
877 return -1; /* Not for us */
881 iface_bond_close(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
)
883 iface_multicast(cfg
, hardware
->h_ifname
, 1);
884 iface_multicast(cfg
, (char*)hardware
->h_data
, 1);
885 free(hardware
->h_data
);
890 lldpd_ifh_bond(struct lldpd
*cfg
, struct ifaddrs
*ifap
)
893 struct lldpd_hardware
*hardware
;
895 for (ifa
= ifap
; ifa
!= NULL
; ifa
= ifa
->ifa_next
) {
896 if (!iface_minimal_checks(cfg
, ifa
))
898 if ((master
= iface_is_enslaved(cfg
, ifa
->ifa_name
)) == -1)
901 if ((hardware
= lldpd_get_hardware(cfg
,
903 if_nametoindex(ifa
->ifa_name
),
904 &bond_ops
)) == NULL
) {
905 if ((hardware
= lldpd_alloc_hardware(cfg
,
906 ifa
->ifa_name
)) == NULL
) {
907 LLOG_WARNX("Unable to allocate space for %s",
911 hardware
->h_data
= (char *)calloc(1, IFNAMSIZ
);
912 if_indextoname(master
, hardware
->h_data
);
913 if (iface_bond_init(cfg
, hardware
) != 0) {
914 LLOG_WARN("unable to initialize %s",
916 lldpd_hardware_cleanup(cfg
, hardware
);
919 hardware
->h_ops
= &bond_ops
;
920 hardware
->h_ifindex
= if_nametoindex(ifa
->ifa_name
);
921 TAILQ_INSERT_TAIL(&cfg
->g_hardware
, hardware
, h_entries
);
923 if (hardware
->h_flags
) continue; /* Already seen this time */
924 memset(hardware
->h_data
, 0, IFNAMSIZ
);
925 if_indextoname(master
, hardware
->h_data
);
926 lldpd_port_cleanup(&hardware
->h_lport
, 0);
929 hardware
->h_flags
= ifa
->ifa_flags
;
932 /* Get local address */
933 iface_get_permanent_mac(cfg
, hardware
);
935 /* Fill information about port */
936 iface_port_name_desc(hardware
);
938 /* Fill additional info */
940 hardware
->h_lport
.p_aggregid
= master
;
942 iface_macphy(hardware
);
943 iface_mtu(cfg
, hardware
);
949 iface_append_vlan(struct lldpd
*cfg
,
950 struct lldpd_hardware
*hardware
, struct ifaddrs
*ifa
)
952 struct lldpd_port
*port
= &hardware
->h_lport
;
953 struct lldpd_vlan
*vlan
;
954 struct vlan_ioctl_args ifv
;
956 /* Check if the VLAN is already here. */
957 TAILQ_FOREACH(vlan
, &port
->p_vlans
, v_entries
)
958 if (strncmp(ifa
->ifa_name
, vlan
->v_name
, IFNAMSIZ
) == 0)
960 if ((vlan
= (struct lldpd_vlan
*)
961 calloc(1, sizeof(struct lldpd_vlan
))) == NULL
)
963 if ((vlan
->v_name
= strdup(ifa
->ifa_name
)) == NULL
) {
967 memset(&ifv
, 0, sizeof(ifv
));
968 ifv
.cmd
= GET_VLAN_VID_CMD
;
969 strlcpy(ifv
.device1
, ifa
->ifa_name
, sizeof(ifv
.device1
));
970 if (ioctl(cfg
->g_sock
, SIOCGIFVLAN
, &ifv
) < 0) {
971 /* Dunno what happened */
976 vlan
->v_vid
= ifv
.u
.VID
;
977 TAILQ_INSERT_TAIL(&port
->p_vlans
, vlan
, v_entries
);
981 lldpd_ifh_vlan(struct lldpd
*cfg
, struct ifaddrs
*ifap
)
984 struct vlan_ioctl_args ifv
;
985 struct lldpd_hardware
*hardware
;
987 for (ifa
= ifap
; ifa
!= NULL
; ifa
= ifa
->ifa_next
) {
990 if (!iface_is_vlan(cfg
, ifa
->ifa_name
))
993 /* We need to find the physical interfaces of this
994 vlan, through bonds and bridges. */
995 memset(&ifv
, 0, sizeof(ifv
));
996 ifv
.cmd
= GET_VLAN_REALDEV_NAME_CMD
;
997 strlcpy(ifv
.device1
, ifa
->ifa_name
, sizeof(ifv
.device1
));
998 if (ioctl(cfg
->g_sock
, SIOCGIFVLAN
, &ifv
) >= 0) {
1000 1. we get a real device
1004 if ((hardware
= lldpd_get_hardware(cfg
,
1006 if_nametoindex(ifv
.u
.device2
),
1008 if (iface_is_bond(cfg
, ifv
.u
.device2
)) {
1009 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
,
1011 if (iface_is_bond_slave(cfg
,
1013 ifv
.u
.device2
, NULL
))
1014 iface_append_vlan(cfg
,
1016 } else if (iface_is_bridge(cfg
, ifv
.u
.device2
)) {
1017 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
,
1019 if (iface_is_bridged_to(cfg
,
1022 iface_append_vlan(cfg
,
1025 } else iface_append_vlan(cfg
,
1032 #ifndef IN_IS_ADDR_LOOPBACK
1033 #define IN_IS_ADDR_LOOPBACK(a) ((a)->s_addr == htonl(INADDR_LOOPBACK))
1035 #ifndef IN_IS_ADDR_GLOBAL
1036 #define IN_IS_ADDR_GLOBAL(a) (!IN_IS_ADDR_LOOPBACK(a))
1038 #ifndef IN6_IS_ADDR_GLOBAL
1039 #define IN6_IS_ADDR_GLOBAL(a) (!IN6_IS_ADDR_LOOPBACK(a) && \
1040 !IN6_IS_ADDR_LINKLOCAL(a))
1043 /* Find a management address in all available interfaces, even those that were
1044 already handled. This is a special interface handler because it does not
1045 really handle interface related information (management address is attached
1046 to the local chassis). */
1048 lldpd_ifh_mgmt(struct lldpd
*cfg
, struct ifaddrs
*ifap
)
1050 struct ifaddrs
*ifa
;
1051 char addrstrbuf
[INET6_ADDRSTRLEN
];
1052 struct lldpd_mgmt
*mgmt
;
1054 size_t sin_addr_size
;
1056 int allnegative
= 0;
1058 lldpd_chassis_mgmt_cleanup(LOCAL_CHASSIS(cfg
));
1060 /* Is the pattern provided all negative? */
1061 if (cfg
->g_mgmt_pattern
== NULL
) allnegative
= 1;
1062 else if (cfg
->g_mgmt_pattern
[0] == '!') {
1063 /* If each comma is followed by '!', its an all
1065 char *sep
= cfg
->g_mgmt_pattern
;
1066 while ((sep
= strchr(sep
, ',')) &&
1068 if (sep
== NULL
) allnegative
= 1;
1071 /* Find management addresses */
1072 for (af
= LLDPD_AF_UNSPEC
+ 1; af
!= LLDPD_AF_LAST
; af
++) {
1073 /* We only take one of each address family, unless a
1074 pattern is provided and is not all negative. For
1075 example !*:*,!10.* will only blacklist
1076 addresses. We will pick the first IPv4 address not
1080 ifa
= ifa
->ifa_next
) {
1081 if (ifa
->ifa_addr
== NULL
)
1083 if (ifa
->ifa_addr
->sa_family
!= lldpd_af(af
))
1088 sin_addr_ptr
= &((struct sockaddr_in
*)ifa
->ifa_addr
)->sin_addr
;
1089 sin_addr_size
= sizeof(struct in_addr
);
1090 if (!IN_IS_ADDR_GLOBAL((struct in_addr
*)sin_addr_ptr
))
1094 sin_addr_ptr
= &((struct sockaddr_in6
*)ifa
->ifa_addr
)->sin6_addr
;
1095 sin_addr_size
= sizeof(struct in6_addr
);
1096 if (!IN6_IS_ADDR_GLOBAL((struct in6_addr
*)sin_addr_ptr
))
1103 if (inet_ntop(lldpd_af(af
), sin_addr_ptr
,
1104 addrstrbuf
, sizeof(addrstrbuf
)) == NULL
) {
1105 LLOG_WARN("unable to convert IP address to a string");
1108 if (cfg
->g_mgmt_pattern
== NULL
||
1109 pattern_match(addrstrbuf
, cfg
->g_mgmt_pattern
, allnegative
)) {
1110 mgmt
= lldpd_alloc_mgmt(af
, sin_addr_ptr
, sin_addr_size
,
1111 if_nametoindex(ifa
->ifa_name
));
1113 assert(errno
== ENOMEM
); /* anything else is a bug */
1114 LLOG_WARN("out of memory error");
1117 TAILQ_INSERT_TAIL(&LOCAL_CHASSIS(cfg
)->c_mgmt
, mgmt
, m_entries
);
1119 /* Don't take additional address if the pattern is all negative. */
1120 if (allnegative
) break;
1127 /* Fill out chassis ID if not already done. This handler is special
1128 because we will only handle interfaces that are already handled. */
1130 lldpd_ifh_chassis(struct lldpd
*cfg
, struct ifaddrs
*ifap
)
1132 struct ifaddrs
*ifa
;
1133 struct lldpd_hardware
*hardware
;
1136 if (LOCAL_CHASSIS(cfg
)->c_id
!= NULL
&&
1137 LOCAL_CHASSIS(cfg
)->c_id_subtype
== LLDP_CHASSISID_SUBTYPE_LLADDR
)
1138 return; /* We already have one */
1140 for (ifa
= ifap
; ifa
!= NULL
; ifa
= ifa
->ifa_next
) {
1141 if (ifa
->ifa_flags
) continue;
1142 if (cfg
->g_cid_pattern
&&
1143 !pattern_match(ifa
->ifa_name
, cfg
->g_cid_pattern
, 0)) continue;
1145 if ((hardware
= lldpd_get_hardware(cfg
,
1147 if_nametoindex(ifa
->ifa_name
),
1149 /* That's odd. Let's skip. */
1152 name
= malloc(sizeof(hardware
->h_lladdr
));
1154 LLOG_WARN("Not enough memory for chassis ID");
1157 free(LOCAL_CHASSIS(cfg
)->c_id
);
1158 memcpy(name
, hardware
->h_lladdr
, sizeof(hardware
->h_lladdr
));
1159 LOCAL_CHASSIS(cfg
)->c_id
= name
;
1160 LOCAL_CHASSIS(cfg
)->c_id_len
= sizeof(hardware
->h_lladdr
);
1161 LOCAL_CHASSIS(cfg
)->c_id_subtype
= LLDP_CHASSISID_SUBTYPE_LLADDR
;
1166 struct lldpd_ops eth_ops
= {
1167 .send
= iface_eth_send
,
1168 .recv
= iface_eth_recv
,
1169 .cleanup
= iface_eth_close
,
1171 struct lldpd_ops bond_ops
= {
1172 .send
= iface_bond_send
,
1173 .recv
= iface_bond_recv
,
1174 .cleanup
= iface_bond_close
,