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.
227 * Initially, upper == vlan. This function will be called recursively.
230 iface_append_vlan_to_lower(struct lldpd
*cfg
,
231 struct interfaces_device_list
*interfaces
,
232 struct interfaces_device
*vlan
,
233 struct interfaces_device
*upper
)
235 struct interfaces_device
*lower
;
236 log_debug("interfaces",
237 "looking to apply VLAN %s to physical interface behind %s",
238 vlan
->name
, upper
->name
);
240 /* Easy: check if we have a lower interface. */
242 log_debug("interfaces", "VLAN %s on lower interface %s",
243 vlan
->name
, upper
->name
);
244 iface_append_vlan_to_lower(cfg
,
250 /* Other easy case, we have a physical interface. */
251 if (upper
->type
& IFACE_PHYSICAL_T
) {
252 log_debug("interfaces", "VLAN %s on physical interface %s",
253 vlan
->name
, upper
->name
);
254 iface_append_vlan(cfg
, vlan
, upper
);
258 /* We can now search for interfaces that have our interface as an upper
260 TAILQ_FOREACH(lower
, interfaces
, next
) {
261 if (lower
->upper
!= upper
) continue;
262 log_debug("interfaces", "VLAN %s on lower interface %s",
263 vlan
->name
, upper
->name
);
264 iface_append_vlan_to_lower(cfg
,
265 interfaces
, vlan
, lower
);
270 interfaces_helper_vlan(struct lldpd
*cfg
,
271 struct interfaces_device_list
*interfaces
)
273 struct interfaces_device
*iface
;
275 TAILQ_FOREACH(iface
, interfaces
, next
) {
278 if (!(iface
->type
& IFACE_VLAN_T
))
281 /* We need to find the physical interfaces of this
282 vlan, through bonds and bridges. */
283 log_debug("interfaces", "search physical interface for VLAN interface %s",
285 iface_append_vlan_to_lower(cfg
, interfaces
,
291 /* Fill out chassis ID if not already done. Only physical interfaces are
294 interfaces_helper_chassis(struct lldpd
*cfg
,
295 struct interfaces_device_list
*interfaces
)
297 struct interfaces_device
*iface
;
298 struct lldpd_hardware
*hardware
;
301 LOCAL_CHASSIS(cfg
)->c_cap_enabled
&=
302 ~(LLDP_CAP_BRIDGE
| LLDP_CAP_WLAN
| LLDP_CAP_STATION
);
303 TAILQ_FOREACH(iface
, interfaces
, next
) {
304 if (iface
->type
& IFACE_BRIDGE_T
)
305 LOCAL_CHASSIS(cfg
)->c_cap_enabled
|= LLDP_CAP_BRIDGE
;
306 if (iface
->type
& IFACE_WIRELESS_T
)
307 LOCAL_CHASSIS(cfg
)->c_cap_enabled
|= LLDP_CAP_WLAN
;
309 if ((LOCAL_CHASSIS(cfg
)->c_cap_available
& LLDP_CAP_STATION
) &&
310 (LOCAL_CHASSIS(cfg
)->c_cap_enabled
== 0))
311 LOCAL_CHASSIS(cfg
)->c_cap_enabled
= LLDP_CAP_STATION
;
313 if (LOCAL_CHASSIS(cfg
)->c_id
!= NULL
&&
314 LOCAL_CHASSIS(cfg
)->c_id_subtype
== LLDP_CHASSISID_SUBTYPE_LLADDR
)
315 return; /* We already have one */
317 TAILQ_FOREACH(iface
, interfaces
, next
) {
318 if (!(iface
->type
& IFACE_PHYSICAL_T
)) continue;
319 if (cfg
->g_config
.c_cid_pattern
&&
320 !pattern_match(iface
->name
, cfg
->g_config
.c_cid_pattern
, 0)) continue;
322 if ((hardware
= lldpd_get_hardware(cfg
,
326 /* That's odd. Let's skip. */
329 name
= malloc(ETHER_ADDR_LEN
);
331 log_warn("interfaces", "not enough memory for chassis ID");
334 free(LOCAL_CHASSIS(cfg
)->c_id
);
335 memcpy(name
, hardware
->h_lladdr
, ETHER_ADDR_LEN
);
336 LOCAL_CHASSIS(cfg
)->c_id
= name
;
337 LOCAL_CHASSIS(cfg
)->c_id_len
= ETHER_ADDR_LEN
;
338 LOCAL_CHASSIS(cfg
)->c_id_subtype
= LLDP_CHASSISID_SUBTYPE_LLADDR
;
343 #undef IN_IS_ADDR_LOOPBACK
344 #define IN_IS_ADDR_LOOPBACK(a) ((a)->s_addr == htonl(INADDR_LOOPBACK))
345 #undef IN_IS_ADDR_ANY
346 #define IN_IS_ADDR_ANY(a) ((a)->s_addr == htonl(INADDR_ANY))
347 #undef IN_IS_ADDR_GLOBAL
348 #define IN_IS_ADDR_GLOBAL(a) (!IN_IS_ADDR_LOOPBACK(a) && !IN_IS_ADDR_ANY(a))
349 #undef IN6_IS_ADDR_GLOBAL
350 #define IN6_IS_ADDR_GLOBAL(a) \
351 (!IN6_IS_ADDR_LOOPBACK(a) && !IN6_IS_ADDR_LINKLOCAL(a))
353 /* Find a management address in all available interfaces, even those that were
354 already handled. This is a special interface handler because it does not
355 really handle interface related information (management address is attached
356 to the local chassis). */
358 interfaces_helper_mgmt(struct lldpd
*cfg
,
359 struct interfaces_address_list
*addrs
)
361 struct interfaces_address
*addr
;
362 char addrstrbuf
[INET6_ADDRSTRLEN
];
363 struct lldpd_mgmt
*mgmt
;
365 size_t sin_addr_size
;
369 lldpd_chassis_mgmt_cleanup(LOCAL_CHASSIS(cfg
));
371 /* Is the pattern provided all negative? */
372 if (cfg
->g_config
.c_mgmt_pattern
== NULL
) allnegative
= 1;
373 else if (cfg
->g_config
.c_mgmt_pattern
[0] == '!') {
374 /* If each comma is followed by '!', its an all
376 char *sep
= cfg
->g_config
.c_mgmt_pattern
;
377 while ((sep
= strchr(sep
, ',')) &&
379 if (sep
== NULL
) allnegative
= 1;
382 /* Find management addresses */
383 for (af
= LLDPD_AF_UNSPEC
+ 1; af
!= LLDPD_AF_LAST
; af
++) {
384 /* We only take one of each address family, unless a
385 pattern is provided and is not all negative. For
386 example !*:*,!10.* will only blacklist
387 addresses. We will pick the first IPv4 address not
389 TAILQ_FOREACH(addr
, addrs
, next
) {
390 if (addr
->address
.ss_family
!= lldpd_af(af
))
395 sin_addr_ptr
= &((struct sockaddr_in
*)&addr
->address
)->sin_addr
;
396 sin_addr_size
= sizeof(struct in_addr
);
397 if (!IN_IS_ADDR_GLOBAL((struct in_addr
*)sin_addr_ptr
))
401 sin_addr_ptr
= &((struct sockaddr_in6
*)&addr
->address
)->sin6_addr
;
402 sin_addr_size
= sizeof(struct in6_addr
);
403 if (!IN6_IS_ADDR_GLOBAL((struct in6_addr
*)sin_addr_ptr
))
410 if (inet_ntop(lldpd_af(af
), sin_addr_ptr
,
411 addrstrbuf
, sizeof(addrstrbuf
)) == NULL
) {
412 log_warn("interfaces", "unable to convert IP address to a string");
415 if (cfg
->g_config
.c_mgmt_pattern
== NULL
||
416 pattern_match(addrstrbuf
, cfg
->g_config
.c_mgmt_pattern
, allnegative
)) {
417 mgmt
= lldpd_alloc_mgmt(af
, sin_addr_ptr
, sin_addr_size
,
420 assert(errno
== ENOMEM
); /* anything else is a bug */
421 log_warn("interfaces", "out of memory error");
424 log_debug("interfaces", "add management address %s", addrstrbuf
);
425 TAILQ_INSERT_TAIL(&LOCAL_CHASSIS(cfg
)->c_mgmt
, mgmt
, m_entries
);
427 /* Don't take additional address if the pattern is all negative. */
428 if (allnegative
) break;
434 /* Fill up port name and description */
436 interfaces_helper_port_name_desc(struct lldpd
*cfg
,
437 struct lldpd_hardware
*hardware
,
438 struct interfaces_device
*iface
)
440 struct lldpd_port
*port
= &hardware
->h_lport
;
442 /* We need to set the portid to what the client configured.
443 This can be done from the CLI.
445 switch (cfg
->g_config
.c_lldp_portid_type
) {
446 case LLDP_PORTID_SUBTYPE_IFNAME
:
447 log_debug("interfaces", "use ifname for %s",
449 port
->p_id_subtype
= LLDP_PORTID_SUBTYPE_IFNAME
;
450 port
->p_id_len
= strlen(hardware
->h_ifname
);
451 if (port
->p_id
!= NULL
) {
454 if ((port
->p_id
= calloc(1, port
->p_id_len
)) == NULL
)
455 fatal("interfaces", NULL
);
456 memcpy(port
->p_id
, hardware
->h_ifname
, port
->p_id_len
);
458 case LLDP_PORTID_SUBTYPE_LLADDR
:
459 /* fall through so we use the mac address */
461 log_debug("interfaces", "use MAC address for %s",
463 port
->p_id_subtype
= LLDP_PORTID_SUBTYPE_LLADDR
;
464 if (port
->p_id
!= NULL
) {
467 if ((port
->p_id
= calloc(1, ETHER_ADDR_LEN
)) == NULL
)
468 fatal("interfaces", NULL
);
469 memcpy(port
->p_id
, hardware
->h_lladdr
, ETHER_ADDR_LEN
);
470 port
->p_id_len
= ETHER_ADDR_LEN
;
473 if (iface
->alias
!= NULL
&& strlen(iface
->alias
) != 0) {
474 /* use the actual alias in the port description */
475 log_debug("interfaces", "using alias in description for %s",
477 if (port
->p_descr
!= NULL
) {
480 port
->p_descr
= strdup(iface
->alias
);
482 /* use the ifname in the port description until alias is set */
483 log_debug("interfaces", "using ifname in description for %s",
485 if (port
->p_descr
!= NULL
) {
488 port
->p_descr
= strdup(hardware
->h_ifname
);
493 interfaces_helper_add_hardware(struct lldpd
*cfg
,
494 struct lldpd_hardware
*hardware
)
496 TRACE(LLDPD_INTERFACES_NEW(hardware
->h_ifname
));
497 TAILQ_INSERT_TAIL(&cfg
->g_hardware
, hardware
, h_entries
);
501 interfaces_helper_physical(struct lldpd
*cfg
,
502 struct interfaces_device_list
*interfaces
,
503 struct lldpd_ops
*ops
,
504 int(*init
)(struct lldpd
*, struct lldpd_hardware
*))
506 struct interfaces_device
*iface
;
507 struct lldpd_hardware
*hardware
;
509 TAILQ_FOREACH(iface
, interfaces
, next
) {
510 if (!(iface
->type
& IFACE_PHYSICAL_T
)) continue;
511 if (!iface
->flags
) continue;
513 log_debug("interfaces", "%s is an acceptable ethernet device",
515 if ((hardware
= lldpd_get_hardware(cfg
,
519 if ((hardware
= lldpd_alloc_hardware(cfg
,
521 iface
->index
)) == NULL
) {
522 log_warnx("interfaces", "Unable to allocate space for %s",
526 if (init(cfg
, hardware
) != 0) {
527 log_warnx("interfaces",
528 "unable to initialize %s",
530 lldpd_hardware_cleanup(cfg
, hardware
);
533 hardware
->h_ops
= ops
;
534 hardware
->h_mangle
= (iface
->upper
&&
535 iface
->upper
->type
& IFACE_BOND_T
);
536 interfaces_helper_add_hardware(cfg
, hardware
);
538 if (hardware
->h_flags
) continue; /* Already seen this time */
539 lldpd_port_cleanup(&hardware
->h_lport
, 0);
542 hardware
->h_flags
= iface
->flags
; /* Should be non-zero */
543 iface
->flags
= 0; /* Future handlers
548 /* Get local address */
549 memcpy(&hardware
->h_lladdr
, iface
->address
, ETHER_ADDR_LEN
);
551 /* Fill information about port */
552 interfaces_helper_port_name_desc(cfg
, hardware
, iface
);
554 /* Fill additional info */
555 hardware
->h_mtu
= iface
->mtu
? iface
->mtu
: 1500;
558 if (iface
->upper
&& iface
->upper
->type
& IFACE_BOND_T
)
559 hardware
->h_lport
.p_aggregid
= iface
->upper
->index
;
565 interfaces_helper_promisc(struct lldpd
*cfg
,
566 struct lldpd_hardware
*hardware
)
568 if (!cfg
->g_config
.c_promisc
) return;
569 if (priv_iface_promisc(hardware
->h_ifname
) != 0) {
570 log_warnx("interfaces",
571 "unable to enable promiscuous mode for %s",
577 * Send the packet using the hardware function. Optionnaly mangle the MAC address.
579 * With bonds, we have duplicate MAC address on different physical
580 * interfaces. We need to alter the source MAC address when we send on an
581 * inactive slave. The `h_mangle` flah is used to know if we need to do
582 * something like that.
585 interfaces_send_helper(struct lldpd
*cfg
,
586 struct lldpd_hardware
*hardware
,
587 char *buffer
, size_t size
)
589 if (size
< 2 * ETHER_ADDR_LEN
) {
590 log_warnx("interfaces",
591 "packet to send on %s is too small!",
595 if (hardware
->h_mangle
) {
596 #define MAC_UL_ADMINISTERED_BIT_MASK 0x02
597 char *src_mac
= buffer
+ ETHER_ADDR_LEN
;
598 char arbitrary
[] = { 0x00, 0x60, 0x08, 0x69, 0x97, 0xef};
600 switch (cfg
->g_config
.c_bond_slave_src_mac_type
) {
601 case LLDP_BOND_SLAVE_SRC_MAC_TYPE_LOCALLY_ADMINISTERED
:
602 if (!(*src_mac
& MAC_UL_ADMINISTERED_BIT_MASK
)) {
603 *src_mac
|= MAC_UL_ADMINISTERED_BIT_MASK
;
606 /* Fallback to fixed value */
607 case LLDP_BOND_SLAVE_SRC_MAC_TYPE_FIXED
:
608 memcpy(src_mac
, arbitrary
, ETHER_ADDR_LEN
);
610 case LLDP_BOND_SLAVE_SRC_MAC_TYPE_ZERO
:
611 memset(src_mac
, 0, ETHER_ADDR_LEN
);
615 return hardware
->h_ops
->send(cfg
, hardware
, buffer
, size
);