]> git.ipfire.org Git - thirdparty/lldpd.git/blob - src/daemon/interfaces.c
80324566ab880199c1e303fbde39f1b4a5310516
[thirdparty/lldpd.git] / src / daemon / interfaces.c
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
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
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
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
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
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
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*
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*
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
180 interfaces_helper_whitelist(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", "blacklist %s", iface->name);
193 iface->ignore = 1;
194 continue;
195 case 2:
196 log_debug("interfaces", "whitelist %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
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
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 /* Easy: check if we have a lower interface. */
289 if (upper->lower) {
290 log_debug("interfaces", "VLAN %s on lower interface %s",
291 vlan->name, upper->name);
292 iface_append_vlan_to_lower(cfg,
293 interfaces, vlan,
294 upper->lower,
295 depth);
296 return;
297 }
298
299 /* Other easy case, we have a physical interface. */
300 if (upper->type & IFACE_PHYSICAL_T) {
301 log_debug("interfaces", "VLAN %s on physical interface %s",
302 vlan->name, upper->name);
303 iface_append_vlan(cfg, vlan, upper);
304 return;
305 }
306
307 /* We can now search for interfaces that have our interface as an upper
308 * interface. */
309 TAILQ_FOREACH(lower, interfaces, next) {
310 if (lower->upper != upper) continue;
311 log_debug("interfaces", "VLAN %s on lower interface %s",
312 vlan->name, upper->name);
313 iface_append_vlan_to_lower(cfg,
314 interfaces, vlan, lower, depth);
315 }
316 }
317
318 void
319 interfaces_helper_vlan(struct lldpd *cfg,
320 struct interfaces_device_list *interfaces)
321 {
322 struct interfaces_device *iface;
323
324 TAILQ_FOREACH(iface, interfaces, next) {
325 if (!(iface->type & IFACE_VLAN_T) && is_bitmap_empty(iface->vlan_bmap))
326 continue;
327
328 /* We need to find the physical interfaces of this
329 vlan, through bonds and bridges. */
330 log_debug("interfaces", "search physical interface for VLAN interface %s",
331 iface->name);
332 iface_append_vlan_to_lower(cfg, interfaces,
333 iface, iface, 0);
334 }
335 }
336 #endif
337
338 /* Fill out chassis ID if not already done. Only physical interfaces are
339 * considered. */
340 void
341 interfaces_helper_chassis(struct lldpd *cfg,
342 struct interfaces_device_list *interfaces)
343 {
344 struct interfaces_device *iface;
345 struct lldpd_hardware *hardware;
346 char *name = NULL;
347
348 LOCAL_CHASSIS(cfg)->c_cap_enabled &=
349 ~(LLDP_CAP_BRIDGE | LLDP_CAP_WLAN | LLDP_CAP_STATION);
350 TAILQ_FOREACH(iface, interfaces, next) {
351 if (iface->type & IFACE_BRIDGE_T)
352 LOCAL_CHASSIS(cfg)->c_cap_enabled |= LLDP_CAP_BRIDGE;
353 if (iface->type & IFACE_WIRELESS_T)
354 LOCAL_CHASSIS(cfg)->c_cap_enabled |= LLDP_CAP_WLAN;
355 }
356 if ((LOCAL_CHASSIS(cfg)->c_cap_available & LLDP_CAP_STATION) &&
357 (LOCAL_CHASSIS(cfg)->c_cap_enabled == 0))
358 LOCAL_CHASSIS(cfg)->c_cap_enabled = LLDP_CAP_STATION;
359
360 if (LOCAL_CHASSIS(cfg)->c_id != NULL &&
361 LOCAL_CHASSIS(cfg)->c_id_subtype == LLDP_CHASSISID_SUBTYPE_LLADDR)
362 return; /* We already have one */
363
364 TAILQ_FOREACH(iface, interfaces, next) {
365 if (!(iface->type & IFACE_PHYSICAL_T)) continue;
366 if (cfg->g_config.c_cid_pattern &&
367 !pattern_match(iface->name, cfg->g_config.c_cid_pattern, 0)) continue;
368
369 if ((hardware = lldpd_get_hardware(cfg,
370 iface->name,
371 iface->index)) == NULL)
372 /* That's odd. Let's skip. */
373 continue;
374
375 name = malloc(ETHER_ADDR_LEN);
376 if (!name) {
377 log_warn("interfaces", "not enough memory for chassis ID");
378 return;
379 }
380 free(LOCAL_CHASSIS(cfg)->c_id);
381 memcpy(name, hardware->h_lladdr, ETHER_ADDR_LEN);
382 LOCAL_CHASSIS(cfg)->c_id = name;
383 LOCAL_CHASSIS(cfg)->c_id_len = ETHER_ADDR_LEN;
384 LOCAL_CHASSIS(cfg)->c_id_subtype = LLDP_CHASSISID_SUBTYPE_LLADDR;
385 return;
386 }
387 }
388
389 #undef IN_IS_ADDR_LOOPBACK
390 #define IN_IS_ADDR_LOOPBACK(a) ((a)->s_addr == htonl(INADDR_LOOPBACK))
391 #undef IN_IS_ADDR_ANY
392 #define IN_IS_ADDR_ANY(a) ((a)->s_addr == htonl(INADDR_ANY))
393 #undef IN_IS_ADDR_LINKLOCAL
394 #define IN_IS_ADDR_LINKLOCAL(a) (((a)->s_addr & htonl(0xffff0000)) == htonl(0xa9fe0000))
395 #undef IN_IS_ADDR_GLOBAL
396 #define IN_IS_ADDR_GLOBAL(a) (!IN_IS_ADDR_LOOPBACK(a) && !IN_IS_ADDR_ANY(a) && !IN_IS_ADDR_LINKLOCAL(a))
397 #undef IN6_IS_ADDR_GLOBAL
398 #define IN6_IS_ADDR_GLOBAL(a) \
399 (!IN6_IS_ADDR_LOOPBACK(a) && !IN6_IS_ADDR_LINKLOCAL(a))
400
401 /* Add management addresses for the given family. We only take one of each
402 address family, unless a pattern is provided and is not all negative. For
403 example !*:*,!10.* will only blacklist addresses. We will pick the first IPv4
404 address not matching 10.*.
405 */
406 static int
407 interfaces_helper_mgmt_for_af(struct lldpd *cfg,
408 int af,
409 struct interfaces_address_list *addrs,
410 struct interfaces_device_list *interfaces,
411 int global, int allnegative)
412 {
413 struct interfaces_address *addr;
414 struct interfaces_device *device;
415 struct lldpd_mgmt *mgmt;
416 char addrstrbuf[INET6_ADDRSTRLEN];
417 int found = 0;
418 union lldpd_address in_addr;
419 size_t in_addr_size;
420
421 TAILQ_FOREACH(addr, addrs, next) {
422 if (addr->address.ss_family != lldpd_af(af))
423 continue;
424
425 switch (af) {
426 case LLDPD_AF_IPV4:
427 in_addr_size = sizeof(struct in_addr);
428 memcpy(&in_addr, &((struct sockaddr_in *)&addr->address)->sin_addr,
429 in_addr_size);
430 if (global) {
431 if (!IN_IS_ADDR_GLOBAL(&in_addr.inet))
432 continue;
433 } else {
434 if (!IN_IS_ADDR_LINKLOCAL(&in_addr.inet))
435 continue;
436 }
437 break;
438 case LLDPD_AF_IPV6:
439 in_addr_size = sizeof(struct in6_addr);
440 memcpy(&in_addr, &((struct sockaddr_in6 *)&addr->address)->sin6_addr,
441 in_addr_size);
442 if (global) {
443 if (!IN6_IS_ADDR_GLOBAL(&in_addr.inet6))
444 continue;
445 } else {
446 if (!IN6_IS_ADDR_LINKLOCAL(&in_addr.inet6))
447 continue;
448 }
449 break;
450 default:
451 assert(0);
452 continue;
453 }
454 if (inet_ntop(lldpd_af(af), &in_addr,
455 addrstrbuf, sizeof(addrstrbuf)) == NULL) {
456 log_warn("interfaces", "unable to convert IP address to a string");
457 continue;
458 }
459 if (cfg->g_config.c_mgmt_pattern == NULL ||
460 /* Match on IP address */
461 pattern_match(addrstrbuf, cfg->g_config.c_mgmt_pattern, allnegative) ||
462 /* Match on interface name */
463 ((device = interfaces_indextointerface(interfaces, addr->index)) &&
464 pattern_match(device->name, cfg->g_config.c_mgmt_pattern, allnegative))) {
465 mgmt = lldpd_alloc_mgmt(af, &in_addr, in_addr_size,
466 addr->index);
467 if (mgmt == NULL) {
468 assert(errno == ENOMEM); /* anything else is a bug */
469 log_warn("interfaces", "out of memory error");
470 return found;
471 }
472 log_debug("interfaces", "add management address %s", addrstrbuf);
473 TAILQ_INSERT_TAIL(&LOCAL_CHASSIS(cfg)->c_mgmt, mgmt, m_entries);
474 found = 1;
475
476 /* Don't take additional address if the pattern is all negative. */
477 if (allnegative) break;
478 }
479 }
480 return found;
481 }
482
483 /* Find a management address in all available interfaces, even those that were
484 already handled. This is a special interface handler because it does not
485 really handle interface related information (management address is attached
486 to the local chassis). */
487 void
488 interfaces_helper_mgmt(struct lldpd *cfg,
489 struct interfaces_address_list *addrs,
490 struct interfaces_device_list *interfaces)
491 {
492 int allnegative = 0;
493 int af;
494 const char *pattern = cfg->g_config.c_mgmt_pattern;
495
496 lldpd_chassis_mgmt_cleanup(LOCAL_CHASSIS(cfg));
497 if (!cfg->g_config.c_mgmt_advertise)
498 return;
499
500 /* Is the pattern provided an actual IP address? */
501 if (pattern && strpbrk(pattern, "!,*?") == NULL) {
502 struct in6_addr addr;
503 size_t addr_size;
504 struct lldpd_mgmt *mgmt;
505 struct interfaces_address *ifaddr;
506
507 for (af = LLDPD_AF_UNSPEC + 1;
508 af != LLDPD_AF_LAST; af++) {
509 switch (af) {
510 case LLDPD_AF_IPV4: addr_size = sizeof(struct in_addr); break;
511 case LLDPD_AF_IPV6: addr_size = sizeof(struct in6_addr); break;
512 default: assert(0);
513 }
514 if (inet_pton(lldpd_af(af), pattern, &addr) == 1)
515 break;
516 }
517 if (af != LLDPD_AF_LAST) {
518 /* Try to get the index if possible. */
519 TAILQ_FOREACH(ifaddr, addrs, next) {
520 if (ifaddr->address.ss_family != lldpd_af(af))
521 continue;
522 if (LLDPD_AF_IPV4 == af) {
523 struct sockaddr_in *sa_sin;
524 sa_sin = (struct sockaddr_in *)&ifaddr->address;
525 if ((sa_sin->sin_addr.s_addr) == ((struct in_addr *)&addr)->s_addr)
526 break;
527 }
528 else if (LLDPD_AF_IPV6 == af) {
529 if (0 == memcmp(&addr,
530 &((struct sockaddr_in6 *)&ifaddr->address)->sin6_addr,
531 addr_size))
532 break;
533 }
534 }
535
536 mgmt = lldpd_alloc_mgmt(af, &addr, addr_size, ifaddr ? ifaddr->index : 0);
537 if (mgmt == NULL) {
538 log_warn("interfaces", "out of memory error");
539 return;
540 }
541 log_debug("interfaces", "add exact management address %s",
542 pattern);
543 TAILQ_INSERT_TAIL(&LOCAL_CHASSIS(cfg)->c_mgmt, mgmt, m_entries);
544 return;
545 }
546 /* else: could be an interface name */
547 }
548
549 /* Is the pattern provided all negative? */
550 if (pattern == NULL) allnegative = 1;
551 else if (pattern[0] == '!') {
552 /* If each comma is followed by '!', its an all
553 negative pattern */
554 const char *sep = pattern;
555 while ((sep = strchr(sep, ',')) &&
556 (*(++sep) == '!'));
557 if (sep == NULL) allnegative = 1;
558 }
559
560 /* Find management addresses */
561 for (af = LLDPD_AF_UNSPEC + 1; af != LLDPD_AF_LAST; af++) {
562 (void)(interfaces_helper_mgmt_for_af(cfg, af, addrs, interfaces, 1, allnegative) ||
563 interfaces_helper_mgmt_for_af(cfg, af, addrs, interfaces, 0, allnegative));
564 }
565 }
566
567 /* Fill up port name and description */
568 void
569 interfaces_helper_port_name_desc(struct lldpd *cfg,
570 struct lldpd_hardware *hardware,
571 struct interfaces_device *iface)
572 {
573 struct lldpd_port *port = &hardware->h_lport;
574
575 /* We need to set the portid to what the client configured.
576 This can be done from the CLI.
577 */
578 int has_alias = (iface->alias != NULL && strlen(iface->alias) != 0);
579 int portid_type = cfg->g_config.c_lldp_portid_type;
580 if (portid_type == LLDP_PORTID_SUBTYPE_IFNAME ||
581 (portid_type == LLDP_PORTID_SUBTYPE_UNKNOWN && has_alias) ||
582 (port->p_id_subtype == LLDP_PORTID_SUBTYPE_LOCAL && has_alias)) {
583 if (port->p_id_subtype != LLDP_PORTID_SUBTYPE_LOCAL) {
584 log_debug("interfaces", "use ifname for %s",
585 hardware->h_ifname);
586 port->p_id_subtype = LLDP_PORTID_SUBTYPE_IFNAME;
587 port->p_id_len = strlen(hardware->h_ifname);
588 free(port->p_id);
589 if ((port->p_id = calloc(1, port->p_id_len)) == NULL)
590 fatal("interfaces", NULL);
591 memcpy(port->p_id, hardware->h_ifname, port->p_id_len);
592 }
593
594 if (port->p_descr_force == 0) {
595 /* use the actual alias in the port description */
596 log_debug("interfaces", "using alias in description for %s",
597 hardware->h_ifname);
598 free(port->p_descr);
599 if (has_alias) {
600 port->p_descr = strdup(iface->alias);
601 } else {
602 /* We don't have anything else to put here and for CDP
603 * with need something non-NULL */
604 port->p_descr = strdup(hardware->h_ifname);
605 }
606 }
607 } else {
608 if (port->p_id_subtype != LLDP_PORTID_SUBTYPE_LOCAL) {
609 log_debug("interfaces", "use MAC address for %s",
610 hardware->h_ifname);
611 port->p_id_subtype = LLDP_PORTID_SUBTYPE_LLADDR;
612 free(port->p_id);
613 if ((port->p_id = calloc(1, ETHER_ADDR_LEN)) == NULL)
614 fatal("interfaces", NULL);
615 memcpy(port->p_id, hardware->h_lladdr, ETHER_ADDR_LEN);
616 port->p_id_len = ETHER_ADDR_LEN;
617 }
618
619 if (port->p_descr_force == 0) {
620 /* use the ifname in the port description until alias is set */
621 log_debug("interfaces", "using ifname in description for %s",
622 hardware->h_ifname);
623 free(port->p_descr);
624 port->p_descr = strdup(hardware->h_ifname);
625 }
626 }
627 }
628
629 void
630 interfaces_helper_add_hardware(struct lldpd *cfg,
631 struct lldpd_hardware *hardware)
632 {
633 TRACE(LLDPD_INTERFACES_NEW(hardware->h_ifname));
634 TAILQ_INSERT_TAIL(&cfg->g_hardware, hardware, h_entries);
635 }
636
637 void
638 interfaces_helper_physical(struct lldpd *cfg,
639 struct interfaces_device_list *interfaces,
640 struct lldpd_ops *ops,
641 int(*init)(struct lldpd *, struct lldpd_hardware *))
642 {
643 struct interfaces_device *iface;
644 struct lldpd_hardware *hardware;
645 int created;
646
647 TAILQ_FOREACH(iface, interfaces, next) {
648 if (!(iface->type & IFACE_PHYSICAL_T)) continue;
649 if (iface->ignore) continue;
650
651 log_debug("interfaces", "%s is an acceptable ethernet device",
652 iface->name);
653 created = 0;
654 if ((hardware = lldpd_get_hardware(cfg,
655 iface->name,
656 iface->index)) == NULL) {
657 if ((hardware = lldpd_alloc_hardware(cfg,
658 iface->name,
659 iface->index)) == NULL) {
660 log_warnx("interfaces", "Unable to allocate space for %s",
661 iface->name);
662 continue;
663 }
664 created = 1;
665 }
666 if (hardware->h_flags)
667 continue;
668 if (hardware->h_ops != ops) {
669 if (!created) {
670 log_debug("interfaces",
671 "interface %s is converted from another type of interface",
672 hardware->h_ifname);
673 if (hardware->h_ops && hardware->h_ops->cleanup) {
674 hardware->h_ops->cleanup(cfg, hardware);
675 levent_hardware_release(hardware);
676 levent_hardware_init(hardware);
677 }
678 }
679 if (init(cfg, hardware) != 0) {
680 log_warnx("interfaces",
681 "unable to initialize %s",
682 hardware->h_ifname);
683 lldpd_hardware_cleanup(cfg, hardware);
684 continue;
685 }
686 hardware->h_ops = ops;
687 hardware->h_mangle = (iface->upper &&
688 iface->upper->type & IFACE_BOND_T);
689 }
690 if (created)
691 interfaces_helper_add_hardware(cfg, hardware);
692 else
693 lldpd_port_cleanup(&hardware->h_lport, 0);
694
695 hardware->h_flags = iface->flags; /* Should be non-zero */
696 iface->ignore = 1; /* Future handlers
697 don't have to
698 care about this
699 interface. */
700
701 /* Get local address */
702 memcpy(&hardware->h_lladdr, iface->address, ETHER_ADDR_LEN);
703
704 /* Fill information about port */
705 interfaces_helper_port_name_desc(cfg, hardware, iface);
706
707 /* Fill additional info */
708 hardware->h_mtu = iface->mtu ? iface->mtu : 1500;
709
710 #ifdef ENABLE_DOT3
711 if (iface->upper && iface->upper->type & IFACE_BOND_T)
712 hardware->h_lport.p_aggregid = iface->upper->index;
713 else
714 hardware->h_lport.p_aggregid = 0;
715 #endif
716 }
717 }
718
719 void
720 interfaces_helper_promisc(struct lldpd *cfg,
721 struct lldpd_hardware *hardware)
722 {
723 if (!cfg->g_config.c_promisc) return;
724 if (priv_iface_promisc(hardware->h_ifname) != 0) {
725 log_warnx("interfaces",
726 "unable to enable promiscuous mode for %s",
727 hardware->h_ifname);
728 }
729 }
730
731 /**
732 * Send the packet using the hardware function. Optionnaly mangle the MAC address.
733 *
734 * With bonds, we have duplicate MAC address on different physical
735 * interfaces. We need to alter the source MAC address when we send on an
736 * inactive slave. The `h_mangle` flah is used to know if we need to do
737 * something like that.
738 */
739 int
740 interfaces_send_helper(struct lldpd *cfg,
741 struct lldpd_hardware *hardware,
742 char *buffer, size_t size)
743 {
744 if (size < 2 * ETHER_ADDR_LEN) {
745 log_warnx("interfaces",
746 "packet to send on %s is too small!",
747 hardware->h_ifname);
748 return 0;
749 }
750 if (hardware->h_mangle) {
751 #define MAC_UL_ADMINISTERED_BIT_MASK 0x02
752 char *src_mac = buffer + ETHER_ADDR_LEN;
753 char arbitrary[] = { 0x00, 0x60, 0x08, 0x69, 0x97, 0xef};
754
755 switch (cfg->g_config.c_bond_slave_src_mac_type) {
756 case LLDP_BOND_SLAVE_SRC_MAC_TYPE_LOCALLY_ADMINISTERED:
757 if (!(*src_mac & MAC_UL_ADMINISTERED_BIT_MASK)) {
758 *src_mac |= MAC_UL_ADMINISTERED_BIT_MASK;
759 break;
760 }
761 /* Fallback to fixed value */
762 /* FALL THROUGH */
763 case LLDP_BOND_SLAVE_SRC_MAC_TYPE_FIXED:
764 memcpy(src_mac, arbitrary, ETHER_ADDR_LEN);
765 break;
766 case LLDP_BOND_SLAVE_SRC_MAC_TYPE_ZERO:
767 memset(src_mac, 0, ETHER_ADDR_LEN);
768 break;
769 }
770 }
771 return hardware->h_ops->send(cfg, hardware, buffer, size);
772 }