1 /* -*- mode: c; c-file-style: "openbsd" -*- */
3 * Copyright (c) 2012 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.
25 #include <arpa/inet.h>
27 /* Generic ethernet interface initialization */
29 * Enable multicast on the given interface.
32 interfaces_setup_multicast(struct lldpd
*cfg
, const char *name
,
37 for (i
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
38 if (!cfg
->g_protocols
[i
].enabled
) continue;
39 if ((rc
= priv_iface_multicast(name
,
40 cfg
->g_protocols
[i
].mac
, !remove
)) != 0) {
43 log_debug("interfaces",
44 "unable to %s %s address to multicast filter for %s (%s)",
45 (remove
)?"delete":"add",
46 cfg
->g_protocols
[i
].name
,
55 * @param iff interface to be freed
58 interfaces_free_device(struct interfaces_device
*iff
)
69 * Free a list of interfaces.
71 * @param ifs list of interfaces to be freed
74 interfaces_free_devices(struct interfaces_device_list
*ifs
)
76 struct interfaces_device
*iff
, *iff_next
;
78 for (iff
= TAILQ_FIRST(ifs
);
81 iff_next
= TAILQ_NEXT(iff
, next
);
82 interfaces_free_device(iff
);
90 * @param ifaddr Address to be freed
93 interfaces_free_address(struct interfaces_address
*ifaddr
)
99 * Free a list of addresses.
101 * @param ifaddrs list of addresses
104 interfaces_free_addresses(struct interfaces_address_list
*ifaddrs
)
106 struct interfaces_address
*ifa
, *ifa_next
;
107 if (!ifaddrs
) return;
108 for (ifa
= TAILQ_FIRST(ifaddrs
);
111 ifa_next
= TAILQ_NEXT(ifa
, next
);
112 interfaces_free_address(ifa
);
118 * Find the appropriate interface from the name.
120 * @param interfaces List of available interfaces
121 * @param device Name of the device we search for
122 * @return The interface or NULL if not found
124 struct interfaces_device
*
125 interfaces_nametointerface(struct interfaces_device_list
*interfaces
,
128 struct interfaces_device
*iface
;
129 TAILQ_FOREACH(iface
, interfaces
, next
) {
130 if (!strncmp(iface
->name
, device
, IFNAMSIZ
))
133 log_debug("interfaces", "cannot get interface for index %s",
139 * Find the appropriate interface from the index.
141 * @param interfaces List of available interfaces
142 * @param index Index of the device we search for
143 * @return The interface or NULL if not found
145 struct interfaces_device
*
146 interfaces_indextointerface(struct interfaces_device_list
*interfaces
,
149 struct interfaces_device
*iface
;
150 TAILQ_FOREACH(iface
, interfaces
, next
) {
151 if (iface
->index
== index
)
154 log_debug("interfaces", "cannot get interface for index %d",
160 interfaces_helper_whitelist(struct lldpd
*cfg
,
161 struct interfaces_device_list
*interfaces
)
163 struct interfaces_device
*iface
;
165 if (!cfg
->g_config
.c_iface_pattern
)
168 TAILQ_FOREACH(iface
, interfaces
, next
) {
169 int m
= pattern_match(iface
->name
, cfg
->g_config
.c_iface_pattern
, 0);
172 log_debug("interfaces", "blacklist %s", iface
->name
);
176 log_debug("interfaces", "whitelist %s (consider it as a physical interface)",
178 iface
->type
|= IFACE_PHYSICAL_T
;
186 iface_append_vlan(struct lldpd
*cfg
,
187 struct interfaces_device
*vlan
,
188 struct interfaces_device
*lower
)
190 struct lldpd_hardware
*hardware
=
191 lldpd_get_hardware(cfg
, lower
->name
, lower
->index
, NULL
);
192 struct lldpd_port
*port
;
193 struct lldpd_vlan
*v
;
195 if (hardware
== NULL
) {
196 log_debug("interfaces",
197 "cannot find real interface %s for VLAN %s",
198 lower
->name
, vlan
->name
);
202 /* Check if the VLAN is already here. */
203 port
= &hardware
->h_lport
;
204 TAILQ_FOREACH(v
, &port
->p_vlans
, v_entries
)
205 if (strncmp(vlan
->name
, v
->v_name
, IFNAMSIZ
) == 0)
207 if ((v
= (struct lldpd_vlan
*)
208 calloc(1, sizeof(struct lldpd_vlan
))) == NULL
)
210 if ((v
->v_name
= strdup(vlan
->name
)) == NULL
) {
214 v
->v_vid
= vlan
->vlanid
;
215 log_debug("interfaces", "append VLAN %s for %s",
218 TAILQ_INSERT_TAIL(&port
->p_vlans
, v
, v_entries
);
222 * Append VLAN to the lowest possible interface.
224 * @param vlan The VLAN interface (used to get VLAN ID).
225 * @param upper The upper interface we are currently examining.
226 * @param depth Depth of the stack (avoid infinite recursion)
228 * Initially, upper == vlan. This function will be called recursively.
231 iface_append_vlan_to_lower(struct lldpd
*cfg
,
232 struct interfaces_device_list
*interfaces
,
233 struct interfaces_device
*vlan
,
234 struct interfaces_device
*upper
,
238 log_debug("interfaces",
239 "maximum depth reached when applying VLAN %s (loop?)",
244 struct interfaces_device
*lower
;
245 log_debug("interfaces",
246 "looking to apply VLAN %s to physical interface behind %s",
247 vlan
->name
, upper
->name
);
249 /* Easy: check if we have a lower interface. */
251 log_debug("interfaces", "VLAN %s on lower interface %s",
252 vlan
->name
, upper
->name
);
253 iface_append_vlan_to_lower(cfg
,
260 /* Other easy case, we have a physical interface. */
261 if (upper
->type
& IFACE_PHYSICAL_T
) {
262 log_debug("interfaces", "VLAN %s on physical interface %s",
263 vlan
->name
, upper
->name
);
264 iface_append_vlan(cfg
, vlan
, upper
);
268 /* We can now search for interfaces that have our interface as an upper
270 TAILQ_FOREACH(lower
, interfaces
, next
) {
271 if (lower
->upper
!= upper
) continue;
272 log_debug("interfaces", "VLAN %s on lower interface %s",
273 vlan
->name
, upper
->name
);
274 iface_append_vlan_to_lower(cfg
,
275 interfaces
, vlan
, lower
, depth
);
280 interfaces_helper_vlan(struct lldpd
*cfg
,
281 struct interfaces_device_list
*interfaces
)
283 struct interfaces_device
*iface
;
285 TAILQ_FOREACH(iface
, interfaces
, next
) {
288 if (!(iface
->type
& IFACE_VLAN_T
))
291 /* We need to find the physical interfaces of this
292 vlan, through bonds and bridges. */
293 log_debug("interfaces", "search physical interface for VLAN interface %s",
295 iface_append_vlan_to_lower(cfg
, interfaces
,
301 /* Fill out chassis ID if not already done. Only physical interfaces are
304 interfaces_helper_chassis(struct lldpd
*cfg
,
305 struct interfaces_device_list
*interfaces
)
307 struct interfaces_device
*iface
;
308 struct lldpd_hardware
*hardware
;
311 LOCAL_CHASSIS(cfg
)->c_cap_enabled
&=
312 ~(LLDP_CAP_BRIDGE
| LLDP_CAP_WLAN
| LLDP_CAP_STATION
);
313 TAILQ_FOREACH(iface
, interfaces
, next
) {
314 if (iface
->type
& IFACE_BRIDGE_T
)
315 LOCAL_CHASSIS(cfg
)->c_cap_enabled
|= LLDP_CAP_BRIDGE
;
316 if (iface
->type
& IFACE_WIRELESS_T
)
317 LOCAL_CHASSIS(cfg
)->c_cap_enabled
|= LLDP_CAP_WLAN
;
319 if ((LOCAL_CHASSIS(cfg
)->c_cap_available
& LLDP_CAP_STATION
) &&
320 (LOCAL_CHASSIS(cfg
)->c_cap_enabled
== 0))
321 LOCAL_CHASSIS(cfg
)->c_cap_enabled
= LLDP_CAP_STATION
;
323 if (LOCAL_CHASSIS(cfg
)->c_id
!= NULL
&&
324 LOCAL_CHASSIS(cfg
)->c_id_subtype
== LLDP_CHASSISID_SUBTYPE_LLADDR
)
325 return; /* We already have one */
327 TAILQ_FOREACH(iface
, interfaces
, next
) {
328 if (!(iface
->type
& IFACE_PHYSICAL_T
)) continue;
329 if (cfg
->g_config
.c_cid_pattern
&&
330 !pattern_match(iface
->name
, cfg
->g_config
.c_cid_pattern
, 0)) continue;
332 if ((hardware
= lldpd_get_hardware(cfg
,
336 /* That's odd. Let's skip. */
339 name
= malloc(ETHER_ADDR_LEN
);
341 log_warn("interfaces", "not enough memory for chassis ID");
344 free(LOCAL_CHASSIS(cfg
)->c_id
);
345 memcpy(name
, hardware
->h_lladdr
, ETHER_ADDR_LEN
);
346 LOCAL_CHASSIS(cfg
)->c_id
= name
;
347 LOCAL_CHASSIS(cfg
)->c_id_len
= ETHER_ADDR_LEN
;
348 LOCAL_CHASSIS(cfg
)->c_id_subtype
= LLDP_CHASSISID_SUBTYPE_LLADDR
;
353 #undef IN_IS_ADDR_LOOPBACK
354 #define IN_IS_ADDR_LOOPBACK(a) ((a)->s_addr == htonl(INADDR_LOOPBACK))
355 #undef IN_IS_ADDR_ANY
356 #define IN_IS_ADDR_ANY(a) ((a)->s_addr == htonl(INADDR_ANY))
357 #undef IN_IS_ADDR_LINKLOCAL
358 #define IN_IS_ADDR_LINKLOCAL(a) (((a)->s_addr & htonl(0xffff0000)) == htonl(0xa9fe0000))
359 #undef IN_IS_ADDR_GLOBAL
360 #define IN_IS_ADDR_GLOBAL(a) (!IN_IS_ADDR_LOOPBACK(a) && !IN_IS_ADDR_ANY(a) && !IN_IS_ADDR_LINKLOCAL(a))
361 #undef IN6_IS_ADDR_GLOBAL
362 #define IN6_IS_ADDR_GLOBAL(a) \
363 (!IN6_IS_ADDR_LOOPBACK(a) && !IN6_IS_ADDR_LINKLOCAL(a))
365 /* Add management addresses for the given family. We only take one of each
366 address family, unless a pattern is provided and is not all negative. For
367 example !*:*,!10.* will only blacklist addresses. We will pick the first IPv4
368 address not matching 10.*.
371 interfaces_helper_mgmt_for_af(struct lldpd
*cfg
,
373 struct interfaces_address_list
*addrs
,
374 int global
, int allnegative
)
376 struct interfaces_address
*addr
;
377 struct lldpd_mgmt
*mgmt
;
378 char addrstrbuf
[INET6_ADDRSTRLEN
];
381 size_t sin_addr_size
;
383 TAILQ_FOREACH(addr
, addrs
, next
) {
384 if (addr
->address
.ss_family
!= lldpd_af(af
))
389 sin_addr_ptr
= &((struct sockaddr_in
*)&addr
->address
)->sin_addr
;
390 sin_addr_size
= sizeof(struct in_addr
);
392 if (!IN_IS_ADDR_GLOBAL((struct in_addr
*)sin_addr_ptr
))
395 if (!IN_IS_ADDR_LINKLOCAL((struct in_addr
*)sin_addr_ptr
))
400 sin_addr_ptr
= &((struct sockaddr_in6
*)&addr
->address
)->sin6_addr
;
401 sin_addr_size
= sizeof(struct in6_addr
);
403 if (!IN6_IS_ADDR_GLOBAL((struct in6_addr
*)sin_addr_ptr
))
406 if (!IN6_IS_ADDR_LINKLOCAL((struct in6_addr
*)sin_addr_ptr
))
414 if (inet_ntop(lldpd_af(af
), sin_addr_ptr
,
415 addrstrbuf
, sizeof(addrstrbuf
)) == NULL
) {
416 log_warn("interfaces", "unable to convert IP address to a string");
419 if (cfg
->g_config
.c_mgmt_pattern
== NULL
||
420 pattern_match(addrstrbuf
, cfg
->g_config
.c_mgmt_pattern
, allnegative
)) {
421 mgmt
= lldpd_alloc_mgmt(af
, sin_addr_ptr
, sin_addr_size
,
424 assert(errno
== ENOMEM
); /* anything else is a bug */
425 log_warn("interfaces", "out of memory error");
428 log_debug("interfaces", "add management address %s", addrstrbuf
);
429 TAILQ_INSERT_TAIL(&LOCAL_CHASSIS(cfg
)->c_mgmt
, mgmt
, m_entries
);
432 /* Don't take additional address if the pattern is all negative. */
433 if (allnegative
) break;
439 /* Find a management address in all available interfaces, even those that were
440 already handled. This is a special interface handler because it does not
441 really handle interface related information (management address is attached
442 to the local chassis). */
444 interfaces_helper_mgmt(struct lldpd
*cfg
,
445 struct interfaces_address_list
*addrs
)
449 const char *pattern
= cfg
->g_config
.c_mgmt_pattern
;
451 lldpd_chassis_mgmt_cleanup(LOCAL_CHASSIS(cfg
));
452 if (!cfg
->g_config
.c_mgmt_advertise
)
455 /* Is the pattern provided an actual IP address? */
456 if (pattern
&& strpbrk(pattern
, "!,*?") == NULL
) {
457 struct in6_addr addr
;
459 for (af
= LLDPD_AF_UNSPEC
+ 1;
460 af
!= LLDPD_AF_LAST
; af
++) {
462 case LLDPD_AF_IPV4
: addr_size
= sizeof(struct in_addr
); break;
463 case LLDPD_AF_IPV6
: addr_size
= sizeof(struct in6_addr
); break;
466 if (inet_pton(lldpd_af(af
), pattern
, &addr
) == 1)
469 if (af
== LLDPD_AF_LAST
) {
470 log_debug("interfaces",
471 "interface management pattern is an incorrect IP");
473 struct lldpd_mgmt
*mgmt
;
474 mgmt
= lldpd_alloc_mgmt(af
, &addr
, addr_size
, 0);
476 log_warn("interfaces", "out of memory error");
479 log_debug("interfaces", "add exact management address %s",
481 TAILQ_INSERT_TAIL(&LOCAL_CHASSIS(cfg
)->c_mgmt
, mgmt
, m_entries
);
486 /* Is the pattern provided all negative? */
487 if (pattern
== NULL
) allnegative
= 1;
488 else if (pattern
[0] == '!') {
489 /* If each comma is followed by '!', its an all
491 const char *sep
= pattern
;
492 while ((sep
= strchr(sep
, ',')) &&
494 if (sep
== NULL
) allnegative
= 1;
497 /* Find management addresses */
498 for (af
= LLDPD_AF_UNSPEC
+ 1; af
!= LLDPD_AF_LAST
; af
++) {
499 (void)(interfaces_helper_mgmt_for_af(cfg
, af
, addrs
, 1, allnegative
) ||
500 interfaces_helper_mgmt_for_af(cfg
, af
, addrs
, 0, allnegative
));
504 /* Fill up port name and description */
506 interfaces_helper_port_name_desc(struct lldpd
*cfg
,
507 struct lldpd_hardware
*hardware
,
508 struct interfaces_device
*iface
)
510 struct lldpd_port
*port
= &hardware
->h_lport
;
512 /* We need to set the portid to what the client configured.
513 This can be done from the CLI.
515 int has_alias
= (iface
->alias
!= NULL
&& strlen(iface
->alias
) != 0);
516 int portid_type
= cfg
->g_config
.c_lldp_portid_type
;
517 if (portid_type
== LLDP_PORTID_SUBTYPE_IFNAME
||
518 (portid_type
== LLDP_PORTID_SUBTYPE_UNKNOWN
&& has_alias
) ||
519 (portid_type
== LLDP_PORTID_SUBTYPE_LOCAL
&& has_alias
)) {
520 if (portid_type
!= LLDP_PORTID_SUBTYPE_LOCAL
) {
521 log_debug("interfaces", "use ifname for %s",
523 port
->p_id_subtype
= LLDP_PORTID_SUBTYPE_IFNAME
;
524 port
->p_id_len
= strlen(hardware
->h_ifname
);
526 if ((port
->p_id
= calloc(1, port
->p_id_len
)) == NULL
)
527 fatal("interfaces", NULL
);
528 memcpy(port
->p_id
, hardware
->h_ifname
, port
->p_id_len
);
531 /* use the actual alias in the port description */
532 log_debug("interfaces", "using alias in description for %s",
536 port
->p_descr
= strdup(iface
->alias
);
538 /* We don't have anything else to put here and for CDP
539 * with need something non-NULL */
540 port
->p_descr
= strdup(hardware
->h_ifname
);
543 if (portid_type
!= LLDP_PORTID_SUBTYPE_LOCAL
) {
544 log_debug("interfaces", "use MAC address for %s",
546 port
->p_id_subtype
= LLDP_PORTID_SUBTYPE_LLADDR
;
548 if ((port
->p_id
= calloc(1, ETHER_ADDR_LEN
)) == NULL
)
549 fatal("interfaces", NULL
);
550 memcpy(port
->p_id
, hardware
->h_lladdr
, ETHER_ADDR_LEN
);
551 port
->p_id_len
= ETHER_ADDR_LEN
;
554 /* use the ifname in the port description until alias is set */
555 log_debug("interfaces", "using ifname in description for %s",
558 port
->p_descr
= strdup(hardware
->h_ifname
);
563 interfaces_helper_add_hardware(struct lldpd
*cfg
,
564 struct lldpd_hardware
*hardware
)
566 TRACE(LLDPD_INTERFACES_NEW(hardware
->h_ifname
));
567 TAILQ_INSERT_TAIL(&cfg
->g_hardware
, hardware
, h_entries
);
571 interfaces_helper_physical(struct lldpd
*cfg
,
572 struct interfaces_device_list
*interfaces
,
573 struct lldpd_ops
*ops
,
574 int(*init
)(struct lldpd
*, struct lldpd_hardware
*))
576 struct interfaces_device
*iface
;
577 struct lldpd_hardware
*hardware
;
579 TAILQ_FOREACH(iface
, interfaces
, next
) {
580 if (!(iface
->type
& IFACE_PHYSICAL_T
)) continue;
581 if (iface
->ignore
) continue;
583 log_debug("interfaces", "%s is an acceptable ethernet device",
585 if ((hardware
= lldpd_get_hardware(cfg
,
589 if ((hardware
= lldpd_alloc_hardware(cfg
,
591 iface
->index
)) == NULL
) {
592 log_warnx("interfaces", "Unable to allocate space for %s",
596 if (init(cfg
, hardware
) != 0) {
597 log_warnx("interfaces",
598 "unable to initialize %s",
600 lldpd_hardware_cleanup(cfg
, hardware
);
603 hardware
->h_ops
= ops
;
604 hardware
->h_mangle
= (iface
->upper
&&
605 iface
->upper
->type
& IFACE_BOND_T
);
606 interfaces_helper_add_hardware(cfg
, hardware
);
608 if (hardware
->h_flags
) continue; /* Already seen this time */
609 lldpd_port_cleanup(&hardware
->h_lport
, 0);
612 hardware
->h_flags
= iface
->flags
; /* Should be non-zero */
613 iface
->ignore
= 1; /* Future handlers
618 /* Get local address */
619 memcpy(&hardware
->h_lladdr
, iface
->address
, ETHER_ADDR_LEN
);
621 /* Fill information about port */
622 interfaces_helper_port_name_desc(cfg
, hardware
, iface
);
624 /* Fill additional info */
625 hardware
->h_mtu
= iface
->mtu
? iface
->mtu
: 1500;
628 if (iface
->upper
&& iface
->upper
->type
& IFACE_BOND_T
)
629 hardware
->h_lport
.p_aggregid
= iface
->upper
->index
;
635 interfaces_helper_promisc(struct lldpd
*cfg
,
636 struct lldpd_hardware
*hardware
)
638 if (!cfg
->g_config
.c_promisc
) return;
639 if (priv_iface_promisc(hardware
->h_ifname
) != 0) {
640 log_warnx("interfaces",
641 "unable to enable promiscuous mode for %s",
647 * Send the packet using the hardware function. Optionnaly mangle the MAC address.
649 * With bonds, we have duplicate MAC address on different physical
650 * interfaces. We need to alter the source MAC address when we send on an
651 * inactive slave. The `h_mangle` flah is used to know if we need to do
652 * something like that.
655 interfaces_send_helper(struct lldpd
*cfg
,
656 struct lldpd_hardware
*hardware
,
657 char *buffer
, size_t size
)
659 if (size
< 2 * ETHER_ADDR_LEN
) {
660 log_warnx("interfaces",
661 "packet to send on %s is too small!",
665 if (hardware
->h_mangle
) {
666 #define MAC_UL_ADMINISTERED_BIT_MASK 0x02
667 char *src_mac
= buffer
+ ETHER_ADDR_LEN
;
668 char arbitrary
[] = { 0x00, 0x60, 0x08, 0x69, 0x97, 0xef};
670 switch (cfg
->g_config
.c_bond_slave_src_mac_type
) {
671 case LLDP_BOND_SLAVE_SRC_MAC_TYPE_LOCALLY_ADMINISTERED
:
672 if (!(*src_mac
& MAC_UL_ADMINISTERED_BIT_MASK
)) {
673 *src_mac
|= MAC_UL_ADMINISTERED_BIT_MASK
;
676 /* Fallback to fixed value */
677 case LLDP_BOND_SLAVE_SRC_MAC_TYPE_FIXED
:
678 memcpy(src_mac
, arbitrary
, ETHER_ADDR_LEN
);
680 case LLDP_BOND_SLAVE_SRC_MAC_TYPE_ZERO
:
681 memset(src_mac
, 0, ETHER_ADDR_LEN
);
685 return hardware
->h_ops
->send(cfg
, hardware
, buffer
, size
);