1 /* -*- mode: c; c-file-style: "openbsd" -*- */
2 /*
3  * Copyright (c) 2012 Vincent Bernat <bernat@luffy.cx>
4  *
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.
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 
18 #include "lldpd.h"
19 #include "trace.h"
20 
21 #include <stddef.h>
22 #include <unistd.h>
23 #include <errno.h>
24 #include <assert.h>
25 #include <arpa/inet.h>
26 
27 static int
lldpd_af(int af)28 lldpd_af(int af)
29 {
30 	switch (af) {
31 	case LLDPD_AF_IPV4: return AF_INET;
32 	case LLDPD_AF_IPV6: return AF_INET6;
33 	case LLDPD_AF_LAST: return AF_MAX;
34 	default: return AF_UNSPEC;
35 	}
36 }
37 
38 /* Generic ethernet interface initialization */
39 /**
40  * Enable multicast on the given interface.
41  */
42 void
interfaces_setup_multicast(struct lldpd * cfg,const char * name,int remove)43 interfaces_setup_multicast(struct lldpd *cfg, const char *name,
44     int remove)
45 {
46 	int rc;
47 	size_t i, j;
48 	const u_int8_t *mac;
49 	const u_int8_t zero[ETHER_ADDR_LEN] = {};
50 
51 	for (i = 0; cfg->g_protocols[i].mode != 0; i++) {
52 		if (!cfg->g_protocols[i].enabled) continue;
53 		for (mac = cfg->g_protocols[i].mac1, j = 0;
54 		     j < 3;
55 		     mac += ETHER_ADDR_LEN,
56 		     j++) {
57 			if (memcmp(mac, zero, ETHER_ADDR_LEN) == 0) break;
58 			if ((rc = priv_iface_multicast(name,
59 				    mac, !remove)) != 0) {
60 				errno = rc;
61 				if (errno != ENOENT)
62 					log_debug("interfaces",
63 					    "unable to %s %s address to multicast filter for %s (%s)",
64 					    (remove)?"delete":"add",
65 					    cfg->g_protocols[i].name,
66 					    name, strerror(rc));
67 			}
68 		}
69 	}
70 }
71 
72 /**
73  * Free an interface.
74  *
75  * @param iff interface to be freed
76  */
77 void
interfaces_free_device(struct interfaces_device * iff)78 interfaces_free_device(struct interfaces_device *iff)
79 {
80 	if (!iff) return;
81 	free(iff->name);
82 	free(iff->alias);
83 	free(iff->address);
84 	free(iff->driver);
85 	free(iff);
86 }
87 
88 /**
89  * Free a list of interfaces.
90  *
91  * @param ifs list of interfaces to be freed
92  */
93 void
interfaces_free_devices(struct interfaces_device_list * ifs)94 interfaces_free_devices(struct interfaces_device_list *ifs)
95 {
96 	struct interfaces_device *iff, *iff_next;
97 	if (!ifs) return;
98 	for (iff = TAILQ_FIRST(ifs);
99 	     iff != NULL;
100 	     iff = iff_next) {
101 		iff_next = TAILQ_NEXT(iff, next);
102 		interfaces_free_device(iff);
103 	}
104 	free(ifs);
105 }
106 
107 /**
108  * Free one address
109  *
110  * @param ifaddr Address to be freed
111  */
112 void
interfaces_free_address(struct interfaces_address * ifaddr)113 interfaces_free_address(struct interfaces_address *ifaddr)
114 {
115 	free(ifaddr);
116 }
117 
118 /**
119  * Free a list of addresses.
120  *
121  * @param ifaddrs list of addresses
122  */
123 void
interfaces_free_addresses(struct interfaces_address_list * ifaddrs)124 interfaces_free_addresses(struct interfaces_address_list *ifaddrs)
125 {
126 	struct interfaces_address *ifa, *ifa_next;
127 	if (!ifaddrs) return;
128 	for (ifa = TAILQ_FIRST(ifaddrs);
129 	     ifa != NULL;
130 	     ifa = ifa_next) {
131 		ifa_next = TAILQ_NEXT(ifa, next);
132 		interfaces_free_address(ifa);
133 	}
134 	free(ifaddrs);
135 }
136 
137 /**
138  * Find the appropriate interface from the name.
139  *
140  * @param interfaces List of available interfaces
141  * @param device     Name of the device we search for
142  * @return The interface or NULL if not found
143  */
144 struct interfaces_device*
interfaces_nametointerface(struct interfaces_device_list * interfaces,const char * device)145 interfaces_nametointerface(struct interfaces_device_list *interfaces,
146     const char *device)
147 {
148 	struct interfaces_device *iface;
149 	TAILQ_FOREACH(iface, interfaces, next) {
150 		if (!strncmp(iface->name, device, IFNAMSIZ))
151 			return iface;
152 	}
153 	log_debug("interfaces", "cannot get interface for index %s",
154 	    device);
155 	return NULL;
156 }
157 
158 /**
159  * Find the appropriate interface from the index.
160  *
161  * @param interfaces List of available interfaces
162  * @param index      Index of the device we search for
163  * @return The interface or NULL if not found
164  */
165 struct interfaces_device*
interfaces_indextointerface(struct interfaces_device_list * interfaces,int index)166 interfaces_indextointerface(struct interfaces_device_list *interfaces,
167     int index)
168 {
169 	struct interfaces_device *iface;
170 	TAILQ_FOREACH(iface, interfaces, next) {
171 		if (iface->index == index)
172 			return iface;
173 	}
174 	log_debug("interfaces", "cannot get interface for index %d",
175 	    index);
176 	return NULL;
177 }
178 
179 void
interfaces_helper_allowlist(struct lldpd * cfg,struct interfaces_device_list * interfaces)180 interfaces_helper_allowlist(struct lldpd *cfg,
181     struct interfaces_device_list *interfaces)
182 {
183 	struct interfaces_device *iface;
184 
185 	if (!cfg->g_config.c_iface_pattern)
186 		return;
187 
188 	TAILQ_FOREACH(iface, interfaces, next) {
189 		int m = pattern_match(iface->name, cfg->g_config.c_iface_pattern, 0);
190 		switch (m) {
191 		case 0:
192 			log_debug("interfaces", "deny %s", iface->name);
193 			iface->ignore = 1;
194 			continue;
195 		case 2:
196 			log_debug("interfaces", "allow %s (consider it as a physical interface)",
197 			    iface->name);
198 			iface->type |= IFACE_PHYSICAL_T;
199 			continue;
200 		}
201 	}
202 }
203 
204 #ifdef ENABLE_DOT1
205 static void
iface_append_vlan(struct lldpd * cfg,struct interfaces_device * vlan,struct interfaces_device * lower)206 iface_append_vlan(struct lldpd *cfg,
207     struct interfaces_device *vlan,
208     struct interfaces_device *lower)
209 {
210 	struct lldpd_hardware *hardware =
211 	    lldpd_get_hardware(cfg, lower->name, lower->index);
212 	struct lldpd_port *port;
213 	struct lldpd_vlan *v;
214 	char *name = NULL;
215 	uint16_t vlan_id;
216 
217 	if (hardware == NULL) {
218 		log_debug("interfaces",
219 		    "cannot find real interface %s for VLAN %s",
220 		    lower->name, vlan->name);
221 		return;
222 	}
223 	port = &hardware->h_lport;
224 
225 	for (int i = 0; (i < VLAN_BITMAP_LEN); i++) {
226 		if (vlan->vlan_bmap[i] == 0)
227 			continue;
228 		for (unsigned bit = 0; bit < 32; bit++) {
229 			uint32_t mask = 1L << bit;
230 			if (!(vlan->vlan_bmap[i] & mask))
231 				continue;
232 			vlan_id = (i * 32) + bit;
233 			if (asprintf(&name, "vlan%d", vlan_id) == -1)
234 				return;
235 
236 			/* Check if the VLAN is already here. */
237 			TAILQ_FOREACH(v, &port->p_vlans, v_entries)
238 				if (strncmp(name, v->v_name, IFNAMSIZ) == 0) {
239 					free(name);
240 					return;
241 				}
242 
243 			if ((v = (struct lldpd_vlan *)
244 				calloc(1, sizeof(struct lldpd_vlan))) == NULL) {
245 				free(name);
246 				return;
247 			}
248 			v->v_name = name;
249 			v->v_vid = vlan_id;
250 			if (vlan->pvid)
251 				port->p_pvid = vlan->pvid;
252 			log_debug("interfaces", "append VLAN %s for %s",
253 				v->v_name,
254 				hardware->h_ifname);
255 			TAILQ_INSERT_TAIL(&port->p_vlans, v, v_entries);
256 		}
257 	}
258 }
259 
260 /**
261  * Append VLAN to the lowest possible interface.
262  *
263  * @param vlan  The VLAN interface (used to get VLAN ID).
264  * @param upper The upper interface we are currently examining.
265  * @param depth Depth of the stack (avoid infinite recursion)
266  *
267  * Initially, upper == vlan. This function will be called recursively.
268  */
269 static void
iface_append_vlan_to_lower(struct lldpd * cfg,struct interfaces_device_list * interfaces,struct interfaces_device * vlan,struct interfaces_device * upper,int depth)270 iface_append_vlan_to_lower(struct lldpd *cfg,
271     struct interfaces_device_list *interfaces,
272     struct interfaces_device *vlan,
273     struct interfaces_device *upper,
274     int depth)
275 {
276 	if (depth > 5) {
277 		log_warnx("interfaces",
278 		    "BUG: maximum depth reached when applying VLAN %s (loop?)",
279 		    vlan->name);
280 		return;
281 	}
282 	depth++;
283 	struct interfaces_device *lower;
284 	log_debug("interfaces",
285 	    "looking to apply VLAN %s to physical interface behind %s",
286 	    vlan->name, upper->name);
287 
288 	/* Some bridges managed VLAN internally, skip them. */
289 	if (upper->type & IFACE_BRIDGE_VLAN_T) {
290 		log_debug("interfaces", "VLAN %s ignored for VLAN-aware bridge interface %s",
291 		    vlan->name, upper->name);
292 		return;
293 	}
294 
295 	/* Easy: check if we have a lower interface. */
296 	if (upper->lower) {
297 		log_debug("interfaces", "VLAN %s on lower interface %s",
298 		    vlan->name, upper->name);
299 		iface_append_vlan_to_lower(cfg,
300 		    interfaces, vlan,
301 		    upper->lower,
302 		    depth);
303 		return;
304 	}
305 
306 	/* Other easy case, we have a physical interface. */
307 	if (upper->type & IFACE_PHYSICAL_T) {
308 		log_debug("interfaces", "VLAN %s on physical interface %s",
309 		    vlan->name, upper->name);
310 		iface_append_vlan(cfg, vlan, upper);
311 		return;
312 	}
313 
314 	/* We can now search for interfaces that have our interface as an upper
315 	 * interface. */
316 	TAILQ_FOREACH(lower, interfaces, next) {
317 		if (lower->upper != upper) continue;
318 		log_debug("interfaces", "VLAN %s on lower interface %s",
319 		    vlan->name, upper->name);
320 		iface_append_vlan_to_lower(cfg,
321 		    interfaces, vlan, lower, depth);
322 	}
323 }
324 
325 void
interfaces_helper_vlan(struct lldpd * cfg,struct interfaces_device_list * interfaces)326 interfaces_helper_vlan(struct lldpd *cfg,
327     struct interfaces_device_list *interfaces)
328 {
329 	struct interfaces_device *iface;
330 
331 	TAILQ_FOREACH(iface, interfaces, next) {
332 		if (!(iface->type & IFACE_VLAN_T) && bitmap_isempty(iface->vlan_bmap))
333 			continue;
334 
335 		/* We need to find the physical interfaces of this
336 		   vlan, through bonds and bridges. */
337 		log_debug("interfaces", "search physical interface for VLAN interface %s",
338 		    iface->name);
339 		iface_append_vlan_to_lower(cfg, interfaces,
340 		    iface, iface, 0);
341 	}
342 }
343 #endif
344 
345 /* Fill out chassis ID if not already done. Only physical interfaces are
346  * considered. */
347 void
interfaces_helper_chassis(struct lldpd * cfg,struct interfaces_device_list * interfaces)348 interfaces_helper_chassis(struct lldpd *cfg,
349     struct interfaces_device_list *interfaces)
350 {
351 	struct interfaces_device *iface;
352 	struct lldpd_hardware *hardware;
353 	char *name = NULL;
354 
355 	LOCAL_CHASSIS(cfg)->c_cap_enabled &=
356 			    ~(LLDP_CAP_BRIDGE | LLDP_CAP_WLAN | LLDP_CAP_STATION);
357 	TAILQ_FOREACH(iface, interfaces, next) {
358 		if (iface->type & IFACE_BRIDGE_T)
359 			LOCAL_CHASSIS(cfg)->c_cap_enabled |= LLDP_CAP_BRIDGE;
360 		if (iface->type & IFACE_WIRELESS_T)
361 			LOCAL_CHASSIS(cfg)->c_cap_enabled |= LLDP_CAP_WLAN;
362 	}
363 	if ((LOCAL_CHASSIS(cfg)->c_cap_available & LLDP_CAP_STATION) &&
364 		(LOCAL_CHASSIS(cfg)->c_cap_enabled == 0))
365 	    LOCAL_CHASSIS(cfg)->c_cap_enabled = LLDP_CAP_STATION;
366 
367 	/* Do not modify the chassis if it's already set to a MAC address or if
368 	 * it's set to a local address equal to the user-provided
369 	 * configuration. */
370 	if ((LOCAL_CHASSIS(cfg)->c_id != NULL &&
371 	    LOCAL_CHASSIS(cfg)->c_id_subtype == LLDP_CHASSISID_SUBTYPE_LLADDR) ||
372 	    cfg->g_config.c_cid_string != NULL)
373 		return;		/* We already have one */
374 
375 	TAILQ_FOREACH(iface, interfaces, next) {
376 		if (!(iface->type & IFACE_PHYSICAL_T)) continue;
377 		if (cfg->g_config.c_cid_pattern &&
378 		    !pattern_match(iface->name, cfg->g_config.c_cid_pattern, 0)) continue;
379 
380 		if ((hardware = lldpd_get_hardware(cfg,
381 			    iface->name,
382 			    iface->index)) == NULL)
383 			/* That's odd. Let's skip. */
384 			continue;
385 
386 		name = malloc(ETHER_ADDR_LEN);
387 		if (!name) {
388 			log_warn("interfaces", "not enough memory for chassis ID");
389 			return;
390 		}
391 		free(LOCAL_CHASSIS(cfg)->c_id);
392 		memcpy(name, hardware->h_lladdr, ETHER_ADDR_LEN);
393 		LOCAL_CHASSIS(cfg)->c_id = name;
394 		LOCAL_CHASSIS(cfg)->c_id_len = ETHER_ADDR_LEN;
395 		LOCAL_CHASSIS(cfg)->c_id_subtype = LLDP_CHASSISID_SUBTYPE_LLADDR;
396 		return;
397 	}
398 }
399 
400 #undef IN_IS_ADDR_LOOPBACK
401 #define IN_IS_ADDR_LOOPBACK(a) ((a)->s_addr == htonl(INADDR_LOOPBACK))
402 #undef IN_IS_ADDR_ANY
403 #define IN_IS_ADDR_ANY(a) ((a)->s_addr == htonl(INADDR_ANY))
404 #undef IN_IS_ADDR_LINKLOCAL
405 #define IN_IS_ADDR_LINKLOCAL(a) (((a)->s_addr & htonl(0xffff0000)) == htonl(0xa9fe0000))
406 #undef IN_IS_ADDR_GLOBAL
407 #define IN_IS_ADDR_GLOBAL(a) (!IN_IS_ADDR_LOOPBACK(a) && !IN_IS_ADDR_ANY(a) && !IN_IS_ADDR_LINKLOCAL(a))
408 #undef IN6_IS_ADDR_GLOBAL
409 #define IN6_IS_ADDR_GLOBAL(a) \
410 	(!IN6_IS_ADDR_LOOPBACK(a) && !IN6_IS_ADDR_LINKLOCAL(a))
411 
412 /* Add management addresses for the given family. We only take one of each
413    address family, unless a pattern is provided and is not all negative. For
414    example !*:*,!10.* will only deny addresses. We will pick the first IPv4
415    address not matching 10.*.
416 */
417 static int
interfaces_helper_mgmt_for_af(struct lldpd * cfg,int af,struct interfaces_address_list * addrs,struct interfaces_device_list * interfaces,int global,int allnegative)418 interfaces_helper_mgmt_for_af(struct lldpd *cfg,
419     int af,
420     struct interfaces_address_list *addrs,
421     struct interfaces_device_list *interfaces,
422     int global, int allnegative)
423 {
424 	struct interfaces_address *addr;
425 	struct interfaces_device *device;
426 	struct lldpd_mgmt *mgmt;
427 	char addrstrbuf[INET6_ADDRSTRLEN];
428 	int found = 0;
429 	union lldpd_address in_addr;
430 	size_t in_addr_size;
431 
432 	TAILQ_FOREACH(addr, addrs, next) {
433 		if (addr->address.ss_family != lldpd_af(af))
434 			continue;
435 
436 		switch (af) {
437 		case LLDPD_AF_IPV4:
438 			in_addr_size = sizeof(struct in_addr);
439 			memcpy(&in_addr, &((struct sockaddr_in *)&addr->address)->sin_addr,
440 			    in_addr_size);
441 			if (global) {
442 				if (!IN_IS_ADDR_GLOBAL(&in_addr.inet))
443 					continue;
444 			} else {
445 				if (!IN_IS_ADDR_LINKLOCAL(&in_addr.inet))
446 					continue;
447 			}
448 			break;
449 		case LLDPD_AF_IPV6:
450 			in_addr_size = sizeof(struct in6_addr);
451 			memcpy(&in_addr, &((struct sockaddr_in6 *)&addr->address)->sin6_addr,
452 			    in_addr_size);
453 			if (global) {
454 				if (!IN6_IS_ADDR_GLOBAL(&in_addr.inet6))
455 					continue;
456 			} else {
457 				if (!IN6_IS_ADDR_LINKLOCAL(&in_addr.inet6))
458 					continue;
459 			}
460 			break;
461 		default:
462 			assert(0);
463 			continue;
464 		}
465 		if (inet_ntop(lldpd_af(af), &in_addr,
466 			addrstrbuf, sizeof(addrstrbuf)) == NULL) {
467 			log_warn("interfaces", "unable to convert IP address to a string");
468 			continue;
469 		}
470 		if (cfg->g_config.c_mgmt_pattern == NULL ||
471 		    /* Match on IP address */
472 		    pattern_match(addrstrbuf, cfg->g_config.c_mgmt_pattern, allnegative) ||
473 		    /* Match on interface name */
474 		    ((device = interfaces_indextointerface(interfaces, addr->index)) &&
475 		    pattern_match(device->name, cfg->g_config.c_mgmt_pattern, allnegative))) {
476 			mgmt = lldpd_alloc_mgmt(af, &in_addr, in_addr_size,
477 			    addr->index);
478 			if (mgmt == NULL) {
479 				assert(errno == ENOMEM); /* anything else is a bug */
480 				log_warn("interfaces", "out of memory error");
481 				return found;
482 			}
483 			log_debug("interfaces", "add management address %s", addrstrbuf);
484 			TAILQ_INSERT_TAIL(&LOCAL_CHASSIS(cfg)->c_mgmt, mgmt, m_entries);
485 			found = 1;
486 
487 			/* Don't take additional address if the pattern is all negative. */
488 			if (allnegative) break;
489 		}
490 	}
491 	return found;
492 }
493 
494 /* Find a management address in all available interfaces, even those that were
495    already handled. This is a special interface handler because it does not
496    really handle interface related information (management address is attached
497    to the local chassis). */
498 void
interfaces_helper_mgmt(struct lldpd * cfg,struct interfaces_address_list * addrs,struct interfaces_device_list * interfaces)499 interfaces_helper_mgmt(struct lldpd *cfg,
500     struct interfaces_address_list *addrs,
501     struct interfaces_device_list *interfaces)
502 {
503 	int allnegative = 0;
504 	int af;
505 	const char *pattern = cfg->g_config.c_mgmt_pattern;
506 
507 	lldpd_chassis_mgmt_cleanup(LOCAL_CHASSIS(cfg));
508 	if (!cfg->g_config.c_mgmt_advertise)
509 		return;
510 
511 	/* Is the pattern provided an actual IP address? */
512 	if (pattern && strpbrk(pattern, "!,*?") == NULL) {
513 		unsigned char addr[sizeof(struct in6_addr)];
514 		size_t addr_size;
515 		struct lldpd_mgmt *mgmt;
516 		struct interfaces_address *ifaddr;
517 
518 		for (af = LLDPD_AF_UNSPEC + 1;
519 		     af != LLDPD_AF_LAST; af++) {
520 			switch (af) {
521 			case LLDPD_AF_IPV4: addr_size = sizeof(struct in_addr); break;
522 			case LLDPD_AF_IPV6: addr_size = sizeof(struct in6_addr); break;
523 			default: assert(0);
524 			}
525 			if (inet_pton(lldpd_af(af), pattern, addr) == 1)
526 				break;
527 		}
528 		if (af != LLDPD_AF_LAST) {
529 			/* Try to get the index if possible. */
530 			TAILQ_FOREACH(ifaddr, addrs, next) {
531 				if (ifaddr->address.ss_family != lldpd_af(af))
532 					continue;
533 				if (LLDPD_AF_IPV4 == af) {
534 					struct sockaddr_in *sa_sin;
535 					sa_sin = (struct sockaddr_in *)&ifaddr->address;
536 					if (0 == memcmp(addr,
537 					    &(sa_sin->sin_addr),
538 					    addr_size))
539 						break;
540 				}
541 				else if (LLDPD_AF_IPV6 == af) {
542 					if (0 == memcmp(addr,
543 					    &((struct sockaddr_in6 *)&ifaddr->address)->sin6_addr,
544 					    addr_size))
545 						break;
546 				}
547 			}
548 
549 			mgmt = lldpd_alloc_mgmt(af, addr, addr_size, ifaddr ? ifaddr->index : 0);
550 			if (mgmt == NULL) {
551 				log_warn("interfaces", "out of memory error");
552 				return;
553 			}
554 			log_debug("interfaces", "add exact management address %s",
555 			    pattern);
556 			TAILQ_INSERT_TAIL(&LOCAL_CHASSIS(cfg)->c_mgmt, mgmt, m_entries);
557 			return;
558 		}
559 		/* else: could be an interface name */
560 	}
561 
562 	/* Is the pattern provided all negative? */
563 	if (pattern == NULL) allnegative = 1;
564 	else if (pattern[0] == '!') {
565 		/* If each comma is followed by '!', its an all
566 		   negative pattern */
567 		const char *sep = pattern;
568 		while ((sep = strchr(sep, ',')) &&
569 		       (*(++sep) == '!'));
570 		if (sep == NULL) allnegative = 1;
571 	}
572 
573 	/* Find management addresses */
574 	for (af = LLDPD_AF_UNSPEC + 1; af != LLDPD_AF_LAST; af++) {
575 		(void)(interfaces_helper_mgmt_for_af(cfg, af, addrs, interfaces, 1, allnegative) ||
576 		    interfaces_helper_mgmt_for_af(cfg, af, addrs, interfaces, 0, allnegative));
577 	}
578 }
579 
580 /* Fill up port name and description */
581 void
interfaces_helper_port_name_desc(struct lldpd * cfg,struct lldpd_hardware * hardware,struct interfaces_device * iface)582 interfaces_helper_port_name_desc(struct lldpd *cfg,
583     struct lldpd_hardware *hardware,
584     struct interfaces_device *iface)
585 {
586 	struct lldpd_port *port = &hardware->h_lport;
587 
588 	/* We need to set the portid to what the client configured.
589 	   This can be done from the CLI.
590 	*/
591 	int has_alias = (iface->alias != NULL && strlen(iface->alias) != 0);
592 	int portid_type = cfg->g_config.c_lldp_portid_type;
593 	if (portid_type == LLDP_PORTID_SUBTYPE_IFNAME ||
594 	    (portid_type == LLDP_PORTID_SUBTYPE_UNKNOWN && has_alias) ||
595 	    (port->p_id_subtype == LLDP_PORTID_SUBTYPE_LOCAL && has_alias)) {
596 		if (port->p_id_subtype != LLDP_PORTID_SUBTYPE_LOCAL) {
597 			log_debug("interfaces", "use ifname for %s",
598 			    hardware->h_ifname);
599 			port->p_id_subtype = LLDP_PORTID_SUBTYPE_IFNAME;
600 			port->p_id_len = strlen(hardware->h_ifname);
601 			free(port->p_id);
602 			if ((port->p_id = calloc(1, port->p_id_len)) == NULL)
603 				fatal("interfaces", NULL);
604 			memcpy(port->p_id, hardware->h_ifname, port->p_id_len);
605 		}
606 
607 		if (port->p_descr_force == 0) {
608 			/* use the actual alias in the port description */
609 			log_debug("interfaces", "using alias in description for %s",
610 			    hardware->h_ifname);
611 			free(port->p_descr);
612 			if (has_alias) {
613 				port->p_descr = strdup(iface->alias);
614 			} else {
615 				/* We don't have anything else to put here and for CDP
616 				 * with need something non-NULL */
617 				port->p_descr = strdup(hardware->h_ifname);
618 			}
619 		}
620 	} else {
621 		if (port->p_id_subtype != LLDP_PORTID_SUBTYPE_LOCAL) {
622 			log_debug("interfaces", "use MAC address for %s",
623 			    hardware->h_ifname);
624 			port->p_id_subtype = LLDP_PORTID_SUBTYPE_LLADDR;
625 			free(port->p_id);
626 			if ((port->p_id = calloc(1, ETHER_ADDR_LEN)) == NULL)
627 				fatal("interfaces", NULL);
628 			memcpy(port->p_id, hardware->h_lladdr, ETHER_ADDR_LEN);
629 			port->p_id_len = ETHER_ADDR_LEN;
630 		}
631 
632 		if (port->p_descr_force == 0) {
633 			/* use the ifname in the port description until alias is set */
634 			log_debug("interfaces", "using ifname in description for %s",
635 			    hardware->h_ifname);
636 			free(port->p_descr);
637 			port->p_descr = strdup(hardware->h_ifname);
638 		}
639 	}
640 }
641 
642 void
interfaces_helper_add_hardware(struct lldpd * cfg,struct lldpd_hardware * hardware)643 interfaces_helper_add_hardware(struct lldpd *cfg,
644     struct lldpd_hardware *hardware)
645 {
646 	TRACE(LLDPD_INTERFACES_NEW(hardware->h_ifname));
647 	TAILQ_INSERT_TAIL(&cfg->g_hardware, hardware, h_entries);
648 }
649 
650 void
interfaces_helper_physical(struct lldpd * cfg,struct interfaces_device_list * interfaces,struct lldpd_ops * ops,int (* init)(struct lldpd *,struct lldpd_hardware *))651 interfaces_helper_physical(struct lldpd *cfg,
652     struct interfaces_device_list *interfaces,
653     struct lldpd_ops *ops,
654     int(*init)(struct lldpd *, struct lldpd_hardware *))
655 {
656 	struct interfaces_device *iface;
657 	struct lldpd_hardware *hardware;
658 	int created;
659 
660 	TAILQ_FOREACH(iface, interfaces, next) {
661 		if (!(iface->type & IFACE_PHYSICAL_T)) continue;
662 		if (iface->ignore) continue;
663 
664 		log_debug("interfaces", "%s is an acceptable ethernet device",
665 		    iface->name);
666 		created = 0;
667 		if ((hardware = lldpd_get_hardware(cfg,
668 			    iface->name,
669 			    iface->index)) == NULL) {
670 			if  ((hardware = lldpd_alloc_hardware(cfg,
671 				    iface->name,
672 				    iface->index)) == NULL) {
673 				log_warnx("interfaces", "Unable to allocate space for %s",
674 				    iface->name);
675 				continue;
676 			}
677 			created = 1;
678 		}
679 		if (hardware->h_flags)
680 			continue;
681 		if (hardware->h_ops != ops) {
682 			if (!created) {
683 				log_debug("interfaces",
684 				    "interface %s is converted from another type of interface",
685 				    hardware->h_ifname);
686 				if (hardware->h_ops && hardware->h_ops->cleanup) {
687 					hardware->h_ops->cleanup(cfg, hardware);
688 					levent_hardware_release(hardware);
689 					levent_hardware_init(hardware);
690 				}
691 			}
692 			if (init(cfg, hardware) != 0) {
693 				log_warnx("interfaces",
694 				    "unable to initialize %s",
695 				    hardware->h_ifname);
696 				lldpd_hardware_cleanup(cfg, hardware);
697 				continue;
698 			}
699 			hardware->h_ops = ops;
700 			hardware->h_mangle = (iface->upper &&
701 			    iface->upper->type & IFACE_BOND_T);
702 		}
703 		if (created)
704 			interfaces_helper_add_hardware(cfg, hardware);
705 		else
706 			lldpd_port_cleanup(&hardware->h_lport, 0);
707 
708 		hardware->h_flags = iface->flags;   /* Should be non-zero */
709 		iface->ignore = 1;		    /* Future handlers
710 						       don't have to
711 						       care about this
712 						       interface. */
713 
714 		/* Get local address */
715 		memcpy(&hardware->h_lladdr, iface->address, ETHER_ADDR_LEN);
716 
717 		/* Fill information about port */
718 		interfaces_helper_port_name_desc(cfg, hardware, iface);
719 
720 		/* Fill additional info */
721 		hardware->h_mtu = iface->mtu ? iface->mtu : 1500;
722 
723 #ifdef ENABLE_DOT3
724 		if (iface->upper && iface->upper->type & IFACE_BOND_T)
725 			hardware->h_lport.p_aggregid = iface->upper->index;
726 		else
727 			hardware->h_lport.p_aggregid = 0;
728 #endif
729 	}
730 }
731 
732 void
interfaces_helper_promisc(struct lldpd * cfg,struct lldpd_hardware * hardware)733 interfaces_helper_promisc(struct lldpd *cfg,
734     struct lldpd_hardware *hardware)
735 {
736 	if (!cfg->g_config.c_promisc) return;
737 	if (priv_iface_promisc(hardware->h_ifname) != 0) {
738 		log_warnx("interfaces",
739 		    "unable to enable promiscuous mode for %s",
740 		    hardware->h_ifname);
741 	}
742 }
743 
744 /**
745  * Send the packet using the hardware function. Optionnaly mangle the MAC address.
746  *
747  * With bonds, we have duplicate MAC address on different physical
748  * interfaces. We need to alter the source MAC address when we send on an
749  * inactive slave. The `h_mangle` flah is used to know if we need to do
750  * something like that.
751  */
752 int
interfaces_send_helper(struct lldpd * cfg,struct lldpd_hardware * hardware,char * buffer,size_t size)753 interfaces_send_helper(struct lldpd *cfg,
754     struct lldpd_hardware *hardware,
755     char *buffer, size_t size)
756 {
757 	if (size < 2 * ETHER_ADDR_LEN) {
758 		log_warnx("interfaces",
759 		    "packet to send on %s is too small!",
760 		    hardware->h_ifname);
761 		return 0;
762 	}
763 	if (hardware->h_mangle) {
764 #define MAC_UL_ADMINISTERED_BIT_MASK 0x02
765 		char *src_mac = buffer + ETHER_ADDR_LEN;
766 		char arbitrary[] = { 0x00, 0x60, 0x08, 0x69, 0x97, 0xef};
767 
768 		switch (cfg->g_config.c_bond_slave_src_mac_type) {
769 		case LLDP_BOND_SLAVE_SRC_MAC_TYPE_LOCALLY_ADMINISTERED:
770 			if (!(*src_mac & MAC_UL_ADMINISTERED_BIT_MASK)) {
771 				*src_mac |= MAC_UL_ADMINISTERED_BIT_MASK;
772 				break;
773 			}
774 			/* Fallback to fixed value */
775 			memcpy(src_mac, arbitrary, ETHER_ADDR_LEN);
776 			break;
777 		case LLDP_BOND_SLAVE_SRC_MAC_TYPE_FIXED:
778 			memcpy(src_mac, arbitrary, ETHER_ADDR_LEN);
779 			break;
780 		case LLDP_BOND_SLAVE_SRC_MAC_TYPE_ZERO:
781 			memset(src_mac, 0, ETHER_ADDR_LEN);
782 			break;
783 		}
784 	}
785 	return hardware->h_ops->send(cfg, hardware, buffer, size);
786 }
787