Coverage Report

Created: 2026-07-15 06:54

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