]> git.ipfire.org Git - thirdparty/lldpd.git/blame - src/daemon/interfaces.c
interfaces: limit the maximum search depth when applying a VLAN
[thirdparty/lldpd.git] / src / daemon / interfaces.c
CommitLineData
adbb6e54
VB
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"
bdfe4193 19#include "trace.h"
adbb6e54
VB
20
21#include <stddef.h>
22#include <unistd.h>
23#include <errno.h>
24#include <assert.h>
adbb6e54
VB
25#include <arpa/inet.h>
26
adbb6e54
VB
27/* Generic ethernet interface initialization */
28/**
29 * Enable multicast on the given interface.
30 */
31void
32interfaces_setup_multicast(struct lldpd *cfg, const char *name,
33 int remove)
34{
35 int i, rc;
36
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) {
41 errno = rc;
42 if (errno != ENOENT)
0469161d
ST
43 log_debug("interfaces",
44 "unable to %s %s address to multicast filter for %s (%s)",
adbb6e54
VB
45 (remove)?"delete":"add",
46 cfg->g_protocols[i].name,
0469161d 47 name, strerror(rc));
adbb6e54
VB
48 }
49 }
50}
51
adbb6e54
VB
52/**
53 * Free an interface.
54 *
55 * @param iff interface to be freed
56 */
57void
58interfaces_free_device(struct interfaces_device *iff)
59{
60 if (!iff) return;
61 free(iff->name);
62 free(iff->alias);
63 free(iff->address);
64 free(iff->driver);
65 free(iff);
66}
67
68/**
69 * Free a list of interfaces.
70 *
71 * @param ifs list of interfaces to be freed
72 */
73void
74interfaces_free_devices(struct interfaces_device_list *ifs)
75{
76 struct interfaces_device *iff, *iff_next;
77 if (!ifs) return;
78 for (iff = TAILQ_FIRST(ifs);
79 iff != NULL;
80 iff = iff_next) {
81 iff_next = TAILQ_NEXT(iff, next);
82 interfaces_free_device(iff);
83 }
84 free(ifs);
85}
86
87/**
88 * Free one address
89 *
90 * @param ifaddr Address to be freed
91 */
92void
93interfaces_free_address(struct interfaces_address *ifaddr)
94{
95 free(ifaddr);
96}
97
98/**
99 * Free a list of addresses.
100 *
101 * @param ifaddrs list of addresses
102 */
103void
104interfaces_free_addresses(struct interfaces_address_list *ifaddrs)
105{
106 struct interfaces_address *ifa, *ifa_next;
107 if (!ifaddrs) return;
108 for (ifa = TAILQ_FIRST(ifaddrs);
109 ifa != NULL;
110 ifa = ifa_next) {
111 ifa_next = TAILQ_NEXT(ifa, next);
112 interfaces_free_address(ifa);
113 }
114 free(ifaddrs);
115}
116
117/**
118 * Find the appropriate interface from the name.
119 *
120 * @param interfaces List of available interfaces
121 * @param device Name of the device we search for
9cac8fed 122 * @return The interface or NULL if not found
adbb6e54
VB
123 */
124struct interfaces_device*
125interfaces_nametointerface(struct interfaces_device_list *interfaces,
126 const char *device)
127{
128 struct interfaces_device *iface;
129 TAILQ_FOREACH(iface, interfaces, next) {
130 if (!strncmp(iface->name, device, IFNAMSIZ))
131 return iface;
132 }
133 log_debug("interfaces", "cannot get interface for index %s",
134 device);
135 return NULL;
136}
137
138/**
139 * Find the appropriate interface from the index.
140 *
141 * @param interfaces List of available interfaces
142 * @param index Index of the device we search for
9cac8fed 143 * @return The interface or NULL if not found
adbb6e54
VB
144 */
145struct interfaces_device*
146interfaces_indextointerface(struct interfaces_device_list *interfaces,
147 int index)
148{
149 struct interfaces_device *iface;
150 TAILQ_FOREACH(iface, interfaces, next) {
151 if (iface->index == index)
152 return iface;
153 }
154 log_debug("interfaces", "cannot get interface for index %d",
155 index);
156 return NULL;
157}
158
adbb6e54
VB
159void
160interfaces_helper_whitelist(struct lldpd *cfg,
161 struct interfaces_device_list *interfaces)
162{
163 struct interfaces_device *iface;
164
165 if (!cfg->g_config.c_iface_pattern)
166 return;
167
168 TAILQ_FOREACH(iface, interfaces, next) {
627e31c4
VB
169 int m = pattern_match(iface->name, cfg->g_config.c_iface_pattern, 0);
170 switch (m) {
171 case 0:
adbb6e54 172 log_debug("interfaces", "blacklist %s", iface->name);
0fa2254b 173 iface->ignore = 1;
627e31c4
VB
174 continue;
175 case 2:
c6aa43e5
VB
176 log_debug("interfaces", "whitelist %s (consider it as a physical interface)",
177 iface->name);
178 iface->type |= IFACE_PHYSICAL_T;
627e31c4 179 continue;
adbb6e54
VB
180 }
181 }
182}
183
184#ifdef ENABLE_DOT1
185static void
186iface_append_vlan(struct lldpd *cfg,
187 struct interfaces_device *vlan,
188 struct interfaces_device *lower)
189{
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;
194
195 if (hardware == NULL) {
196 log_debug("interfaces",
197 "cannot find real interface %s for VLAN %s",
198 lower->name, vlan->name);
199 return;
200 }
201
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)
206 return;
207 if ((v = (struct lldpd_vlan *)
208 calloc(1, sizeof(struct lldpd_vlan))) == NULL)
209 return;
210 if ((v->v_name = strdup(vlan->name)) == NULL) {
211 free(v);
212 return;
213 }
214 v->v_vid = vlan->vlanid;
215 log_debug("interfaces", "append VLAN %s for %s",
216 v->v_name,
217 hardware->h_ifname);
218 TAILQ_INSERT_TAIL(&port->p_vlans, v, v_entries);
219}
220
221/**
222 * Append VLAN to the lowest possible interface.
223 *
224 * @param vlan The VLAN interface (used to get VLAN ID).
225 * @param upper The upper interface we are currently examining.
e7e6676e 226 * @param depth Depth of the stack (avoid infinite recursion)
adbb6e54
VB
227 *
228 * Initially, upper == vlan. This function will be called recursively.
229 */
230static void
231iface_append_vlan_to_lower(struct lldpd *cfg,
232 struct interfaces_device_list *interfaces,
233 struct interfaces_device *vlan,
e7e6676e
VB
234 struct interfaces_device *upper,
235 int depth)
adbb6e54 236{
e7e6676e
VB
237 if (depth > 5) {
238 log_debug("interfaces",
239 "maximum depth reached when applying VLAN %s (loop?)",
240 vlan->name);
241 return;
242 }
243 depth++;
adbb6e54
VB
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);
248
249 /* Easy: check if we have a lower interface. */
250 if (upper->lower) {
251 log_debug("interfaces", "VLAN %s on lower interface %s",
252 vlan->name, upper->name);
253 iface_append_vlan_to_lower(cfg,
254 interfaces, vlan,
e7e6676e
VB
255 upper->lower,
256 depth);
adbb6e54
VB
257 return;
258 }
259
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);
265 return;
266 }
267
268 /* We can now search for interfaces that have our interface as an upper
269 * interface. */
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,
e7e6676e 275 interfaces, vlan, lower, depth);
adbb6e54
VB
276 }
277}
278
279void
280interfaces_helper_vlan(struct lldpd *cfg,
281 struct interfaces_device_list *interfaces)
282{
283 struct interfaces_device *iface;
284
285 TAILQ_FOREACH(iface, interfaces, next) {
0fa2254b 286 if (iface->ignore)
adbb6e54
VB
287 continue;
288 if (!(iface->type & IFACE_VLAN_T))
289 continue;
290
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",
294 iface->name);
295 iface_append_vlan_to_lower(cfg, interfaces,
e7e6676e 296 iface, iface, 0);
adbb6e54
VB
297 }
298}
299#endif
300
790752d0
VB
301/* Fill out chassis ID if not already done. Only physical interfaces are
302 * considered. */
adbb6e54
VB
303void
304interfaces_helper_chassis(struct lldpd *cfg,
305 struct interfaces_device_list *interfaces)
306{
307 struct interfaces_device *iface;
308 struct lldpd_hardware *hardware;
309 char *name = NULL;
310
a2b113ef 311 LOCAL_CHASSIS(cfg)->c_cap_enabled &=
312 ~(LLDP_CAP_BRIDGE | LLDP_CAP_WLAN | LLDP_CAP_STATION);
adbb6e54
VB
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;
318 }
a2b113ef 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;
adbb6e54
VB
322
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 */
326
327 TAILQ_FOREACH(iface, interfaces, next) {
790752d0 328 if (!(iface->type & IFACE_PHYSICAL_T)) continue;
adbb6e54
VB
329 if (cfg->g_config.c_cid_pattern &&
330 !pattern_match(iface->name, cfg->g_config.c_cid_pattern, 0)) continue;
331
332 if ((hardware = lldpd_get_hardware(cfg,
333 iface->name,
334 iface->index,
335 NULL)) == NULL)
336 /* That's odd. Let's skip. */
337 continue;
338
ed409ccd 339 name = malloc(ETHER_ADDR_LEN);
adbb6e54
VB
340 if (!name) {
341 log_warn("interfaces", "not enough memory for chassis ID");
342 return;
343 }
344 free(LOCAL_CHASSIS(cfg)->c_id);
ed409ccd 345 memcpy(name, hardware->h_lladdr, ETHER_ADDR_LEN);
adbb6e54 346 LOCAL_CHASSIS(cfg)->c_id = name;
ed409ccd 347 LOCAL_CHASSIS(cfg)->c_id_len = ETHER_ADDR_LEN;
adbb6e54
VB
348 LOCAL_CHASSIS(cfg)->c_id_subtype = LLDP_CHASSISID_SUBTYPE_LLADDR;
349 return;
350 }
351}
352
0c6a1966 353#undef IN_IS_ADDR_LOOPBACK
adbb6e54 354#define IN_IS_ADDR_LOOPBACK(a) ((a)->s_addr == htonl(INADDR_LOOPBACK))
0c6a1966 355#undef IN_IS_ADDR_ANY
c3e340b6 356#define IN_IS_ADDR_ANY(a) ((a)->s_addr == htonl(INADDR_ANY))
4b67a7b2
VB
357#undef IN_IS_ADDR_LINKLOCAL
358#define IN_IS_ADDR_LINKLOCAL(a) (((a)->s_addr & htonl(0xffff0000)) == htonl(0xa9fe0000))
0c6a1966 359#undef IN_IS_ADDR_GLOBAL
4b67a7b2 360#define IN_IS_ADDR_GLOBAL(a) (!IN_IS_ADDR_LOOPBACK(a) && !IN_IS_ADDR_ANY(a) && !IN_IS_ADDR_LINKLOCAL(a))
0c6a1966 361#undef IN6_IS_ADDR_GLOBAL
adbb6e54
VB
362#define IN6_IS_ADDR_GLOBAL(a) \
363 (!IN6_IS_ADDR_LOOPBACK(a) && !IN6_IS_ADDR_LINKLOCAL(a))
adbb6e54 364
63d2c3f8
VB
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.*.
369*/
370static int
371interfaces_helper_mgmt_for_af(struct lldpd *cfg,
372 int af,
373 struct interfaces_address_list *addrs,
374 int global, int allnegative)
375{
376 struct interfaces_address *addr;
377 struct lldpd_mgmt *mgmt;
378 char addrstrbuf[INET6_ADDRSTRLEN];
379 int found = 0;
380 void *sin_addr_ptr;
381 size_t sin_addr_size;
382
383 TAILQ_FOREACH(addr, addrs, next) {
384 if (addr->address.ss_family != lldpd_af(af))
385 continue;
386
387 switch (af) {
388 case LLDPD_AF_IPV4:
389 sin_addr_ptr = &((struct sockaddr_in *)&addr->address)->sin_addr;
390 sin_addr_size = sizeof(struct in_addr);
391 if (global) {
392 if (!IN_IS_ADDR_GLOBAL((struct in_addr *)sin_addr_ptr))
393 continue;
394 } else {
395 if (!IN_IS_ADDR_LINKLOCAL((struct in_addr *)sin_addr_ptr))
396 continue;
397 }
398 break;
399 case LLDPD_AF_IPV6:
400 sin_addr_ptr = &((struct sockaddr_in6 *)&addr->address)->sin6_addr;
401 sin_addr_size = sizeof(struct in6_addr);
402 if (global) {
403 if (!IN6_IS_ADDR_GLOBAL((struct in6_addr *)sin_addr_ptr))
404 continue;
405 } else {
406 if (!IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)sin_addr_ptr))
407 continue;
408 }
409 break;
410 default:
411 assert(0);
412 continue;
413 }
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");
417 continue;
418 }
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,
422 addr->index);
423 if (mgmt == NULL) {
424 assert(errno == ENOMEM); /* anything else is a bug */
425 log_warn("interfaces", "out of memory error");
426 return found;
427 }
428 log_debug("interfaces", "add management address %s", addrstrbuf);
429 TAILQ_INSERT_TAIL(&LOCAL_CHASSIS(cfg)->c_mgmt, mgmt, m_entries);
430 found = 1;
431
432 /* Don't take additional address if the pattern is all negative. */
433 if (allnegative) break;
434 }
435 }
436 return found;
437}
438
adbb6e54
VB
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). */
443void
444interfaces_helper_mgmt(struct lldpd *cfg,
445 struct interfaces_address_list *addrs)
446{
adbb6e54 447 int allnegative = 0;
63d2c3f8 448 int af;
abfea7d0 449 const char *pattern = cfg->g_config.c_mgmt_pattern;
adbb6e54
VB
450
451 lldpd_chassis_mgmt_cleanup(LOCAL_CHASSIS(cfg));
1c2217aa
AA
452 if (!cfg->g_config.c_mgmt_advertise)
453 return;
adbb6e54 454
abfea7d0
VB
455 /* Is the pattern provided an actual IP address? */
456 if (pattern && strpbrk(pattern, "!,*?") == NULL) {
457 struct in6_addr addr;
458 size_t addr_size;
459 for (af = LLDPD_AF_UNSPEC + 1;
460 af != LLDPD_AF_LAST; af++) {
461 switch (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;
464 default: assert(0);
465 }
466 if (inet_pton(lldpd_af(af), pattern, &addr) == 1)
467 break;
468 }
469 if (af == LLDPD_AF_LAST) {
470 log_debug("interfaces",
471 "interface management pattern is an incorrect IP");
472 } else {
473 struct lldpd_mgmt *mgmt;
474 mgmt = lldpd_alloc_mgmt(af, &addr, addr_size, 0);
475 if (mgmt == NULL) {
476 log_warn("interfaces", "out of memory error");
477 return;
478 }
479 log_debug("interfaces", "add exact management address %s",
480 pattern);
481 TAILQ_INSERT_TAIL(&LOCAL_CHASSIS(cfg)->c_mgmt, mgmt, m_entries);
482 }
483 return;
484 }
485
adbb6e54 486 /* Is the pattern provided all negative? */
abfea7d0
VB
487 if (pattern == NULL) allnegative = 1;
488 else if (pattern[0] == '!') {
adbb6e54
VB
489 /* If each comma is followed by '!', its an all
490 negative pattern */
abfea7d0 491 const char *sep = pattern;
adbb6e54
VB
492 while ((sep = strchr(sep, ',')) &&
493 (*(++sep) == '!'));
494 if (sep == NULL) allnegative = 1;
495 }
496
497 /* Find management addresses */
498 for (af = LLDPD_AF_UNSPEC + 1; af != LLDPD_AF_LAST; af++) {
63d2c3f8
VB
499 (void)(interfaces_helper_mgmt_for_af(cfg, af, addrs, 1, allnegative) ||
500 interfaces_helper_mgmt_for_af(cfg, af, addrs, 0, allnegative));
adbb6e54
VB
501 }
502}
503
504/* Fill up port name and description */
505void
8fbd3195
ST
506interfaces_helper_port_name_desc(struct lldpd *cfg,
507 struct lldpd_hardware *hardware,
adbb6e54
VB
508 struct interfaces_device *iface)
509{
510 struct lldpd_port *port = &hardware->h_lport;
511
8fbd3195
ST
512 /* We need to set the portid to what the client configured.
513 This can be done from the CLI.
adbb6e54 514 */
a403df66
VB
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",
522 hardware->h_ifname);
523 port->p_id_subtype = LLDP_PORTID_SUBTYPE_IFNAME;
524 port->p_id_len = strlen(hardware->h_ifname);
525 free(port->p_id);
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);
529 }
8fbd3195 530
8fbd3195
ST
531 /* use the actual alias in the port description */
532 log_debug("interfaces", "using alias in description for %s",
533 hardware->h_ifname);
4db5e8c6 534 free(port->p_descr);
a403df66
VB
535 if (has_alias) {
536 port->p_descr = strdup(iface->alias);
48eaeeb7
VB
537 } else {
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);
a403df66 541 }
8fbd3195 542 } else {
a403df66
VB
543 if (portid_type != LLDP_PORTID_SUBTYPE_LOCAL) {
544 log_debug("interfaces", "use MAC address for %s",
545 hardware->h_ifname);
546 port->p_id_subtype = LLDP_PORTID_SUBTYPE_LLADDR;
547 free(port->p_id);
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;
552 }
553
8fbd3195
ST
554 /* use the ifname in the port description until alias is set */
555 log_debug("interfaces", "using ifname in description for %s",
556 hardware->h_ifname);
4db5e8c6 557 free(port->p_descr);
adbb6e54 558 port->p_descr = strdup(hardware->h_ifname);
adbb6e54 559 }
adbb6e54
VB
560}
561
bdfe4193
VB
562void
563interfaces_helper_add_hardware(struct lldpd *cfg,
564 struct lldpd_hardware *hardware)
565{
566 TRACE(LLDPD_INTERFACES_NEW(hardware->h_ifname));
567 TAILQ_INSERT_TAIL(&cfg->g_hardware, hardware, h_entries);
568}
569
adbb6e54
VB
570void
571interfaces_helper_physical(struct lldpd *cfg,
88bc404f 572 struct interfaces_device_list *interfaces,
22e8cd65 573 struct lldpd_ops *ops,
88bc404f 574 int(*init)(struct lldpd *, struct lldpd_hardware *))
adbb6e54
VB
575{
576 struct interfaces_device *iface;
577 struct lldpd_hardware *hardware;
578
579 TAILQ_FOREACH(iface, interfaces, next) {
c6aa43e5 580 if (!(iface->type & IFACE_PHYSICAL_T)) continue;
0fa2254b 581 if (iface->ignore) continue;
adbb6e54
VB
582
583 log_debug("interfaces", "%s is an acceptable ethernet device",
584 iface->name);
585 if ((hardware = lldpd_get_hardware(cfg,
586 iface->name,
587 iface->index,
22e8cd65 588 ops)) == NULL) {
adbb6e54
VB
589 if ((hardware = lldpd_alloc_hardware(cfg,
590 iface->name,
591 iface->index)) == NULL) {
592 log_warnx("interfaces", "Unable to allocate space for %s",
593 iface->name);
594 continue;
595 }
88bc404f 596 if (init(cfg, hardware) != 0) {
e735a319 597 log_warnx("interfaces",
adbb6e54
VB
598 "unable to initialize %s",
599 hardware->h_ifname);
600 lldpd_hardware_cleanup(cfg, hardware);
601 continue;
602 }
22e8cd65 603 hardware->h_ops = ops;
7d758eec
VB
604 hardware->h_mangle = (iface->upper &&
605 iface->upper->type & IFACE_BOND_T);
bdfe4193 606 interfaces_helper_add_hardware(cfg, hardware);
adbb6e54
VB
607 } else {
608 if (hardware->h_flags) continue; /* Already seen this time */
609 lldpd_port_cleanup(&hardware->h_lport, 0);
610 }
611
612 hardware->h_flags = iface->flags; /* Should be non-zero */
0fa2254b 613 iface->ignore = 1; /* Future handlers
adbb6e54
VB
614 don't have to
615 care about this
616 interface. */
617
618 /* Get local address */
4e5f34c5 619 memcpy(&hardware->h_lladdr, iface->address, ETHER_ADDR_LEN);
adbb6e54
VB
620
621 /* Fill information about port */
8fbd3195 622 interfaces_helper_port_name_desc(cfg, hardware, iface);
adbb6e54
VB
623
624 /* Fill additional info */
625 hardware->h_mtu = iface->mtu ? iface->mtu : 1500;
d60d0bd7
VB
626
627#ifdef ENABLE_DOT3
628 if (iface->upper && iface->upper->type & IFACE_BOND_T)
629 hardware->h_lport.p_aggregid = iface->upper->index;
630#endif
adbb6e54
VB
631 }
632}
99704cd9 633
f84199dd
VB
634void
635interfaces_helper_promisc(struct lldpd *cfg,
636 struct lldpd_hardware *hardware)
637{
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",
642 hardware->h_ifname);
643 }
644}
645
99704cd9 646/**
5347914e 647 * Send the packet using the hardware function. Optionnaly mangle the MAC address.
99704cd9
VB
648 *
649 * With bonds, we have duplicate MAC address on different physical
5347914e
VB
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.
99704cd9 653 */
5347914e
VB
654int
655interfaces_send_helper(struct lldpd *cfg,
656 struct lldpd_hardware *hardware,
657 char *buffer, size_t size)
99704cd9 658{
5347914e
VB
659 if (size < 2 * ETHER_ADDR_LEN) {
660 log_warnx("interfaces",
661 "packet to send on %s is too small!",
662 hardware->h_ifname);
663 return 0;
664 }
665 if (hardware->h_mangle) {
99704cd9 666#define MAC_UL_ADMINISTERED_BIT_MASK 0x02
5347914e
VB
667 char *src_mac = buffer + ETHER_ADDR_LEN;
668 char arbitrary[] = { 0x00, 0x60, 0x08, 0x69, 0x97, 0xef};
669
670 switch (cfg->g_config.c_bond_slave_src_mac_type) {
671 case LLDP_BOND_SLAVE_SRC_MAC_TYPE_LOCALLY_ADMINISTERED:
c6d4d322
VB
672 if (!(*src_mac & MAC_UL_ADMINISTERED_BIT_MASK)) {
673 *src_mac |= MAC_UL_ADMINISTERED_BIT_MASK;
5347914e
VB
674 break;
675 }
c6d4d322 676 /* Fallback to fixed value */
5347914e
VB
677 case LLDP_BOND_SLAVE_SRC_MAC_TYPE_FIXED:
678 memcpy(src_mac, arbitrary, ETHER_ADDR_LEN);
679 break;
680 case LLDP_BOND_SLAVE_SRC_MAC_TYPE_ZERO:
99704cd9 681 memset(src_mac, 0, ETHER_ADDR_LEN);
5347914e 682 break;
99704cd9 683 }
99704cd9 684 }
5347914e 685 return hardware->h_ops->send(cfg, hardware, buffer, size);
99704cd9 686}