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_info("interfaces",
44 "unable to %s %s address to multicast filter for %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 pattern_match(char *iface
, char *list
, int found
)
162 char *interfaces
= NULL
;
165 if ((interfaces
= strdup(list
)) == NULL
) {
166 log_warnx("interfaces", "unable to allocate memory");
170 for (pattern
= strtok(interfaces
, ",");
172 pattern
= strtok(NULL
, ",")) {
173 if ((pattern
[0] == '!') &&
174 ((fnmatch(pattern
+ 1, iface
, 0) == 0))) {
175 /* Blacklisted. No need to search further. */
179 if (fnmatch(pattern
, iface
, 0) == 0)
188 interfaces_helper_whitelist(struct lldpd
*cfg
,
189 struct interfaces_device_list
*interfaces
)
191 struct interfaces_device
*iface
;
193 if (!cfg
->g_config
.c_iface_pattern
)
196 TAILQ_FOREACH(iface
, interfaces
, next
) {
197 if (iface
->flags
== 0) continue; /* Already handled by someone else */
198 if (!pattern_match(iface
->name
, cfg
->g_config
.c_iface_pattern
, 0)) {
199 /* This interface was not found. We flag it. */
200 log_debug("interfaces", "blacklist %s", iface
->name
);
208 iface_append_vlan(struct lldpd
*cfg
,
209 struct interfaces_device
*vlan
,
210 struct interfaces_device
*lower
)
212 struct lldpd_hardware
*hardware
=
213 lldpd_get_hardware(cfg
, lower
->name
, lower
->index
, NULL
);
214 struct lldpd_port
*port
;
215 struct lldpd_vlan
*v
;
217 if (hardware
== NULL
) {
218 log_debug("interfaces",
219 "cannot find real interface %s for VLAN %s",
220 lower
->name
, vlan
->name
);
224 /* Check if the VLAN is already here. */
225 port
= &hardware
->h_lport
;
226 TAILQ_FOREACH(v
, &port
->p_vlans
, v_entries
)
227 if (strncmp(vlan
->name
, v
->v_name
, IFNAMSIZ
) == 0)
229 if ((v
= (struct lldpd_vlan
*)
230 calloc(1, sizeof(struct lldpd_vlan
))) == NULL
)
232 if ((v
->v_name
= strdup(vlan
->name
)) == NULL
) {
236 v
->v_vid
= vlan
->vlanid
;
237 log_debug("interfaces", "append VLAN %s for %s",
240 TAILQ_INSERT_TAIL(&port
->p_vlans
, v
, v_entries
);
244 * Append VLAN to the lowest possible interface.
246 * @param vlan The VLAN interface (used to get VLAN ID).
247 * @param upper The upper interface we are currently examining.
249 * Initially, upper == vlan. This function will be called recursively.
252 iface_append_vlan_to_lower(struct lldpd
*cfg
,
253 struct interfaces_device_list
*interfaces
,
254 struct interfaces_device
*vlan
,
255 struct interfaces_device
*upper
)
257 struct interfaces_device
*lower
;
258 log_debug("interfaces",
259 "looking to apply VLAN %s to physical interface behind %s",
260 vlan
->name
, upper
->name
);
262 /* Easy: check if we have a lower interface. */
264 log_debug("interfaces", "VLAN %s on lower interface %s",
265 vlan
->name
, upper
->name
);
266 iface_append_vlan_to_lower(cfg
,
272 /* Other easy case, we have a physical interface. */
273 if (upper
->type
& IFACE_PHYSICAL_T
) {
274 log_debug("interfaces", "VLAN %s on physical interface %s",
275 vlan
->name
, upper
->name
);
276 iface_append_vlan(cfg
, vlan
, upper
);
280 /* We can now search for interfaces that have our interface as an upper
282 TAILQ_FOREACH(lower
, interfaces
, next
) {
283 if (lower
->upper
!= upper
) continue;
284 log_debug("interfaces", "VLAN %s on lower interface %s",
285 vlan
->name
, upper
->name
);
286 iface_append_vlan_to_lower(cfg
,
287 interfaces
, vlan
, lower
);
292 interfaces_helper_vlan(struct lldpd
*cfg
,
293 struct interfaces_device_list
*interfaces
)
295 struct interfaces_device
*iface
;
297 TAILQ_FOREACH(iface
, interfaces
, next
) {
300 if (!(iface
->type
& IFACE_VLAN_T
))
303 /* We need to find the physical interfaces of this
304 vlan, through bonds and bridges. */
305 log_debug("interfaces", "search physical interface for VLAN interface %s",
307 iface_append_vlan_to_lower(cfg
, interfaces
,
313 /* Fill out chassis ID if not already done. This handler is special
314 because we will only handle interfaces that are already handled. */
316 interfaces_helper_chassis(struct lldpd
*cfg
,
317 struct interfaces_device_list
*interfaces
)
319 struct interfaces_device
*iface
;
320 struct lldpd_hardware
*hardware
;
323 TAILQ_FOREACH(iface
, interfaces
, next
) {
324 if (iface
->type
& IFACE_BRIDGE_T
)
325 LOCAL_CHASSIS(cfg
)->c_cap_enabled
|= LLDP_CAP_BRIDGE
;
326 if (iface
->type
& IFACE_WIRELESS_T
)
327 LOCAL_CHASSIS(cfg
)->c_cap_enabled
|= LLDP_CAP_WLAN
;
330 if (LOCAL_CHASSIS(cfg
)->c_id
!= NULL
&&
331 LOCAL_CHASSIS(cfg
)->c_id_subtype
== LLDP_CHASSISID_SUBTYPE_LLADDR
)
332 return; /* We already have one */
334 TAILQ_FOREACH(iface
, interfaces
, next
) {
335 if (iface
->flags
) continue;
336 if (cfg
->g_config
.c_cid_pattern
&&
337 !pattern_match(iface
->name
, cfg
->g_config
.c_cid_pattern
, 0)) continue;
339 if ((hardware
= lldpd_get_hardware(cfg
,
343 /* That's odd. Let's skip. */
346 name
= malloc(sizeof(hardware
->h_lladdr
));
348 log_warn("interfaces", "not enough memory for chassis ID");
351 free(LOCAL_CHASSIS(cfg
)->c_id
);
352 memcpy(name
, hardware
->h_lladdr
, sizeof(hardware
->h_lladdr
));
353 LOCAL_CHASSIS(cfg
)->c_id
= name
;
354 LOCAL_CHASSIS(cfg
)->c_id_len
= sizeof(hardware
->h_lladdr
);
355 LOCAL_CHASSIS(cfg
)->c_id_subtype
= LLDP_CHASSISID_SUBTYPE_LLADDR
;
360 #ifndef IN_IS_ADDR_LOOPBACK
361 #define IN_IS_ADDR_LOOPBACK(a) ((a)->s_addr == htonl(INADDR_LOOPBACK))
363 #ifndef IN_IS_ADDR_ANY
364 #define IN_IS_ADDR_ANY(a) ((a)->s_addr == htonl(INADDR_ANY))
366 #ifndef IN_IS_ADDR_GLOBAL
367 #define IN_IS_ADDR_GLOBAL(a) (!IN_IS_ADDR_LOOPBACK(a) && !IN_IS_ADDR_ANY(a))
369 #ifndef IN6_IS_ADDR_GLOBAL
370 #define IN6_IS_ADDR_GLOBAL(a) \
371 (!IN6_IS_ADDR_LOOPBACK(a) && !IN6_IS_ADDR_LINKLOCAL(a))
374 /* Find a management address in all available interfaces, even those that were
375 already handled. This is a special interface handler because it does not
376 really handle interface related information (management address is attached
377 to the local chassis). */
379 interfaces_helper_mgmt(struct lldpd
*cfg
,
380 struct interfaces_address_list
*addrs
)
382 struct interfaces_address
*addr
;
383 char addrstrbuf
[INET6_ADDRSTRLEN
];
384 struct lldpd_mgmt
*mgmt
;
386 size_t sin_addr_size
;
390 lldpd_chassis_mgmt_cleanup(LOCAL_CHASSIS(cfg
));
392 /* Is the pattern provided all negative? */
393 if (cfg
->g_config
.c_mgmt_pattern
== NULL
) allnegative
= 1;
394 else if (cfg
->g_config
.c_mgmt_pattern
[0] == '!') {
395 /* If each comma is followed by '!', its an all
397 char *sep
= cfg
->g_config
.c_mgmt_pattern
;
398 while ((sep
= strchr(sep
, ',')) &&
400 if (sep
== NULL
) allnegative
= 1;
403 /* Find management addresses */
404 for (af
= LLDPD_AF_UNSPEC
+ 1; af
!= LLDPD_AF_LAST
; af
++) {
405 /* We only take one of each address family, unless a
406 pattern is provided and is not all negative. For
407 example !*:*,!10.* will only blacklist
408 addresses. We will pick the first IPv4 address not
410 TAILQ_FOREACH(addr
, addrs
, next
) {
411 if (addr
->address
.ss_family
!= lldpd_af(af
))
416 sin_addr_ptr
= &((struct sockaddr_in
*)&addr
->address
)->sin_addr
;
417 sin_addr_size
= sizeof(struct in_addr
);
418 if (!IN_IS_ADDR_GLOBAL((struct in_addr
*)sin_addr_ptr
))
422 sin_addr_ptr
= &((struct sockaddr_in6
*)&addr
->address
)->sin6_addr
;
423 sin_addr_size
= sizeof(struct in6_addr
);
424 if (!IN6_IS_ADDR_GLOBAL((struct in6_addr
*)sin_addr_ptr
))
431 if (inet_ntop(lldpd_af(af
), sin_addr_ptr
,
432 addrstrbuf
, sizeof(addrstrbuf
)) == NULL
) {
433 log_warn("interfaces", "unable to convert IP address to a string");
436 if (cfg
->g_config
.c_mgmt_pattern
== NULL
||
437 pattern_match(addrstrbuf
, cfg
->g_config
.c_mgmt_pattern
, allnegative
)) {
438 mgmt
= lldpd_alloc_mgmt(af
, sin_addr_ptr
, sin_addr_size
,
441 assert(errno
== ENOMEM
); /* anything else is a bug */
442 log_warn("interfaces", "out of memory error");
445 log_debug("interfaces", "add management address %s", addrstrbuf
);
446 TAILQ_INSERT_TAIL(&LOCAL_CHASSIS(cfg
)->c_mgmt
, mgmt
, m_entries
);
448 /* Don't take additional address if the pattern is all negative. */
449 if (allnegative
) break;
455 /* Fill up port name and description */
457 interfaces_helper_port_name_desc(struct lldpd_hardware
*hardware
,
458 struct interfaces_device
*iface
)
460 struct lldpd_port
*port
= &hardware
->h_lport
;
462 /* There are two cases:
464 1. We have a kernel recent enough to support ifAlias
465 _and_ a non empty ifAlias, then we will use it for
466 description and use ifname for port ID.
468 2. Otherwise, we will use the MAC address as ID and the
469 port name in description.
472 if (iface
->alias
== NULL
|| strlen(iface
->alias
) == 0) {
473 /* Case 2: MAC address and port name */
474 log_debug("interfaces", "use ifname and MAC address for %s",
476 port
->p_id_subtype
= LLDP_PORTID_SUBTYPE_LLADDR
;
478 calloc(1, sizeof(hardware
->h_lladdr
))) == NULL
)
479 fatal("interfaces", NULL
);
480 memcpy(port
->p_id
, hardware
->h_lladdr
,
481 sizeof(hardware
->h_lladdr
));
482 port
->p_id_len
= sizeof(hardware
->h_lladdr
);
483 port
->p_descr
= strdup(hardware
->h_ifname
);
486 /* Case 1: port name and port description */
487 log_debug("interfaces", "use ifname and ifalias for %s",
489 port
->p_id_subtype
= LLDP_PORTID_SUBTYPE_IFNAME
;
490 port
->p_id_len
= strlen(hardware
->h_ifname
);
492 calloc(1, port
->p_id_len
)) == NULL
)
493 fatal("interfaces", NULL
);
494 memcpy(port
->p_id
, hardware
->h_ifname
, port
->p_id_len
);
495 port
->p_descr
= strdup(iface
->alias
);
499 interfaces_helper_physical(struct lldpd
*cfg
,
500 struct interfaces_device_list
*interfaces
,
501 struct lldpd_ops
*ops
,
502 int(*init
)(struct lldpd
*, struct lldpd_hardware
*))
504 struct interfaces_device
*iface
;
505 struct lldpd_hardware
*hardware
;
507 TAILQ_FOREACH(iface
, interfaces
, next
) {
508 if (!(iface
->type
& IFACE_PHYSICAL_T
)) continue;
509 if (!iface
->flags
) continue;
511 log_debug("interfaces", "%s is an acceptable ethernet device",
513 if ((hardware
= lldpd_get_hardware(cfg
,
517 if ((hardware
= lldpd_alloc_hardware(cfg
,
519 iface
->index
)) == NULL
) {
520 log_warnx("interfaces", "Unable to allocate space for %s",
524 if (init(cfg
, hardware
) != 0) {
525 log_warnx("interfaces",
526 "unable to initialize %s",
528 lldpd_hardware_cleanup(cfg
, hardware
);
531 hardware
->h_ops
= ops
;
532 hardware
->h_mangle
= (iface
->upper
&&
533 iface
->upper
->type
& IFACE_BOND_T
);
534 TAILQ_INSERT_TAIL(&cfg
->g_hardware
, hardware
, h_entries
);
536 if (hardware
->h_flags
) continue; /* Already seen this time */
537 lldpd_port_cleanup(&hardware
->h_lport
, 0);
540 hardware
->h_flags
= iface
->flags
; /* Should be non-zero */
541 iface
->flags
= 0; /* Future handlers
546 /* Get local address */
547 memcpy(&hardware
->h_lladdr
, iface
->address
, ETHER_ADDR_LEN
);
549 /* Fill information about port */
550 interfaces_helper_port_name_desc(hardware
, iface
);
552 /* Fill additional info */
553 hardware
->h_mtu
= iface
->mtu
? iface
->mtu
: 1500;
556 if (iface
->upper
&& iface
->upper
->type
& IFACE_BOND_T
)
557 hardware
->h_lport
.p_aggregid
= iface
->upper
->index
;
563 * Send the packet using the hardware function. Optionnaly mangle the MAC address.
565 * With bonds, we have duplicate MAC address on different physical
566 * interfaces. We need to alter the source MAC address when we send on an
567 * inactive slave. The `h_mangle` flah is used to know if we need to do
568 * something like that.
571 interfaces_send_helper(struct lldpd
*cfg
,
572 struct lldpd_hardware
*hardware
,
573 char *buffer
, size_t size
)
575 if (size
< 2 * ETHER_ADDR_LEN
) {
576 log_warnx("interfaces",
577 "packet to send on %s is too small!",
581 if (hardware
->h_mangle
) {
582 #define MAC_UL_ADMINISTERED_BIT_MASK 0x02
583 char *src_mac
= buffer
+ ETHER_ADDR_LEN
;
584 char arbitrary
[] = { 0x00, 0x60, 0x08, 0x69, 0x97, 0xef};
586 switch (cfg
->g_config
.c_bond_slave_src_mac_type
) {
587 case LLDP_BOND_SLAVE_SRC_MAC_TYPE_LOCALLY_ADMINISTERED
:
588 if (*src_mac
& MAC_UL_ADMINISTERED_BIT_MASK
) {
589 /* If locally administered bit already set,
592 memset(src_mac
, 0, ETHER_ADDR_LEN
);
595 case LLDP_BOND_SLAVE_SRC_MAC_TYPE_FIXED
:
596 memcpy(src_mac
, arbitrary
, ETHER_ADDR_LEN
);
598 case LLDP_BOND_SLAVE_SRC_MAC_TYPE_ZERO
:
599 memset(src_mac
, 0, ETHER_ADDR_LEN
);
603 return hardware
->h_ops
->send(cfg
, hardware
, buffer
, size
);