Coverage Report

Created: 2026-04-09 06:36

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/lldpd/src/daemon/lldpd.c
Line
Count
Source
1
/* -*- mode: c; c-file-style: "openbsd" -*- */
2
/*
3
 * Copyright (c) 2008 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 <stdio.h>
22
#include <unistd.h>
23
#include <errno.h>
24
#include <limits.h>
25
#include <signal.h>
26
#include <sys/stat.h>
27
#include <fcntl.h>
28
#include <time.h>
29
#include <libgen.h>
30
#include <assert.h>
31
#include <sys/param.h>
32
#include <sys/utsname.h>
33
#include <sys/types.h>
34
#include <sys/wait.h>
35
#include <sys/socket.h>
36
#include <sys/select.h>
37
#include <sys/time.h>
38
#include <sys/ioctl.h>
39
#include <arpa/inet.h>
40
#include <netinet/if_ether.h>
41
#include <pwd.h>
42
#include <grp.h>
43
44
#if HAVE_VFORK_H
45
#  include <vfork.h>
46
#endif
47
#if HAVE_WORKING_FORK
48
#  define vfork fork
49
#endif
50
51
static void usage(void);
52
53
static struct protocol protos[] = {
54
  { LLDPD_MODE_LLDP, 1, "LLDP", 'l', lldp_send, lldp_decode, NULL,
55
      { LLDP_ADDR_NEAREST_BRIDGE, LLDP_ADDR_NEAREST_NONTPMR_BRIDGE,
56
    LLDP_ADDR_NEAREST_CUSTOMER_BRIDGE } },
57
#ifdef ENABLE_CDP
58
  { LLDPD_MODE_CDPV1, 0, "CDPv1", 'c', cdpv1_send, cdp_decode, cdpv1_guess,
59
      { CDP_MULTICAST_ADDR } },
60
  { LLDPD_MODE_CDPV2, 0, "CDPv2", 'c', cdpv2_send, cdp_decode, cdpv2_guess,
61
      { CDP_MULTICAST_ADDR } },
62
#endif
63
#ifdef ENABLE_SONMP
64
  { LLDPD_MODE_SONMP, 0, "SONMP", 's', sonmp_send, sonmp_decode, NULL,
65
      { SONMP_MULTICAST_ADDR } },
66
#endif
67
#ifdef ENABLE_EDP
68
  { LLDPD_MODE_EDP, 0, "EDP", 'e', edp_send, edp_decode, NULL,
69
      { EDP_MULTICAST_ADDR } },
70
#endif
71
#ifdef ENABLE_FDP
72
  { LLDPD_MODE_FDP, 0, "FDP", 'f', fdp_send, cdp_decode, NULL,
73
      { FDP_MULTICAST_ADDR } },
74
#endif
75
  { 0, 0, "any", ' ', NULL, NULL, NULL, { { 0, 0, 0, 0, 0, 0 } } }
76
};
77
78
static char **saved_argv;
79
#ifdef HAVE___PROGNAME
80
extern const char *__progname;
81
#else
82
#  define __progname "lldpd"
83
#endif
84
85
static void
86
usage(void)
87
0
{
88
0
  fprintf(stderr, "Usage:   %s [OPTIONS ...]\n", __progname);
89
0
  fprintf(stderr, "Version: %s\n", PACKAGE_STRING);
90
91
0
  fprintf(stderr, "\n");
92
93
0
  fprintf(stderr, "-d       Do not daemonize.\n");
94
0
  fprintf(stderr, "-r       Receive-only mode\n");
95
0
  fprintf(stderr, "-i       Disable LLDP-MED inventory TLV transmission.\n");
96
0
  fprintf(stderr,
97
0
      "-k       Disable advertising of kernel release, version, machine.\n");
98
0
  fprintf(stderr, "-S descr Override the default system description.\n");
99
0
  fprintf(stderr, "-P name  Override the default hardware platform.\n");
100
0
  fprintf(stderr,
101
0
      "-m IP    Specify the IP management addresses of this system.\n");
102
0
  fprintf(stderr,
103
0
      "-u file  Specify the Unix-domain socket used for communication with lldpctl(8).\n");
104
0
  fprintf(stderr,
105
0
      "-H mode  Specify the behaviour when detecting multiple neighbors.\n");
106
0
  fprintf(stderr, "-I iface Limit interfaces to use.\n");
107
0
  fprintf(stderr, "-C iface Limit interfaces to use for computing chassis ID.\n");
108
0
  fprintf(stderr, "-L path  Override path for lldpcli command.\n");
109
0
  fprintf(stderr,
110
0
      "-O file  Override default configuration locations processed by lldpcli(8) at start.\n");
111
0
#ifdef ENABLE_LLDPMED
112
0
  fprintf(stderr,
113
0
      "-M class Enable emission of LLDP-MED frames. 'class' should be one of:\n");
114
0
  fprintf(stderr, "             1 Generic Endpoint (Class I)\n");
115
0
  fprintf(stderr, "             2 Media Endpoint (Class II)\n");
116
0
  fprintf(stderr, "             3 Communication Device Endpoints (Class III)\n");
117
0
  fprintf(stderr, "             4 Network Connectivity Device\n");
118
0
#endif
119
#ifdef USE_SNMP
120
  fprintf(stderr, "-x       Enable SNMP subagent.\n");
121
  fprintf(stderr, "-X sock  Specify the SNMP subagent socket.\n");
122
#endif
123
0
  fprintf(stderr, "\n");
124
125
0
#if defined ENABLE_CDP || defined ENABLE_EDP || defined ENABLE_FDP || \
126
0
    defined ENABLE_SONMP
127
0
  fprintf(stderr, "Additional protocol support.\n");
128
0
#  ifdef ENABLE_CDP
129
0
  fprintf(stderr, "-c       Enable the support of CDP protocol. (Cisco)\n");
130
0
#  endif
131
0
#  ifdef ENABLE_EDP
132
0
  fprintf(stderr, "-e       Enable the support of EDP protocol. (Extreme)\n");
133
0
#  endif
134
0
#  ifdef ENABLE_FDP
135
0
  fprintf(stderr, "-f       Enable the support of FDP protocol. (Foundry)\n");
136
0
#  endif
137
0
#  ifdef ENABLE_SONMP
138
0
  fprintf(stderr, "-s       Enable the support of SONMP protocol. (Nortel)\n");
139
0
#  endif
140
141
0
  fprintf(stderr, "\n");
142
0
#endif
143
144
0
  fprintf(stderr, "See manual page lldpd(8) for more information\n");
145
0
  exit(1);
146
0
}
147
148
struct lldpd_hardware *
149
lldpd_get_hardware(struct lldpd *cfg, char *name, int index)
150
0
{
151
0
  struct lldpd_hardware *hardware;
152
0
  TAILQ_FOREACH (hardware, &cfg->g_hardware, h_entries) {
153
0
    if (strcmp(hardware->h_ifname, name) == 0) {
154
0
      if (hardware->h_flags == 0) {
155
0
        if (hardware->h_ifindex != 0 &&
156
0
            hardware->h_ifindex != index) {
157
0
          log_debug("interfaces",
158
0
              "%s changed index: from %d to %d",
159
0
              hardware->h_ifname, hardware->h_ifindex,
160
0
              index);
161
0
          hardware->h_ifindex_changed = 1;
162
0
        }
163
0
        hardware->h_ifindex = index;
164
0
        break;
165
0
      }
166
0
      if (hardware->h_ifindex == index) break;
167
0
    }
168
0
  }
169
0
  return hardware;
170
0
}
171
172
/**
173
 * Allocate the default local port. This port will be cloned each time we need a
174
 * new local port.
175
 */
176
static void
177
lldpd_alloc_default_local_port(struct lldpd *cfg)
178
0
{
179
0
  struct lldpd_port *port;
180
0
181
0
  if ((port = (struct lldpd_port *)calloc(1, sizeof(struct lldpd_port))) == NULL)
182
0
    fatal("main", NULL);
183
0
184
0
#ifdef ENABLE_DOT1
185
0
  TAILQ_INIT(&port->p_vlans);
186
0
  TAILQ_INIT(&port->p_ppvids);
187
0
  TAILQ_INIT(&port->p_pids);
188
0
#endif
189
0
#ifdef ENABLE_CUSTOM
190
0
  TAILQ_INIT(&port->p_custom_list);
191
0
#endif
192
0
  cfg->g_default_local_port = port;
193
0
}
194
195
/**
196
 * Clone a given port. The destination needs to be already allocated.
197
 */
198
static int
199
lldpd_clone_port(struct lldpd_port *destination, struct lldpd_port *source)
200
0
{
201
202
0
  u_int8_t *output = NULL;
203
0
  ssize_t output_len;
204
0
  struct lldpd_port *cloned = NULL;
205
0
  output_len = lldpd_port_serialize(source, (void **)&output);
206
0
  if (output_len == -1 ||
207
0
      lldpd_port_unserialize(output, output_len, &cloned) <= 0) {
208
0
    log_warnx("alloc", "unable to clone default port");
209
0
    free(output);
210
0
    return -1;
211
0
  }
212
0
  memcpy(destination, cloned, sizeof(struct lldpd_port));
213
0
  free(cloned);
214
0
  free(output);
215
0
#ifdef ENABLE_DOT1
216
0
  marshal_repair_tailq(lldpd_vlan, &destination->p_vlans, v_entries);
217
0
  marshal_repair_tailq(lldpd_ppvid, &destination->p_ppvids, p_entries);
218
0
  marshal_repair_tailq(lldpd_pi, &destination->p_pids, p_entries);
219
0
#endif
220
0
#ifdef ENABLE_CUSTOM
221
0
  marshal_repair_tailq(lldpd_custom, &destination->p_custom_list, next);
222
0
#endif
223
0
  return 0;
224
0
}
225
226
struct lldpd_hardware *
227
lldpd_alloc_hardware(struct lldpd *cfg, char *name, int index)
228
0
{
229
0
  struct lldpd_hardware *hardware;
230
231
0
  log_debug("alloc", "allocate a new local port (%s)", name);
232
233
0
  if ((hardware = (struct lldpd_hardware *)calloc(1,
234
0
     sizeof(struct lldpd_hardware))) == NULL)
235
0
    return NULL;
236
237
  /* Clone default local port */
238
0
  if (lldpd_clone_port(&hardware->h_lport, cfg->g_default_local_port) == -1) {
239
0
    log_warnx("alloc", "unable to clone default port");
240
0
    free(hardware);
241
0
    return NULL;
242
0
  }
243
244
0
  hardware->h_cfg = cfg;
245
0
  strlcpy(hardware->h_ifname, name, sizeof(hardware->h_ifname));
246
0
  hardware->h_ifindex = index;
247
0
  hardware->h_lport.p_chassis = LOCAL_CHASSIS(cfg);
248
0
  hardware->h_lport.p_chassis->c_refcount++;
249
0
  TAILQ_INIT(&hardware->h_rports);
250
251
0
#ifdef ENABLE_LLDPMED
252
0
  if (LOCAL_CHASSIS(cfg)->c_med_cap_available) {
253
0
    hardware->h_lport.p_med_cap_enabled = LLDP_MED_CAP_CAP;
254
0
    if (!cfg->g_config.c_noinventory)
255
0
      hardware->h_lport.p_med_cap_enabled |= LLDP_MED_CAP_IV;
256
0
  }
257
0
#endif
258
259
0
  levent_hardware_init(hardware);
260
0
  return hardware;
261
0
}
262
263
struct lldpd_mgmt *
264
lldpd_alloc_mgmt(int family, void *addrptr, size_t addrsize, u_int32_t iface)
265
1.26k
{
266
1.26k
  struct lldpd_mgmt *mgmt;
267
268
1.26k
  log_debug("alloc", "allocate a new management address (family: %d)", family);
269
270
1.26k
  if (family <= LLDPD_AF_UNSPEC || family >= LLDPD_AF_LAST) {
271
0
    errno = EAFNOSUPPORT;
272
0
    return NULL;
273
0
  }
274
1.26k
  if (addrsize > LLDPD_MGMT_MAXADDRSIZE) {
275
13
    errno = EOVERFLOW;
276
13
    return NULL;
277
13
  }
278
1.24k
  mgmt = calloc(1, sizeof(struct lldpd_mgmt));
279
1.24k
  if (mgmt == NULL) {
280
0
    errno = ENOMEM;
281
0
    return NULL;
282
0
  }
283
1.24k
  mgmt->m_family = family;
284
1.24k
  memcpy(&mgmt->m_addr, addrptr, addrsize);
285
1.24k
  mgmt->m_addrsize = addrsize;
286
1.24k
  mgmt->m_iface = iface;
287
1.24k
  return mgmt;
288
1.24k
}
289
290
void
291
lldpd_hardware_cleanup(struct lldpd *cfg, struct lldpd_hardware *hardware)
292
0
{
293
0
  log_debug("alloc", "cleanup hardware port %s", hardware->h_ifname);
294
295
0
  free(hardware->h_lport_previous);
296
0
  free(hardware->h_lchassis_previous_id);
297
0
  free(hardware->h_lport_previous_id);
298
0
  free(hardware->h_ifdescr_previous);
299
0
  free(hardware->h_ifalias);
300
0
  lldpd_port_cleanup(&hardware->h_lport, 1);
301
0
  if (hardware->h_ops && hardware->h_ops->cleanup)
302
0
    hardware->h_ops->cleanup(cfg, hardware);
303
0
  levent_hardware_release(hardware);
304
0
  free(hardware);
305
0
}
306
307
static void
308
lldpd_ifdescr_neighbors(struct lldpd *cfg)
309
0
{
310
0
  if (!cfg->g_config.c_set_ifdescr) return;
311
0
  struct lldpd_hardware *hardware;
312
0
  TAILQ_FOREACH (hardware, &cfg->g_hardware, h_entries) {
313
0
    struct lldpd_port *port;
314
0
    char *description;
315
0
    const char *neighbor = NULL;
316
0
    unsigned neighbors = 0;
317
0
    TAILQ_FOREACH (port, &hardware->h_rports, p_entries) {
318
0
      if (SMART_HIDDEN(port)) continue;
319
0
      neighbors++;
320
0
      neighbor = port->p_chassis->c_name;
321
0
    }
322
0
    if (neighbors == 0)
323
0
      description = strdup("");
324
0
    else if (neighbors == 1 && neighbor && *neighbor != '\0') {
325
0
      if (asprintf(&description, "%s", neighbor) == -1) {
326
0
        continue;
327
0
      }
328
0
    } else {
329
0
      if (asprintf(&description, "%d neighbor%s", neighbors,
330
0
        (neighbors > 1) ? "s" : "") == -1) {
331
0
        continue;
332
0
      }
333
0
    }
334
0
    if (hardware->h_ifdescr_previous == NULL ||
335
0
        strcmp(hardware->h_ifdescr_previous, description)) {
336
0
      priv_iface_description(hardware->h_ifname, description);
337
0
      free(hardware->h_ifdescr_previous);
338
0
      hardware->h_ifdescr_previous = description;
339
0
    } else
340
0
      free(description);
341
0
  }
342
0
}
343
344
static void
345
lldpd_count_neighbors(struct lldpd *cfg)
346
0
{
347
#if HAVE_SETPROCTITLE
348
  struct lldpd_chassis *chassis;
349
  const char *neighbor;
350
  unsigned neighbors = 0;
351
  TAILQ_FOREACH (chassis, &cfg->g_chassis, c_entries) {
352
    neighbors++;
353
    neighbor = chassis->c_name;
354
  }
355
  neighbors--;
356
  if (neighbors == 0)
357
    setproctitle("no neighbor.");
358
  else if (neighbors == 1 && neighbor && *neighbor != '\0')
359
    setproctitle("connected to %s.", neighbor);
360
  else
361
    setproctitle("%d neighbor%s.", neighbors, (neighbors > 1) ? "s" : "");
362
#endif
363
0
  lldpd_ifdescr_neighbors(cfg);
364
0
}
365
366
static void
367
notify_clients_deletion(struct lldpd_hardware *hardware, struct lldpd_port *rport)
368
0
{
369
0
  TRACE(LLDPD_NEIGHBOR_DELETE(hardware->h_ifname, rport->p_chassis->c_name,
370
0
      rport->p_descr));
371
0
  levent_ctl_notify(hardware->h_ifname, hardware->h_ifalias, NEIGHBOR_CHANGE_DELETED, rport);
372
#ifdef USE_SNMP
373
  agent_notify(hardware, NEIGHBOR_CHANGE_DELETED, rport);
374
#endif
375
0
}
376
377
static void
378
lldpd_reset_timer(struct lldpd *cfg)
379
0
{
380
  /* Reset timer for ports that have been changed. */
381
0
  struct lldpd_hardware *hardware;
382
0
  TAILQ_FOREACH (hardware, &cfg->g_hardware, h_entries) {
383
    /* We keep a flat copy of the local port to see if there is any
384
     * change. To do this, we zero out fields that are not
385
     * significant, marshal the port, then restore. */
386
0
    struct lldpd_port *port = &hardware->h_lport;
387
    /* Take the current flags into account to detect a change. */
388
0
    port->_p_hardware_flags = hardware->h_flags;
389
0
    u_int8_t *output = NULL;
390
0
    ssize_t output_len;
391
0
    char save[LLDPD_PORT_START_MARKER];
392
0
    memcpy(save, port, sizeof(save));
393
    /* coverity[sizeof_mismatch]
394
       We intentionally partially memset port */
395
0
    memset(port, 0, sizeof(save));
396
0
    output_len = lldpd_port_serialize(port, (void **)&output);
397
0
    memcpy(port, save, sizeof(save));
398
0
    if (output_len == -1) {
399
0
      log_warnx("localchassis",
400
0
          "unable to serialize local port %s to check for differences",
401
0
          hardware->h_ifname);
402
0
      continue;
403
0
    }
404
405
    /* Compare with the previous value */
406
0
    if (!hardware->h_ifindex_changed && hardware->h_lport_previous &&
407
0
        output_len == hardware->h_lport_previous_len &&
408
0
        !memcmp(output, hardware->h_lport_previous, output_len)) {
409
0
      log_debug("localchassis", "no change detected for port %s",
410
0
          hardware->h_ifname);
411
0
    } else {
412
0
      log_debug("localchassis",
413
0
          "change detected for port %s, resetting its timer",
414
0
          hardware->h_ifname);
415
0
      hardware->h_ifindex_changed = 0;
416
0
      levent_schedule_pdu(hardware);
417
0
    }
418
419
    /* Update the value */
420
0
    free(hardware->h_lport_previous);
421
0
    hardware->h_lport_previous = output;
422
0
    hardware->h_lport_previous_len = output_len;
423
0
  }
424
0
}
425
426
static void
427
lldpd_all_chassis_cleanup(struct lldpd *cfg)
428
0
{
429
0
  struct lldpd_chassis *chassis, *chassis_next;
430
0
  log_debug("localchassis", "cleanup all chassis");
431
432
0
  for (chassis = TAILQ_FIRST(&cfg->g_chassis); chassis; chassis = chassis_next) {
433
0
    chassis_next = TAILQ_NEXT(chassis, c_entries);
434
0
    if (chassis->c_refcount == 0) {
435
0
      TAILQ_REMOVE(&cfg->g_chassis, chassis, c_entries);
436
0
      lldpd_chassis_cleanup(chassis, 1);
437
0
    }
438
0
  }
439
0
}
440
441
void
442
lldpd_cleanup(struct lldpd *cfg)
443
0
{
444
0
  struct lldpd_hardware *hardware, *hardware_next;
445
446
0
  log_debug("localchassis", "cleanup all ports");
447
448
0
  for (hardware = TAILQ_FIRST(&cfg->g_hardware); hardware != NULL;
449
0
       hardware = hardware_next) {
450
0
    hardware_next = TAILQ_NEXT(hardware, h_entries);
451
0
    if (!hardware->h_flags) {
452
0
      int m = cfg->g_config.c_perm_ifaces ?
453
0
          pattern_match(hardware->h_ifname,
454
0
        cfg->g_config.c_perm_ifaces, 0) :
455
0
          0;
456
0
      switch (m) {
457
0
      case PATTERN_MATCH_DENIED:
458
0
        log_debug("localchassis",
459
0
            "delete non-permanent interface %s",
460
0
            hardware->h_ifname);
461
0
        TRACE(LLDPD_INTERFACES_DELETE(hardware->h_ifname));
462
0
        TAILQ_REMOVE(&cfg->g_hardware, hardware, h_entries);
463
0
        lldpd_remote_cleanup(hardware, notify_clients_deletion,
464
0
            1);
465
0
        lldpd_hardware_cleanup(cfg, hardware);
466
0
        break;
467
0
      case PATTERN_MATCH_ALLOWED:
468
0
      case PATTERN_MATCH_ALLOWED_EXACT:
469
0
        log_debug("localchassis", "do not delete %s, permanent",
470
0
            hardware->h_ifname);
471
0
        lldpd_remote_cleanup(hardware, notify_clients_deletion,
472
0
            1);
473
0
        break;
474
0
      }
475
0
    } else {
476
0
      lldpd_remote_cleanup(hardware, notify_clients_deletion,
477
0
          !(hardware->h_flags & IFF_RUNNING));
478
0
    }
479
0
  }
480
481
0
  levent_schedule_cleanup(cfg);
482
0
  lldpd_all_chassis_cleanup(cfg);
483
0
  lldpd_count_neighbors(cfg);
484
0
}
485
486
/* Update chassis `ochassis' with values from `chassis'. The later one is not
487
   expected to be part of a list! It will also be wiped from memory. */
488
static void
489
lldpd_move_chassis(struct lldpd_chassis *ochassis, struct lldpd_chassis *chassis)
490
0
{
491
0
  struct lldpd_mgmt *mgmt, *mgmt_next;
492
493
  /* We want to keep refcount, index and list stuff from the current
494
   * chassis */
495
0
  TAILQ_ENTRY(lldpd_chassis) entries;
496
0
  int refcount = ochassis->c_refcount;
497
0
  int index = ochassis->c_index;
498
0
  memcpy(&entries, &ochassis->c_entries, sizeof(entries));
499
0
  lldpd_chassis_cleanup(ochassis, 0);
500
501
  /* Make the copy. */
502
  /* WARNING: this is a kludgy hack, we need in-place copy and cannot use
503
   * marshaling. */
504
0
  memcpy(ochassis, chassis, sizeof(struct lldpd_chassis));
505
0
  TAILQ_INIT(&ochassis->c_mgmt);
506
507
  /* Copy of management addresses */
508
0
  for (mgmt = TAILQ_FIRST(&chassis->c_mgmt); mgmt != NULL; mgmt = mgmt_next) {
509
0
    mgmt_next = TAILQ_NEXT(mgmt, m_entries);
510
0
    TAILQ_REMOVE(&chassis->c_mgmt, mgmt, m_entries);
511
0
    TAILQ_INSERT_TAIL(&ochassis->c_mgmt, mgmt, m_entries);
512
0
  }
513
514
  /* Restore saved values */
515
0
  ochassis->c_refcount = refcount;
516
0
  ochassis->c_index = index;
517
0
  memcpy(&ochassis->c_entries, &entries, sizeof(entries));
518
519
  /* Get rid of the new chassis */
520
0
  free(chassis);
521
0
}
522
523
static int
524
lldpd_guess_type(struct lldpd *cfg, char *frame, int s)
525
0
{
526
0
  size_t i, j;
527
0
  if (s < ETHER_ADDR_LEN) return -1;
528
0
  for (i = 0; cfg->g_protocols[i].mode != 0; i++) {
529
0
    if (!cfg->g_protocols[i].enabled) continue;
530
0
    if (cfg->g_protocols[i].guess == NULL) {
531
0
      for (j = 0; j < sizeof(cfg->g_protocols[0].mac) /
532
0
         sizeof(cfg->g_protocols[0].mac[0]);
533
0
           j++) {
534
0
        if (memcmp(frame, cfg->g_protocols[i].mac[j],
535
0
          ETHER_ADDR_LEN) == 0) {
536
0
          log_debug("decode",
537
0
              "guessed protocol is %s (from MAC address)",
538
0
              cfg->g_protocols[i].name);
539
0
          return cfg->g_protocols[i].mode;
540
0
        }
541
0
      }
542
0
    } else {
543
0
      if (cfg->g_protocols[i].guess(frame, s)) {
544
0
        log_debug("decode",
545
0
            "guessed protocol is %s (from detector function)",
546
0
            cfg->g_protocols[i].name);
547
0
        return cfg->g_protocols[i].mode;
548
0
      }
549
0
    }
550
0
  }
551
0
  return -1;
552
0
}
553
554
static void
555
lldpd_decode(struct lldpd *cfg, char *frame, int s, struct lldpd_hardware *hardware)
556
0
{
557
0
  int i;
558
0
  struct lldpd_chassis *chassis, *ochassis = NULL;
559
0
  struct lldpd_port *port, *oport = NULL, *aport;
560
0
  int guess = LLDPD_MODE_LLDP;
561
562
0
  log_debug("decode", "decode a received frame on %s", hardware->h_ifname);
563
564
0
  if (s < sizeof(struct ether_header) + 4) {
565
    /* Too short, just discard it */
566
0
    hardware->h_rx_discarded_cnt++;
567
0
    return;
568
0
  }
569
570
  /* Decapsulate VLAN frames */
571
0
  struct ether_header eheader;
572
0
  memcpy(&eheader, frame, sizeof(struct ether_header));
573
0
  if (eheader.ether_type == htons(ETHERTYPE_VLAN)) {
574
    /* VLAN decapsulation means to shift 4 bytes left the frame from
575
     * offset 2*ETHER_ADDR_LEN */
576
0
    memmove(frame + 2 * ETHER_ADDR_LEN, frame + 2 * ETHER_ADDR_LEN + 4,
577
0
        s - 2 * ETHER_ADDR_LEN);
578
0
    s -= 4;
579
0
  }
580
581
0
  TAILQ_FOREACH (oport, &hardware->h_rports, p_entries) {
582
0
    if ((oport->p_lastframe != NULL) && (oport->p_lastframe->size == s) &&
583
0
        (memcmp(oport->p_lastframe->frame, frame, s) == 0)) {
584
      /* Already received the same frame */
585
0
      log_debug("decode", "duplicate frame, no need to decode");
586
0
      oport->p_lastupdate = time(NULL);
587
0
      return;
588
0
    }
589
0
  }
590
591
0
  guess = lldpd_guess_type(cfg, frame, s);
592
0
  for (i = 0; cfg->g_protocols[i].mode != 0; i++) {
593
0
    if (!cfg->g_protocols[i].enabled) continue;
594
0
    if (cfg->g_protocols[i].mode == guess) {
595
0
      log_debug("decode", "using decode function for %s protocol",
596
0
          cfg->g_protocols[i].name);
597
0
      if (cfg->g_protocols[i].decode(cfg, frame, s, hardware,
598
0
        &chassis, &port) == -1) {
599
0
        log_debug("decode",
600
0
            "function for %s protocol did not decode this frame",
601
0
            cfg->g_protocols[i].name);
602
0
        hardware->h_rx_discarded_cnt++;
603
0
        return;
604
0
      }
605
0
      chassis->c_protocol = port->p_protocol =
606
0
          cfg->g_protocols[i].mode;
607
0
      break;
608
0
    }
609
0
  }
610
0
  if (cfg->g_protocols[i].mode == 0) {
611
0
    log_debug("decode", "unable to guess frame type on %s",
612
0
        hardware->h_ifname);
613
0
    return;
614
0
  }
615
0
  TRACE(LLDPD_FRAME_DECODED(hardware->h_ifname, cfg->g_protocols[i].name,
616
0
      chassis->c_name, port->p_descr));
617
618
  /* Do we already have the same MSAP somewhere? */
619
0
  int count = 0;
620
0
  log_debug("decode", "search for the same MSAP");
621
0
  TAILQ_FOREACH (oport, &hardware->h_rports, p_entries) {
622
0
    if (port->p_protocol == oport->p_protocol) {
623
0
      count++;
624
0
      if ((port->p_id_subtype == oport->p_id_subtype) &&
625
0
          (port->p_id_len == oport->p_id_len) &&
626
0
          (memcmp(port->p_id, oport->p_id, port->p_id_len) == 0) &&
627
0
          (chassis->c_id_subtype == oport->p_chassis->c_id_subtype) &&
628
0
          (chassis->c_id_len == oport->p_chassis->c_id_len) &&
629
0
          (memcmp(chassis->c_id, oport->p_chassis->c_id,
630
0
         chassis->c_id_len) == 0)) {
631
0
        ochassis = oport->p_chassis;
632
0
        log_debug("decode", "MSAP is already known");
633
0
        break;
634
0
      }
635
0
    }
636
0
  }
637
  /* Do we have room for a new MSAP? */
638
0
  if (!oport && cfg->g_config.c_max_neighbors) {
639
0
    if (count == (cfg->g_config.c_max_neighbors - 1)) {
640
0
      log_debug("decode",
641
0
          "max neighbors %d reached for port %s, "
642
0
          "dropping any new ones silently",
643
0
          cfg->g_config.c_max_neighbors, hardware->h_ifname);
644
0
    } else if (count > cfg->g_config.c_max_neighbors - 1) {
645
0
      log_debug("decode",
646
0
          "too many neighbors for port %s, drop this new one",
647
0
          hardware->h_ifname);
648
0
      lldpd_port_cleanup(port, 1);
649
0
      lldpd_chassis_cleanup(chassis, 1);
650
0
      free(port);
651
0
      return;
652
0
    }
653
0
  }
654
  /* No, but do we already know the system? */
655
0
  if (!oport) {
656
0
    log_debug("decode", "MSAP is unknown, search for the chassis");
657
0
    TAILQ_FOREACH (ochassis, &cfg->g_chassis, c_entries) {
658
0
      if ((chassis->c_protocol == ochassis->c_protocol) &&
659
0
          (chassis->c_id_subtype == ochassis->c_id_subtype) &&
660
0
          (chassis->c_id_len == ochassis->c_id_len) &&
661
0
          (memcmp(chassis->c_id, ochassis->c_id, chassis->c_id_len) ==
662
0
        0))
663
0
        break;
664
0
    }
665
0
  }
666
667
0
  if (oport) {
668
    /* The port is known, remove it before adding it back */
669
0
    TAILQ_REMOVE(&hardware->h_rports, oport, p_entries);
670
0
    lldpd_port_cleanup(oport, 1);
671
0
    free(oport);
672
0
  }
673
0
  if (ochassis) {
674
0
    if (port->p_ttl == 0) {
675
      /* Shutdown LLDPDU is special. We do not want to replace
676
       * the chassis. Free the new chassis (which is mostly empty) */
677
0
      log_debug("decode", "received a shutdown LLDPDU");
678
0
      lldpd_chassis_cleanup(chassis, 1);
679
0
    } else {
680
0
      lldpd_move_chassis(ochassis, chassis);
681
0
    }
682
0
    chassis = ochassis;
683
0
  } else {
684
    /* Chassis not known, add it */
685
0
    log_debug("decode", "unknown chassis, add it to the list");
686
0
    chassis->c_index = ++cfg->g_lastrid;
687
0
    chassis->c_refcount = 0;
688
0
    TAILQ_INSERT_TAIL(&cfg->g_chassis, chassis, c_entries);
689
0
    i = 0;
690
0
    TAILQ_FOREACH (ochassis, &cfg->g_chassis, c_entries)
691
0
      i++;
692
0
    log_debug("decode", "%d different systems are known", i);
693
0
  }
694
  /* Add port */
695
0
  port->p_lastchange = port->p_lastupdate = time(NULL);
696
0
  if ((port->p_lastframe = (struct lldpd_frame *)malloc(
697
0
     s + sizeof(struct lldpd_frame))) != NULL) {
698
0
    port->p_lastframe->size = s;
699
0
    memcpy(port->p_lastframe->frame, frame, s);
700
0
  }
701
0
  TAILQ_INSERT_TAIL(&hardware->h_rports, port, p_entries);
702
0
  port->p_chassis = chassis;
703
0
  port->p_chassis->c_refcount++;
704
  /* Several cases are possible :
705
       1. chassis is new, its refcount was 0. It is now attached
706
    to this port, its refcount is 1.
707
       2. chassis already exists and was attached to another
708
    port, we increase its refcount accordingly.
709
       3. chassis already exists and was attached to the same
710
    port, its refcount was decreased with
711
    lldpd_port_cleanup() and is now increased again.
712
713
     In all cases, if the port already existed, it has been
714
     freed with lldpd_port_cleanup() and therefore, the refcount
715
     of the chassis that was attached to it is decreased.
716
  */
717
0
  i = 0;
718
  /* coverity[use_after_free]
719
     TAILQ_REMOVE does the right thing */
720
0
  TAILQ_FOREACH (aport, &hardware->h_rports, p_entries)
721
0
    i++;
722
0
  log_debug("decode", "%d neighbors for %s", i, hardware->h_ifname);
723
724
0
  if (!oport) hardware->h_insert_cnt++;
725
726
  /* Notify */
727
0
  log_debug("decode", "send notifications for changes on %s", hardware->h_ifname);
728
0
  if (oport) {
729
0
    TRACE(LLDPD_NEIGHBOR_UPDATE(hardware->h_ifname, chassis->c_name,
730
0
        port->p_descr, i));
731
0
    levent_ctl_notify(hardware->h_ifname, hardware->h_ifalias, NEIGHBOR_CHANGE_UPDATED, port);
732
#ifdef USE_SNMP
733
    agent_notify(hardware, NEIGHBOR_CHANGE_UPDATED, port);
734
#endif
735
0
  } else {
736
0
    TRACE(LLDPD_NEIGHBOR_NEW(hardware->h_ifname, chassis->c_name,
737
0
        port->p_descr, i));
738
0
    levent_ctl_notify(hardware->h_ifname, hardware->h_ifalias, NEIGHBOR_CHANGE_ADDED, port);
739
#ifdef USE_SNMP
740
    agent_notify(hardware, NEIGHBOR_CHANGE_ADDED, port);
741
#endif
742
0
  }
743
744
0
  if (!oport) {
745
    /* New neighbor, fast start */
746
0
    if (hardware->h_cfg->g_config.c_enable_fast_start &&
747
0
        !hardware->h_tx_fast) {
748
0
      log_debug("decode",
749
0
          "%s: entering fast start due to "
750
0
          "new neighbor",
751
0
          hardware->h_ifname);
752
0
      hardware->h_tx_fast = hardware->h_cfg->g_config.c_tx_fast_init;
753
0
    }
754
755
0
    levent_schedule_pdu(hardware);
756
0
  }
757
758
0
  return;
759
0
}
760
761
/* Get the output of lsb_release -s -d.  This is a slow function. It should be
762
   called once. It return NULL if any problem happens. Otherwise, this is a
763
   statically allocated buffer. The result includes the trailing \n  */
764
static char *
765
lldpd_get_lsb_release()
766
0
{
767
0
  static char release[1024];
768
0
  char cmd[][12] = { "lsb_release", "-s", "-d" };
769
0
  char *const command[] = { cmd[0], cmd[1], cmd[2], NULL };
770
0
  int pid, status, devnull, count;
771
0
  int pipefd[2];
772
0
773
0
  log_debug("localchassis", "grab LSB release");
774
0
775
0
  if (pipe(pipefd)) {
776
0
    log_warn("localchassis", "unable to get a pair of pipes");
777
0
    return NULL;
778
0
  }
779
0
780
0
  pid = vfork();
781
0
  switch (pid) {
782
0
  case -1:
783
0
    log_warn("localchassis", "unable to fork");
784
0
    return NULL;
785
0
  case 0:
786
0
    /* Child, exec lsb_release */
787
0
    close(pipefd[0]);
788
0
    if ((devnull = open("/dev/null", O_RDWR, 0)) != -1) {
789
0
      dup2(devnull, STDIN_FILENO);
790
0
      dup2(devnull, STDERR_FILENO);
791
0
      dup2(pipefd[1], STDOUT_FILENO);
792
0
      if (devnull > 2) close(devnull);
793
0
      if (pipefd[1] > 2) close(pipefd[1]);
794
0
      execvp("lsb_release", command);
795
0
    }
796
0
    _exit(127);
797
0
    break;
798
0
  default:
799
0
    /* Father, read the output from the children */
800
0
    close(pipefd[1]);
801
0
    count = 0;
802
0
    do {
803
0
      status =
804
0
          read(pipefd[0], release + count, sizeof(release) - count);
805
0
      if ((status == -1) && (errno == EINTR)) continue;
806
0
      if (status > 0) count += status;
807
0
    } while (count < sizeof(release) && (status > 0));
808
0
    if (status < 0) {
809
0
      log_info("localchassis", "unable to read from lsb_release");
810
0
      close(pipefd[0]);
811
0
      waitpid(pid, &status, 0);
812
0
      return NULL;
813
0
    }
814
0
    close(pipefd[0]);
815
0
    if (count >= sizeof(release)) {
816
0
      log_info("localchassis", "output of lsb_release is too large");
817
0
      waitpid(pid, &status, 0);
818
0
      return NULL;
819
0
    }
820
0
    status = -1;
821
0
    if (waitpid(pid, &status, 0) != pid) return NULL;
822
0
    if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) {
823
0
      log_info("localchassis",
824
0
          "lsb_release information not available");
825
0
      return NULL;
826
0
    }
827
0
    if (!count) {
828
0
      log_info("localchassis",
829
0
          "lsb_release returned an empty string");
830
0
      return NULL;
831
0
    }
832
0
    release[count] = '\0';
833
0
    return release;
834
0
  }
835
0
  /* Should not be here */
836
0
  return NULL;
837
0
}
838
839
/* Same like lldpd_get_lsb_release but reads /etc/os-release for PRETTY_NAME=. */
840
static char *
841
lldpd_get_os_release()
842
0
{
843
0
  static char release[1024];
844
0
  char line[1024];
845
0
  char *key, *val;
846
0
  char *ptr1 = release;
847
0
848
0
  log_debug("localchassis", "grab OS release");
849
0
  FILE *fp = fopen("/etc/os-release", "r");
850
0
  if (!fp) {
851
0
    log_debug("localchassis", "could not open /etc/os-release");
852
0
    fp = fopen("/usr/lib/os-release", "r");
853
0
  }
854
0
  if (!fp) {
855
0
    log_info("localchassis",
856
0
        "could not open either /etc/os-release or /usr/lib/os-release");
857
0
    return NULL;
858
0
  }
859
0
860
0
  while ((fgets(line, sizeof(line), fp) != NULL)) {
861
0
    key = strtok(line, "=");
862
0
    if (key == NULL) continue;
863
0
864
0
    val = strtok(NULL, "=");
865
0
    if (val == NULL) continue;
866
0
867
0
    if (strncmp(key, "PRETTY_NAME", sizeof(line)) == 0) {
868
0
      strlcpy(release, val, sizeof(line));
869
0
      break;
870
0
    }
871
0
  }
872
0
  fclose(fp);
873
0
874
0
  /* Remove trailing newline and all " in the string. */
875
0
  ptr1 = release + strlen(release);
876
0
  while (ptr1 != release && ((*ptr1 == '"') || (*ptr1 == '\n') || (*ptr1 == '\0'))) {
877
0
    *ptr1 = '\0';
878
0
    ptr1--;
879
0
  }
880
0
  if (release[0] == '"') return release + 1;
881
0
  return release;
882
0
}
883
884
static void
885
lldpd_hide_ports(struct lldpd *cfg, struct lldpd_hardware *hardware, int mask)
886
0
{
887
0
  struct lldpd_port *port;
888
0
  int protocols[LLDPD_MODE_MAX + 1];
889
0
  char buffer[256];
890
0
  int i, j, k, found;
891
0
  unsigned int min;
892
893
0
  log_debug("smartfilter", "apply smart filter for port %s", hardware->h_ifname);
894
895
  /* Compute the number of occurrences of each protocol */
896
0
  for (i = 0; i <= LLDPD_MODE_MAX; i++)
897
0
    protocols[i] = 0;
898
0
  TAILQ_FOREACH (port, &hardware->h_rports, p_entries)
899
0
    protocols[port->p_protocol]++;
900
901
  /* Turn the protocols[] array into an array of
902
     enabled/disabled protocols. 1 means enabled, 0
903
     means disabled. */
904
0
  min = (unsigned int)-1;
905
0
  for (i = 0; i <= LLDPD_MODE_MAX; i++)
906
0
    if (protocols[i] && (protocols[i] < min)) min = protocols[i];
907
0
  found = 0;
908
0
  for (i = 0; i <= LLDPD_MODE_MAX; i++)
909
0
    if ((protocols[i] == min) && !found) {
910
      /* If we need a tie breaker, we take
911
         the first protocol only */
912
0
      if (cfg->g_config.c_smart & mask &
913
0
          (SMART_OUTGOING_ONE_PROTO | SMART_INCOMING_ONE_PROTO))
914
0
        found = 1;
915
0
      protocols[i] = 1;
916
0
    } else
917
0
      protocols[i] = 0;
918
919
  /* We set the p_hidden flag to 1 if the protocol is disabled */
920
0
  TAILQ_FOREACH (port, &hardware->h_rports, p_entries) {
921
0
    if (mask == SMART_OUTGOING)
922
0
      port->p_hidden_out = protocols[port->p_protocol] ? 0 : 1;
923
0
    else
924
0
      port->p_hidden_in = protocols[port->p_protocol] ? 0 : 1;
925
0
  }
926
927
  /* If we want only one neighbor, we take the first one */
928
0
  if (cfg->g_config.c_smart & mask &
929
0
      (SMART_OUTGOING_ONE_NEIGH | SMART_INCOMING_ONE_NEIGH)) {
930
0
    found = 0;
931
0
    TAILQ_FOREACH (port, &hardware->h_rports, p_entries) {
932
0
      if (mask == SMART_OUTGOING) {
933
0
        if (found) port->p_hidden_out = 1;
934
0
        if (!port->p_hidden_out) found = 1;
935
0
      }
936
0
      if (mask == SMART_INCOMING) {
937
0
        if (found) port->p_hidden_in = 1;
938
0
        if (!port->p_hidden_in) found = 1;
939
0
      }
940
0
    }
941
0
  }
942
943
  /* Print a debug message summarizing the operation */
944
0
  for (i = 0; i <= LLDPD_MODE_MAX; i++)
945
0
    protocols[i] = 0;
946
0
  k = j = 0;
947
0
  TAILQ_FOREACH (port, &hardware->h_rports, p_entries) {
948
0
    if (!(((mask == SMART_OUTGOING) && port->p_hidden_out) ||
949
0
      ((mask == SMART_INCOMING) && port->p_hidden_in))) {
950
0
      k++;
951
0
      protocols[port->p_protocol] = 1;
952
0
    }
953
0
    j++;
954
0
  }
955
0
  buffer[0] = '\0';
956
0
  for (i = 0; cfg->g_protocols[i].mode != 0; i++) {
957
0
    if (cfg->g_protocols[i].enabled &&
958
0
        protocols[cfg->g_protocols[i].mode]) {
959
0
      if (strlen(buffer) + strlen(cfg->g_protocols[i].name) + 3 >
960
0
          sizeof(buffer)) {
961
        /* Unlikely, our buffer is too small */
962
0
        memcpy(buffer + sizeof(buffer) - 4, "...", 4);
963
0
        break;
964
0
      }
965
0
      if (buffer[0])
966
0
        strncat(buffer, ", ",
967
0
            sizeof(buffer) - strlen(buffer) - 1);
968
0
      strncat(buffer, cfg->g_protocols[i].name,
969
0
          sizeof(buffer) - strlen(buffer) - 1);
970
0
    }
971
0
  }
972
0
  log_debug("smartfilter", "%s: %s: %d visible neighbors (out of %d)",
973
0
      hardware->h_ifname, (mask == SMART_OUTGOING) ? "out filter" : "in filter",
974
0
      k, j);
975
0
  log_debug("smartfilter", "%s: protocols: %s", hardware->h_ifname,
976
0
      buffer[0] ? buffer : "(none)");
977
0
}
978
979
/* Hide unwanted ports depending on smart mode set by the user */
980
static void
981
lldpd_hide_all(struct lldpd *cfg)
982
0
{
983
0
  struct lldpd_hardware *hardware;
984
985
0
  if (!cfg->g_config.c_smart) return;
986
0
  log_debug("smartfilter", "apply smart filter results on all ports");
987
0
  TAILQ_FOREACH (hardware, &cfg->g_hardware, h_entries) {
988
0
    if (cfg->g_config.c_smart & SMART_INCOMING_FILTER)
989
0
      lldpd_hide_ports(cfg, hardware, SMART_INCOMING);
990
0
    if (cfg->g_config.c_smart & SMART_OUTGOING_FILTER)
991
0
      lldpd_hide_ports(cfg, hardware, SMART_OUTGOING);
992
0
  }
993
0
}
994
995
/* If PD device and PSE allocated power, echo back this change. If we have
996
 * several LLDP neighbors, we use the latest updated. */
997
static void
998
lldpd_dot3_power_pd_pse(struct lldpd_hardware *hardware)
999
0
{
1000
0
#ifdef ENABLE_DOT3
1001
0
  struct lldpd_port *port, *selected_port = NULL;
1002
  /* Are we a PD device? */
1003
0
  if (hardware->h_lport.p_power.devicetype != LLDP_DOT3_POWER_PD) return;
1004
0
  TAILQ_FOREACH (port, &hardware->h_rports, p_entries) {
1005
0
    if (port->p_hidden_in) continue;
1006
1007
0
    if (port->p_protocol != LLDPD_MODE_LLDP &&
1008
0
        port->p_protocol != LLDPD_MODE_CDPV2)
1009
0
      continue;
1010
1011
0
    if (port->p_power.devicetype != LLDP_DOT3_POWER_PSE) continue;
1012
0
    if (!selected_port || port->p_lastupdate > selected_port->p_lastupdate)
1013
0
      selected_port = port;
1014
0
  }
1015
0
  if (selected_port &&
1016
0
      selected_port->p_power.allocated != hardware->h_lport.p_power.allocated) {
1017
0
    log_info("receive",
1018
0
        "for %s, PSE told us allocated is now %d instead of %d",
1019
0
        hardware->h_ifname, selected_port->p_power.allocated,
1020
0
        hardware->h_lport.p_power.allocated);
1021
0
    hardware->h_lport.p_power.allocated = selected_port->p_power.allocated;
1022
0
    levent_schedule_pdu(hardware);
1023
0
  }
1024
1025
0
#  ifdef ENABLE_CDP
1026
0
  if (selected_port &&
1027
0
      selected_port->p_cdp_power.management_id !=
1028
0
    hardware->h_lport.p_cdp_power.management_id) {
1029
0
    hardware->h_lport.p_cdp_power.management_id =
1030
0
        selected_port->p_cdp_power.management_id;
1031
0
  }
1032
0
#  endif
1033
1034
0
#endif
1035
0
}
1036
1037
void
1038
lldpd_recv(struct lldpd *cfg, struct lldpd_hardware *hardware, int fd)
1039
0
{
1040
0
  char *buffer = NULL;
1041
0
  int n;
1042
0
  log_debug("receive", "receive a frame on %s", hardware->h_ifname);
1043
0
  if ((buffer = (char *)malloc(hardware->h_mtu)) == NULL) {
1044
0
    log_warn("receive", "failed to alloc reception buffer");
1045
0
    return;
1046
0
  }
1047
0
  if ((n = hardware->h_ops->recv(cfg, hardware, fd, buffer, hardware->h_mtu)) ==
1048
0
      -1) {
1049
0
    log_debug("receive", "discard frame received on %s",
1050
0
        hardware->h_ifname);
1051
0
    free(buffer);
1052
0
    return;
1053
0
  }
1054
0
  if (hardware->h_lport.p_disable_rx) {
1055
0
    log_debug("receive", "RX disabled, ignore the frame on %s",
1056
0
        hardware->h_ifname);
1057
0
    free(buffer);
1058
0
    return;
1059
0
  }
1060
0
  if (cfg->g_config.c_paused) {
1061
0
    log_debug("receive", "paused, ignore the frame on %s",
1062
0
        hardware->h_ifname);
1063
0
    free(buffer);
1064
0
    return;
1065
0
  }
1066
0
  hardware->h_rx_cnt++;
1067
0
  log_debug("receive", "decode received frame on %s", hardware->h_ifname);
1068
0
  TRACE(LLDPD_FRAME_RECEIVED(hardware->h_ifname, buffer, (size_t)n));
1069
0
  lldpd_decode(cfg, buffer, n, hardware);
1070
0
  lldpd_hide_all(cfg); /* Immediately hide */
1071
0
  lldpd_dot3_power_pd_pse(hardware);
1072
0
  lldpd_count_neighbors(cfg);
1073
0
  free(buffer);
1074
0
}
1075
1076
static void
1077
lldpd_send_shutdown(struct lldpd_hardware *hardware)
1078
0
{
1079
0
  struct lldpd *cfg = hardware->h_cfg;
1080
0
  if (cfg->g_config.c_receiveonly || cfg->g_config.c_paused) return;
1081
0
  if (hardware->h_lport.p_disable_tx) return;
1082
0
  if ((hardware->h_flags & IFF_RUNNING) == 0) return;
1083
0
1084
0
  /* It's safe to call `lldp_send_shutdown()` because shutdown LLDPU will
1085
0
   * only be emitted if LLDP was sent on that port. */
1086
0
  if (lldp_send_shutdown(hardware->h_cfg, hardware) != 0)
1087
0
    log_warnx("send", "unable to send shutdown LLDPDU on %s",
1088
0
        hardware->h_ifname);
1089
0
}
1090
1091
void
1092
lldpd_send(struct lldpd_hardware *hardware)
1093
0
{
1094
0
  struct lldpd *cfg = hardware->h_cfg;
1095
0
  struct lldpd_port *port;
1096
0
  int i, sent;
1097
1098
0
  if (cfg->g_config.c_receiveonly || cfg->g_config.c_paused) return;
1099
0
  if (hardware->h_lport.p_disable_tx) return;
1100
0
  if ((hardware->h_flags & IFF_RUNNING) == 0) return;
1101
1102
0
  log_debug("send", "send PDU on %s", hardware->h_ifname);
1103
0
  sent = 0;
1104
0
  for (i = 0; cfg->g_protocols[i].mode != 0; i++) {
1105
0
    if (!cfg->g_protocols[i].enabled) continue;
1106
    /* We send only if we have at least one remote system
1107
     * speaking this protocol or if the protocol is forced */
1108
0
    if (cfg->g_protocols[i].enabled > 1) {
1109
0
      cfg->g_protocols[i].send(cfg, hardware);
1110
0
      sent++;
1111
0
      continue;
1112
0
    }
1113
0
    TAILQ_FOREACH (port, &hardware->h_rports, p_entries) {
1114
      /* If this remote port is disabled, we don't
1115
       * consider it */
1116
0
      if (port->p_hidden_out) continue;
1117
0
      if (port->p_protocol == cfg->g_protocols[i].mode) {
1118
0
        TRACE(LLDPD_FRAME_SEND(hardware->h_ifname,
1119
0
            cfg->g_protocols[i].name));
1120
0
        log_debug("send", "send PDU on %s with protocol %s",
1121
0
            hardware->h_ifname, cfg->g_protocols[i].name);
1122
0
        cfg->g_protocols[i].send(cfg, hardware);
1123
0
        hardware->h_lport.p_protocol = cfg->g_protocols[i].mode;
1124
0
        sent++;
1125
0
        break;
1126
0
      }
1127
0
    }
1128
0
  }
1129
1130
0
  if (!sent) {
1131
    /* Nothing was sent for this port, let's speak the first
1132
     * available protocol. */
1133
0
    for (i = 0; cfg->g_protocols[i].mode != 0; i++) {
1134
0
      if (!cfg->g_protocols[i].enabled) continue;
1135
0
      TRACE(LLDPD_FRAME_SEND(hardware->h_ifname,
1136
0
          cfg->g_protocols[i].name));
1137
0
      log_debug("send", "fallback to protocol %s for %s",
1138
0
          cfg->g_protocols[i].name, hardware->h_ifname);
1139
0
      cfg->g_protocols[i].send(cfg, hardware);
1140
0
      break;
1141
0
    }
1142
0
    if (cfg->g_protocols[i].mode == 0)
1143
0
      log_warnx("send", "no protocol enabled, dunno what to send");
1144
0
  }
1145
0
}
1146
1147
#ifdef ENABLE_LLDPMED
1148
static void
1149
lldpd_med(struct lldpd *cfg, struct utsname *un)
1150
0
{
1151
0
  static short int once = 0;
1152
0
  if (!once && cfg) {
1153
0
    LOCAL_CHASSIS(cfg)->c_med_hw = dmi_hw();
1154
0
    LOCAL_CHASSIS(cfg)->c_med_fw = dmi_fw();
1155
0
    LOCAL_CHASSIS(cfg)->c_med_sn = dmi_sn();
1156
0
    LOCAL_CHASSIS(cfg)->c_med_manuf = dmi_manuf();
1157
0
    LOCAL_CHASSIS(cfg)->c_med_model = dmi_model();
1158
0
    LOCAL_CHASSIS(cfg)->c_med_asset = dmi_asset();
1159
0
    if (un) {
1160
0
      if (LOCAL_CHASSIS(cfg)->c_med_sw)
1161
0
        free(LOCAL_CHASSIS(cfg)->c_med_sw);
1162
1163
0
      if (cfg->g_config.c_advertise_version)
1164
0
        LOCAL_CHASSIS(cfg)->c_med_sw = strdup(un->release);
1165
0
      else
1166
0
        LOCAL_CHASSIS(cfg)->c_med_sw = strdup("Unknown");
1167
0
    }
1168
0
    once = 1;
1169
0
  }
1170
0
}
1171
#endif
1172
1173
static int
1174
lldpd_routing_enabled(struct lldpd *cfg)
1175
0
{
1176
0
  int routing;
1177
1178
0
  if ((LOCAL_CHASSIS(cfg)->c_cap_available & LLDP_CAP_ROUTER) == 0) return 0;
1179
1180
0
  if ((routing = interfaces_routing_enabled(cfg)) == -1) {
1181
0
    log_debug("localchassis", "unable to check if routing is enabled");
1182
0
    return 0;
1183
0
  }
1184
0
  return routing;
1185
0
}
1186
1187
void
1188
lldpd_update_localchassis(struct lldpd *cfg)
1189
0
{
1190
0
  struct utsname un;
1191
0
  char *hp;
1192
1193
0
  log_debug("localchassis", "update information for local chassis");
1194
0
  assert(LOCAL_CHASSIS(cfg) != NULL);
1195
1196
  /* Set system name and description */
1197
0
  if (uname(&un) < 0) fatal("localchassis", "failed to get system information");
1198
0
  if (cfg->g_config.c_hostname) {
1199
0
    log_debug("localchassis", "use overridden system name `%s`",
1200
0
        cfg->g_config.c_hostname);
1201
0
    hp = cfg->g_config.c_hostname;
1202
0
  } else {
1203
0
    if ((hp = priv_gethostname()) == NULL)
1204
0
      fatal("localchassis", "failed to get system name");
1205
0
  }
1206
0
  free(LOCAL_CHASSIS(cfg)->c_name);
1207
0
  free(LOCAL_CHASSIS(cfg)->c_descr);
1208
0
  if ((LOCAL_CHASSIS(cfg)->c_name = strdup(hp)) == NULL)
1209
0
    fatal("localchassis", NULL);
1210
0
  if (cfg->g_config.c_description) {
1211
0
    log_debug("localchassis", "use overridden description `%s`",
1212
0
        cfg->g_config.c_description);
1213
0
    if (asprintf(&LOCAL_CHASSIS(cfg)->c_descr, "%s",
1214
0
      cfg->g_config.c_description) == -1)
1215
0
      fatal("localchassis", "failed to set full system description");
1216
0
  } else {
1217
0
    if (cfg->g_config.c_advertise_version) {
1218
0
      log_debug("localchassis", "advertise system version");
1219
0
      if (asprintf(&LOCAL_CHASSIS(cfg)->c_descr, "%s %s %s %s %s",
1220
0
        cfg->g_lsb_release ? cfg->g_lsb_release : "",
1221
0
        un.sysname, un.release, un.version, un.machine) == -1)
1222
0
        fatal("localchassis",
1223
0
            "failed to set full system description");
1224
0
    } else {
1225
0
      log_debug("localchassis", "do not advertise system version");
1226
0
      if (asprintf(&LOCAL_CHASSIS(cfg)->c_descr, "%s",
1227
0
        cfg->g_lsb_release ? cfg->g_lsb_release : un.sysname) ==
1228
0
          -1)
1229
0
        fatal("localchassis",
1230
0
            "failed to set minimal system description");
1231
0
    }
1232
0
  }
1233
0
  if (cfg->g_config.c_platform == NULL)
1234
0
    cfg->g_config.c_platform = strdup(un.sysname);
1235
1236
0
  if (!cfg->g_config.c_cap_override) {
1237
    /* Check routing */
1238
0
    if (lldpd_routing_enabled(cfg)) {
1239
0
      log_debug("localchassis",
1240
0
          "routing is enabled, enable router capability");
1241
0
      LOCAL_CHASSIS(cfg)->c_cap_enabled |= LLDP_CAP_ROUTER;
1242
0
    } else
1243
0
      LOCAL_CHASSIS(cfg)->c_cap_enabled &= ~LLDP_CAP_ROUTER;
1244
1245
0
#ifdef ENABLE_LLDPMED
1246
0
    if (LOCAL_CHASSIS(cfg)->c_cap_available & LLDP_CAP_TELEPHONE)
1247
0
      LOCAL_CHASSIS(cfg)->c_cap_enabled |= LLDP_CAP_TELEPHONE;
1248
0
    lldpd_med(cfg, &un);
1249
0
#endif
1250
0
    if ((LOCAL_CHASSIS(cfg)->c_cap_available & LLDP_CAP_STATION) &&
1251
0
        (LOCAL_CHASSIS(cfg)->c_cap_enabled == 0))
1252
0
      LOCAL_CHASSIS(cfg)->c_cap_enabled = LLDP_CAP_STATION;
1253
0
    else if (LOCAL_CHASSIS(cfg)->c_cap_enabled != LLDP_CAP_STATION)
1254
0
      LOCAL_CHASSIS(cfg)->c_cap_enabled &= ~LLDP_CAP_STATION;
1255
0
  }
1256
1257
  /* Set chassis ID if needed. This is only done if chassis ID
1258
     has not been set previously (with the MAC address of an
1259
     interface for example)
1260
  */
1261
0
  if (cfg->g_config.c_cid_string != NULL) {
1262
0
    log_debug("localchassis", "use specified chassis ID string");
1263
0
    free(LOCAL_CHASSIS(cfg)->c_id);
1264
0
    if (!(LOCAL_CHASSIS(cfg)->c_id = strdup(cfg->g_config.c_cid_string)))
1265
0
      fatal("localchassis", NULL);
1266
0
    LOCAL_CHASSIS(cfg)->c_id_len = strlen(cfg->g_config.c_cid_string);
1267
0
    LOCAL_CHASSIS(cfg)->c_id_subtype = LLDP_CHASSISID_SUBTYPE_LOCAL;
1268
0
  }
1269
0
  if (LOCAL_CHASSIS(cfg)->c_id == NULL) {
1270
0
    log_debug("localchassis",
1271
0
        "no chassis ID is currently set, use chassis name");
1272
0
    if (!(LOCAL_CHASSIS(cfg)->c_id = strdup(LOCAL_CHASSIS(cfg)->c_name)))
1273
0
      fatal("localchassis", NULL);
1274
0
    LOCAL_CHASSIS(cfg)->c_id_len = strlen(LOCAL_CHASSIS(cfg)->c_name);
1275
0
    LOCAL_CHASSIS(cfg)->c_id_subtype = LLDP_CHASSISID_SUBTYPE_LOCAL;
1276
0
  }
1277
0
}
1278
1279
void
1280
lldpd_update_localports(struct lldpd *cfg)
1281
0
{
1282
0
  struct lldpd_hardware *hardware;
1283
1284
0
  log_debug("localchassis", "update information for local ports");
1285
1286
  /* h_flags is set to 0 for each port. If the port is updated, h_flags
1287
   * will be set to a non-zero value. This will allow us to clean up any
1288
   * non up-to-date port */
1289
0
  TAILQ_FOREACH (hardware, &cfg->g_hardware, h_entries)
1290
0
    hardware->h_flags = 0;
1291
1292
0
  TRACE(LLDPD_INTERFACES_UPDATE());
1293
0
  interfaces_update(cfg);
1294
0
  lldpd_cleanup(cfg);
1295
0
  lldpd_reset_timer(cfg);
1296
0
}
1297
1298
void
1299
lldpd_loop(struct lldpd *cfg)
1300
0
{
1301
  /* Main loop.
1302
     1. Update local ports information
1303
     2. Update local chassis information
1304
  */
1305
0
  log_debug("loop", "start new loop");
1306
0
  if (!cfg->g_config.c_cap_override) LOCAL_CHASSIS(cfg)->c_cap_enabled = 0;
1307
  /* Information for local ports is triggered even when it is possible to
1308
   * update them on some other event because we want to refresh them if we
1309
   * missed something. */
1310
0
  log_debug("loop", "update information for local ports");
1311
0
  lldpd_update_localports(cfg);
1312
0
  log_debug("loop", "update information for local chassis");
1313
0
  lldpd_update_localchassis(cfg);
1314
0
  lldpd_count_neighbors(cfg);
1315
0
}
1316
1317
static void
1318
lldpd_exit(struct lldpd *cfg)
1319
0
{
1320
0
  struct lldpd_hardware *hardware, *hardware_next;
1321
0
  log_debug("main", "exit lldpd");
1322
0
1323
0
  TAILQ_FOREACH (hardware, &cfg->g_hardware, h_entries)
1324
0
    lldpd_send_shutdown(hardware);
1325
0
1326
0
  close(cfg->g_ctl);
1327
0
  priv_ctl_cleanup();
1328
0
  log_debug("main", "cleanup hardware information");
1329
0
  for (hardware = TAILQ_FIRST(&cfg->g_hardware); hardware != NULL;
1330
0
       hardware = hardware_next) {
1331
0
    hardware_next = TAILQ_NEXT(hardware, h_entries);
1332
0
    log_debug("main", "cleanup interface %s", hardware->h_ifname);
1333
0
    lldpd_remote_cleanup(hardware, NULL, 1);
1334
0
    lldpd_hardware_cleanup(cfg, hardware);
1335
0
  }
1336
0
  interfaces_cleanup(cfg);
1337
0
  lldpd_port_cleanup(cfg->g_default_local_port, 1);
1338
0
  lldpd_all_chassis_cleanup(cfg);
1339
0
  free(cfg->g_default_local_port);
1340
0
  free(cfg->g_config.c_platform);
1341
0
  levent_shutdown(cfg);
1342
0
}
1343
1344
/**
1345
 * Run lldpcli to configure lldpd.
1346
 *
1347
 * @return PID of running lldpcli or -1 if error.
1348
 */
1349
static pid_t
1350
lldpd_configure(int use_syslog, int debug, const char *path, const char *ctlname,
1351
    const char *config_path)
1352
0
{
1353
0
  pid_t lldpcli = vfork();
1354
0
  int devnull;
1355
0
1356
0
  char sdebug[debug + 4];
1357
0
  if (use_syslog)
1358
0
    strlcpy(sdebug, "-s", 3);
1359
0
  else {
1360
0
    /* debug = 0 -> -sd */
1361
0
    /* debug = 1 -> -sdd */
1362
0
    /* debug = 2 -> -sddd */
1363
0
    memset(sdebug, 'd', sizeof(sdebug));
1364
0
    sdebug[debug + 3] = '\0';
1365
0
    sdebug[0] = '-';
1366
0
    sdebug[1] = 's';
1367
0
  }
1368
0
  log_debug("main", "invoke %s %s", path, sdebug);
1369
0
1370
0
  switch (lldpcli) {
1371
0
  case -1:
1372
0
    log_warn("main", "unable to fork");
1373
0
    return -1;
1374
0
  case 0:
1375
0
    /* Child, exec lldpcli */
1376
0
    if ((devnull = open("/dev/null", O_RDWR, 0)) != -1) {
1377
0
      dup2(devnull, STDIN_FILENO);
1378
0
      dup2(devnull, STDOUT_FILENO);
1379
0
      if (devnull > 2) close(devnull);
1380
0
1381
0
      if (config_path) {
1382
0
        execl(path, "lldpcli", sdebug, "-u", ctlname, "-C",
1383
0
            config_path, "resume", (char *)NULL);
1384
0
      } else {
1385
0
        execl(path, "lldpcli", sdebug, "-u", ctlname, "-C",
1386
0
            SYSCONFDIR "/lldpd.conf", "-C",
1387
0
            SYSCONFDIR "/lldpd.d", "resume", (char *)NULL);
1388
0
      }
1389
0
1390
0
      log_warn("main", "unable to execute %s", path);
1391
0
      log_warnx("main",
1392
0
          "configuration is incomplete, lldpd needs to be unpaused");
1393
0
    }
1394
0
    _exit(127);
1395
0
    break;
1396
0
  default:
1397
0
    /* Father, don't do anything stupid */
1398
0
    return lldpcli;
1399
0
  }
1400
0
  /* Should not be here */
1401
0
  return -1;
1402
0
}
1403
1404
struct intint {
1405
  int a;
1406
  int b;
1407
};
1408
static const struct intint filters[] = { { 0, 0 },
1409
  { 1,
1410
      SMART_INCOMING_FILTER | SMART_INCOMING_ONE_PROTO | SMART_OUTGOING_FILTER |
1411
    SMART_OUTGOING_ONE_PROTO },
1412
  { 2, SMART_INCOMING_FILTER | SMART_INCOMING_ONE_PROTO },
1413
  { 3, SMART_OUTGOING_FILTER | SMART_OUTGOING_ONE_PROTO },
1414
  { 4, SMART_INCOMING_FILTER | SMART_OUTGOING_FILTER },
1415
  { 5, SMART_INCOMING_FILTER }, { 6, SMART_OUTGOING_FILTER },
1416
  { 7,
1417
      SMART_INCOMING_FILTER | SMART_INCOMING_ONE_PROTO |
1418
    SMART_INCOMING_ONE_NEIGH | SMART_OUTGOING_FILTER |
1419
    SMART_OUTGOING_ONE_PROTO },
1420
  { 8,
1421
      SMART_INCOMING_FILTER | SMART_INCOMING_ONE_PROTO |
1422
    SMART_INCOMING_ONE_NEIGH },
1423
  { 9,
1424
      SMART_INCOMING_FILTER | SMART_INCOMING_ONE_NEIGH | SMART_OUTGOING_FILTER |
1425
    SMART_OUTGOING_ONE_PROTO },
1426
  { 10, SMART_OUTGOING_FILTER | SMART_OUTGOING_ONE_NEIGH },
1427
  { 11, SMART_INCOMING_FILTER | SMART_INCOMING_ONE_NEIGH },
1428
  { 12,
1429
      SMART_INCOMING_FILTER | SMART_INCOMING_ONE_NEIGH | SMART_OUTGOING_FILTER |
1430
    SMART_OUTGOING_ONE_NEIGH },
1431
  { 13,
1432
      SMART_INCOMING_FILTER | SMART_INCOMING_ONE_NEIGH | SMART_OUTGOING_FILTER },
1433
  { 14,
1434
      SMART_INCOMING_FILTER | SMART_INCOMING_ONE_PROTO | SMART_OUTGOING_FILTER |
1435
    SMART_OUTGOING_ONE_NEIGH },
1436
  { 15,
1437
      SMART_INCOMING_FILTER | SMART_INCOMING_ONE_PROTO | SMART_OUTGOING_FILTER },
1438
  { 16,
1439
      SMART_INCOMING_FILTER | SMART_INCOMING_ONE_PROTO |
1440
    SMART_INCOMING_ONE_NEIGH | SMART_OUTGOING_FILTER |
1441
    SMART_OUTGOING_ONE_NEIGH },
1442
  { 17,
1443
      SMART_INCOMING_FILTER | SMART_INCOMING_ONE_PROTO |
1444
    SMART_INCOMING_ONE_NEIGH | SMART_OUTGOING_FILTER },
1445
  { 18,
1446
      SMART_INCOMING_FILTER | SMART_OUTGOING_FILTER | SMART_OUTGOING_ONE_NEIGH },
1447
  { 19,
1448
      SMART_INCOMING_FILTER | SMART_OUTGOING_FILTER | SMART_OUTGOING_ONE_PROTO },
1449
  { -1, 0 } };
1450
1451
#ifndef HOST_OS_OSX
1452
/**
1453
 * Tell if we have been started by systemd.
1454
 */
1455
static int
1456
lldpd_started_by_systemd()
1457
0
{
1458
0
#  ifdef HOST_OS_LINUX
1459
0
  int fd = -1;
1460
0
  int ret = 0;
1461
0
  size_t path_length;
1462
0
  union sockaddr_union {
1463
0
    struct sockaddr sa;
1464
0
    struct sockaddr_un sun;
1465
0
  } socket_addr = {
1466
0
    .sun.sun_family = AF_UNIX,
1467
0
  };
1468
0
  const char *socket_path = getenv("NOTIFY_SOCKET");
1469
0
  if (!socket_path || (socket_path[0] != '/' && socket_path[0] != '@') ||
1470
0
      (path_length = strlen(socket_path)) < 2)
1471
0
    goto done;
1472
0
1473
0
  if (path_length >= sizeof(socket_addr.sun.sun_path)) {
1474
0
    log_warnx("main", "systemd notification socket is too long");
1475
0
    goto done;
1476
0
  }
1477
0
  memcpy(socket_addr.sun.sun_path, socket_path, path_length);
1478
0
1479
0
  /* Support for abstract socket */
1480
0
  if (socket_addr.sun.sun_path[0] == '@') socket_addr.sun.sun_path[0] = 0;
1481
0
1482
0
  log_debug("main", "running with systemd, don't fork but signal ready");
1483
0
  if ((fd = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0)) < 0) {
1484
0
    log_warn("main", "unable to open systemd notification socket %s",
1485
0
        socket_path);
1486
0
    goto done;
1487
0
  }
1488
0
  if (connect(fd, &socket_addr.sa,
1489
0
    offsetof(struct sockaddr_un, sun_path) + path_length) != 0) {
1490
0
    log_warn("main", "unable to connect to systemd notification socket");
1491
0
    goto done;
1492
0
  }
1493
0
  char ready[] = "READY=1";
1494
0
  ssize_t written = write(fd, ready, sizeof ready - 1);
1495
0
  if (written != (ssize_t)sizeof ready - 1) {
1496
0
    log_warn("main", "unable to send notification to systemd");
1497
0
    goto done;
1498
0
  }
1499
0
  unsetenv("NOTIFY_SOCKET");
1500
0
  ret = 1;
1501
0
done:
1502
0
  if (fd >= 0) close(fd);
1503
0
  return ret;
1504
0
#  else
1505
0
  return 0;
1506
0
#  endif
1507
0
}
1508
#endif
1509
1510
#ifdef HOST_OS_LINUX
1511
static void
1512
version_convert(const char *sversion, unsigned iversion[], size_t n)
1513
0
{
1514
0
  const char *p = sversion;
1515
0
  char *end;
1516
0
  for (size_t i = 0; i < n; i++) {
1517
0
    iversion[i] = strtol(p, &end, 10);
1518
0
    if (*end != '.') break;
1519
0
    p = end + 1;
1520
0
  }
1521
0
}
1522
1523
static void
1524
version_check(void)
1525
0
{
1526
0
  struct utsname uts;
1527
0
  if (uname(&uts) == -1) return;
1528
0
  unsigned version_min[3] = {};
1529
0
  unsigned version_cur[3] = {};
1530
0
  version_convert(uts.release, version_cur, 3);
1531
0
  version_convert(MIN_LINUX_KERNEL_VERSION, version_min, 3);
1532
0
  if (version_min[0] > version_cur[0] ||
1533
0
      (version_min[0] == version_cur[0] && version_min[1] > version_cur[1]) ||
1534
0
      (version_min[0] == version_cur[0] && version_min[1] == version_cur[1] &&
1535
0
    version_min[2] > version_cur[2])) {
1536
0
    log_warnx("lldpd", "minimal kernel version required is %s, got %s",
1537
0
        MIN_LINUX_KERNEL_VERSION, uts.release);
1538
0
    log_warnx("lldpd",
1539
0
        "lldpd may be unable to detect bonds and bridges correctly");
1540
0
#  ifndef ENABLE_OLDIES
1541
0
    log_warnx("lldpd", "consider recompiling with --enable-oldies option");
1542
0
#  endif
1543
0
  }
1544
0
}
1545
#else
1546
static void
1547
version_check(void)
1548
{
1549
}
1550
#endif
1551
1552
int
1553
lldpd_main(int argc, char *argv[], char *envp[])
1554
0
{
1555
0
  struct lldpd *cfg;
1556
0
  struct lldpd_chassis *lchassis;
1557
0
  int ch, debug = 0, use_syslog = 1, daemonize = 1;
1558
0
  const char *errstr;
1559
#ifdef USE_SNMP
1560
  int snmp = 0;
1561
  const char *agentx = NULL; /* AgentX socket */
1562
#endif
1563
0
  const char *ctlname = NULL;
1564
0
  char *mgmtp = NULL;
1565
0
  char *cidp = NULL;
1566
0
  char *interfaces = NULL;
1567
  /* We do not want more options here. Please add them in lldpcli instead
1568
   * unless there is a very good reason. Most command-line options will
1569
   * get deprecated at some point. */
1570
0
  char *popt,
1571
0
      opts[] = "H:vhkrdD:p:xX:m:u:4:6:I:C:p:M:P:S:iL:O:@                    ";
1572
0
  int i, found, advertise_version = 1;
1573
0
#ifdef ENABLE_LLDPMED
1574
0
  int lldpmed = 0, noinventory = 0;
1575
0
#endif
1576
0
  int enable_fast_start = 1;
1577
0
  char *descr_override = NULL;
1578
0
  char *platform_override = NULL;
1579
0
  char *lsb_release = NULL;
1580
0
  const char *lldpcli = LLDPCLI_PATH;
1581
0
#ifndef HOST_OS_OSX
1582
0
  const char *pidfile = LLDPD_PID_FILE;
1583
0
#endif
1584
0
  int smart = 15;
1585
0
  int receiveonly = 0, version = 0;
1586
0
  int ctl;
1587
0
  const char *config_file = NULL;
1588
1589
0
#ifdef ENABLE_PRIVSEP
1590
  /* Non privileged user */
1591
0
  struct passwd *user;
1592
0
  struct group *group;
1593
0
  uid_t uid;
1594
0
  gid_t gid;
1595
0
#endif
1596
1597
0
  saved_argv = argv;
1598
1599
#if HAVE_SETPROCTITLE_INIT
1600
  setproctitle_init(argc, argv, envp);
1601
#endif
1602
1603
  /*
1604
   * Get and parse command line options
1605
   */
1606
0
  if ((popt = strchr(opts, '@')) != NULL) {
1607
0
    for (i = 0; protos[i].mode != 0 && *popt != '\0'; i++)
1608
0
      *(popt++) = protos[i].arg;
1609
0
    *popt = '\0';
1610
0
  }
1611
0
  while ((ch = getopt(argc, argv, opts)) != -1) {
1612
0
    switch (ch) {
1613
0
    case 'h':
1614
0
      usage();
1615
0
      break;
1616
0
    case 'v':
1617
0
      version++;
1618
0
      break;
1619
0
    case 'd':
1620
0
      if (daemonize)
1621
0
        daemonize = 0;
1622
0
      else if (use_syslog)
1623
0
        use_syslog = 0;
1624
0
      else
1625
0
        debug++;
1626
0
      break;
1627
0
    case 'D':
1628
0
      log_accept(optarg);
1629
0
      break;
1630
0
#ifndef HOST_OS_OSX
1631
0
    case 'p':
1632
0
      pidfile = optarg;
1633
0
      break;
1634
0
#endif
1635
0
    case 'r':
1636
0
      receiveonly = 1;
1637
0
      break;
1638
0
    case 'm':
1639
0
      if (mgmtp) {
1640
0
        fprintf(stderr, "-m can only be used once\n");
1641
0
        usage();
1642
0
      }
1643
0
      mgmtp = strdup(optarg);
1644
0
      break;
1645
0
    case 'u':
1646
0
      if (ctlname) {
1647
0
        fprintf(stderr, "-u can only be used once\n");
1648
0
        usage();
1649
0
      }
1650
0
      ctlname = optarg;
1651
0
      break;
1652
0
    case 'I':
1653
0
      if (interfaces) {
1654
0
        fprintf(stderr, "-I can only be used once\n");
1655
0
        usage();
1656
0
      }
1657
0
      interfaces = strdup(optarg);
1658
0
      break;
1659
0
    case 'C':
1660
0
      if (cidp) {
1661
0
        fprintf(stderr, "-C can only be used once\n");
1662
0
        usage();
1663
0
      }
1664
0
      cidp = strdup(optarg);
1665
0
      break;
1666
0
    case 'L':
1667
0
      if (strlen(optarg))
1668
0
        lldpcli = optarg;
1669
0
      else
1670
0
        lldpcli = NULL;
1671
0
      break;
1672
0
    case 'k':
1673
0
      advertise_version = 0;
1674
0
      break;
1675
0
#ifdef ENABLE_LLDPMED
1676
0
    case 'M':
1677
0
      lldpmed = strtonum(optarg, 1, 4, &errstr);
1678
0
      if (errstr) {
1679
0
        fprintf(stderr,
1680
0
            "-M requires an argument between 1 and 4\n");
1681
0
        usage();
1682
0
      }
1683
0
      break;
1684
0
    case 'i':
1685
0
      noinventory = 1;
1686
0
      break;
1687
#else
1688
    case 'M':
1689
    case 'i':
1690
      fprintf(stderr, "LLDP-MED support is not built-in\n");
1691
      usage();
1692
      break;
1693
#endif
1694
#ifdef USE_SNMP
1695
    case 'x':
1696
      snmp = 1;
1697
      break;
1698
    case 'X':
1699
      if (agentx) {
1700
        fprintf(stderr, "-X can only be used once\n");
1701
        usage();
1702
      }
1703
      snmp = 1;
1704
      agentx = optarg;
1705
      break;
1706
#else
1707
0
    case 'x':
1708
0
    case 'X':
1709
0
      fprintf(stderr, "SNMP support is not built-in\n");
1710
0
      usage();
1711
0
#endif
1712
0
      break;
1713
0
    case 'S':
1714
0
      if (descr_override) {
1715
0
        fprintf(stderr, "-S can only be used once\n");
1716
0
        usage();
1717
0
      }
1718
0
      descr_override = strdup(optarg);
1719
0
      break;
1720
0
    case 'P':
1721
0
      if (platform_override) {
1722
0
        fprintf(stderr, "-P can only be used once\n");
1723
0
        usage();
1724
0
      }
1725
0
      platform_override = strdup(optarg);
1726
0
      break;
1727
0
    case 'H':
1728
0
      smart = strtonum(optarg, 0,
1729
0
          sizeof(filters) / sizeof(filters[0]), &errstr);
1730
0
      if (errstr) {
1731
0
        fprintf(stderr,
1732
0
            "-H requires an int between 0 and %zu\n",
1733
0
            sizeof(filters) / sizeof(filters[0]));
1734
0
        usage();
1735
0
      }
1736
0
      break;
1737
0
    case 'O':
1738
0
      if (config_file) {
1739
0
        fprintf(stderr, "-O can only be used once\n");
1740
0
        usage();
1741
0
      }
1742
0
      config_file = optarg;
1743
0
      break;
1744
0
    default:
1745
0
      found = 0;
1746
0
      for (i = 0; protos[i].mode != 0; i++) {
1747
0
        if (ch == protos[i].arg) {
1748
0
          found = 1;
1749
0
          protos[i].enabled++;
1750
0
        }
1751
0
      }
1752
0
      if (!found) usage();
1753
0
    }
1754
0
  }
1755
1756
0
  if (version) {
1757
0
    version_display(stdout, "lldpd", version > 1);
1758
0
    exit(0);
1759
0
  }
1760
1761
0
  if (ctlname == NULL) ctlname = LLDPD_CTL_SOCKET;
1762
1763
  /* Set correct smart mode */
1764
0
  for (i = 0; (filters[i].a != -1) && (filters[i].a != smart); i++)
1765
0
    ;
1766
0
  if (filters[i].a == -1) {
1767
0
    fprintf(stderr, "Incorrect mode for -H\n");
1768
0
    usage();
1769
0
  }
1770
0
  smart = filters[i].b;
1771
1772
0
  log_init(use_syslog, debug, __progname);
1773
0
  tzset(); /* Get timezone info before chroot */
1774
0
  if (use_syslog && daemonize) {
1775
    /* So, we use syslog and we daemonize (or we are started by
1776
     * systemd). No need to continue writing to stdout. */
1777
0
    int fd;
1778
    /* coverity[resource_leak]
1779
       fd may be leaked if < 2, it's expected */
1780
0
    if ((fd = open("/dev/null", O_RDWR, 0)) != -1) {
1781
0
      dup2(fd, STDIN_FILENO);
1782
0
      dup2(fd, STDOUT_FILENO);
1783
0
      dup2(fd, STDERR_FILENO);
1784
0
      if (fd > 2) close(fd);
1785
0
    }
1786
0
  }
1787
0
  log_debug("main", "lldpd " PACKAGE_VERSION " starting...");
1788
0
  version_check();
1789
0
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
1790
0
  fatalx("main", "fuzzing enabled, unsafe for production");
1791
0
#endif
1792
1793
  /* Grab uid and gid to use for priv sep */
1794
0
#ifdef ENABLE_PRIVSEP
1795
0
  if ((user = getpwnam(PRIVSEP_USER)) == NULL)
1796
0
    fatalx("main",
1797
0
        "no " PRIVSEP_USER
1798
0
        " user for privilege separation, please create it");
1799
0
  uid = user->pw_uid;
1800
0
  if ((group = getgrnam(PRIVSEP_GROUP)) == NULL)
1801
0
    fatalx("main",
1802
0
        "no " PRIVSEP_GROUP
1803
0
        " group for privilege separation, please create it");
1804
0
  gid = group->gr_gid;
1805
0
#endif
1806
1807
  /* Create and setup socket */
1808
0
  int retry = 1;
1809
0
  log_debug("main", "creating control socket");
1810
0
  while ((ctl = ctl_create(ctlname)) == -1) {
1811
0
    if (retry-- && errno == EADDRINUSE) {
1812
      /* Check if a daemon is really listening */
1813
0
      int tfd;
1814
0
      log_info("main",
1815
0
          "unable to create control socket because it already exists");
1816
0
      log_info("main", "check if another instance is running");
1817
0
      if ((tfd = ctl_connect(ctlname)) != -1) {
1818
        /* Another instance is running */
1819
0
        close(tfd);
1820
0
        log_warnx("main",
1821
0
            "another instance is running, please stop it");
1822
0
        fatalx("main", "giving up");
1823
0
      } else if (errno == ECONNREFUSED) {
1824
        /* Nobody is listening */
1825
0
        log_info("main",
1826
0
            "old control socket is present, clean it");
1827
0
        ctl_cleanup(ctlname);
1828
0
        continue;
1829
0
      }
1830
0
      log_warn("main",
1831
0
          "cannot determine if another daemon is already running");
1832
0
      fatalx("main", "giving up");
1833
0
    }
1834
0
    log_warn("main", "unable to create control socket at %s", ctlname);
1835
0
    fatalx("main", "giving up");
1836
0
  }
1837
0
#ifdef ENABLE_PRIVSEP
1838
0
  if (chown(ctlname, uid, gid) == -1)
1839
0
    log_warn("main", "unable to chown control socket");
1840
0
  if (chmod(ctlname, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP) ==
1841
0
      -1)
1842
0
    log_warn("main", "unable to chmod control socket");
1843
0
#endif
1844
1845
  /* Create associated advisory lock file */
1846
0
  char *lockname = NULL;
1847
0
  int fd;
1848
0
  if (asprintf(&lockname, "%s.lock", ctlname) == -1)
1849
0
    fatal("main", "cannot build lock name");
1850
0
  if ((fd = open(lockname, O_CREAT | O_RDWR, 0000)) == -1)
1851
0
    fatal("main", "cannot create lock file for control socket");
1852
0
  close(fd);
1853
0
#ifdef ENABLE_PRIVSEP
1854
0
  if (chown(lockname, uid, gid) == -1)
1855
0
    log_warn("main", "unable to chown control socket lock");
1856
0
  if (chmod(lockname,
1857
0
    S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP) == -1)
1858
0
    log_warn("main", "unable to chmod control socket lock");
1859
0
#endif
1860
0
  free(lockname);
1861
1862
  /* Disable SIGPIPE */
1863
0
  signal(SIGPIPE, SIG_IGN);
1864
1865
  /* Disable SIGHUP, until handlers are installed */
1866
0
  signal(SIGHUP, SIG_IGN);
1867
1868
  /* Daemonization, unless started by systemd or launchd or debug */
1869
0
#ifndef HOST_OS_OSX
1870
0
  if (!lldpd_started_by_systemd() && daemonize) {
1871
0
    int pid;
1872
0
    char *spid;
1873
0
    log_debug("main", "going into background");
1874
0
    if (daemon(0, 1) != 0) fatal("main", "failed to detach daemon");
1875
0
    if ((pid = open(pidfile, O_TRUNC | O_CREAT | O_WRONLY, 0666)) == -1)
1876
0
      fatal("main",
1877
0
          "unable to open pid file " LLDPD_PID_FILE
1878
0
          " (or the specified one)");
1879
0
    if (asprintf(&spid, "%d\n", getpid()) == -1)
1880
0
      fatal("main",
1881
0
          "unable to create pid file " LLDPD_PID_FILE
1882
0
          " (or the specified one)");
1883
0
    if (write(pid, spid, strlen(spid)) == -1)
1884
0
      fatal("main",
1885
0
          "unable to write pid file " LLDPD_PID_FILE
1886
0
          " (or the specified one)");
1887
0
    free(spid);
1888
0
    close(pid);
1889
0
  }
1890
0
#endif
1891
1892
  /* Configuration with lldpcli */
1893
0
  if (lldpcli) {
1894
0
    if (!config_file) {
1895
0
      log_debug("main",
1896
0
          "invoking lldpcli for default configuration locations");
1897
0
    } else {
1898
0
      log_debug("main",
1899
0
          "invoking lldpcli for user supplied configuration location");
1900
0
    }
1901
0
    if (lldpd_configure(use_syslog, debug, lldpcli, ctlname, config_file) ==
1902
0
        -1)
1903
0
      fatal("main", "unable to spawn lldpcli");
1904
0
  }
1905
1906
  /* Try to read system information from /etc/os-release if possible.
1907
     Fall back to lsb_release for compatibility. */
1908
0
  log_debug("main", "get OS/LSB release information");
1909
0
  lsb_release = lldpd_get_os_release();
1910
0
  if (!lsb_release) {
1911
0
    lsb_release = lldpd_get_lsb_release();
1912
0
  }
1913
1914
0
  log_debug("main", "initialize privilege separation");
1915
0
#ifdef ENABLE_PRIVSEP
1916
0
  priv_init(PRIVSEP_CHROOT, ctl, uid, gid, ctlname);
1917
#else
1918
  priv_init(ctlname);
1919
#endif
1920
1921
  /* Initialization of global configuration */
1922
0
  if ((cfg = (struct lldpd *)calloc(1, sizeof(struct lldpd))) == NULL)
1923
0
    fatal("main", NULL);
1924
1925
0
  lldpd_alloc_default_local_port(cfg);
1926
0
  cfg->g_ctlname = ctlname;
1927
0
  cfg->g_ctl = ctl;
1928
0
  cfg->g_config.c_mgmt_pattern = mgmtp;
1929
0
  cfg->g_config.c_cid_pattern = cidp;
1930
0
  cfg->g_config.c_iface_pattern = interfaces;
1931
0
  cfg->g_config.c_smart = smart;
1932
0
  if (lldpcli) cfg->g_config.c_paused = 1;
1933
0
  cfg->g_config.c_receiveonly = receiveonly;
1934
0
  cfg->g_config.c_tx_interval = LLDPD_TX_INTERVAL * 1000;
1935
0
  cfg->g_config.c_tx_hold = LLDPD_TX_HOLD;
1936
0
  cfg->g_config.c_ttl = cfg->g_config.c_tx_interval * cfg->g_config.c_tx_hold;
1937
0
  cfg->g_config.c_ttl = MIN((cfg->g_config.c_ttl + 999) / 1000, 65535);
1938
0
  cfg->g_config.c_max_neighbors = LLDPD_MAX_NEIGHBORS;
1939
0
  cfg->g_config.c_enable_fast_start = enable_fast_start;
1940
0
  cfg->g_config.c_tx_fast_init = LLDPD_FAST_INIT;
1941
0
  cfg->g_config.c_tx_fast_interval = LLDPD_FAST_TX_INTERVAL;
1942
#ifdef USE_SNMP
1943
  cfg->g_snmp = snmp;
1944
  cfg->g_snmp_agentx = agentx;
1945
#endif /* USE_SNMP */
1946
0
  cfg->g_config.c_bond_slave_src_mac_type =
1947
0
      LLDP_BOND_SLAVE_SRC_MAC_TYPE_LOCALLY_ADMINISTERED;
1948
1949
  /* Get ioctl socket */
1950
0
  log_debug("main", "get an ioctl socket");
1951
0
  if ((cfg->g_sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
1952
0
    fatal("main", "failed to get ioctl socket");
1953
1954
  /* Description */
1955
0
  if (!(cfg->g_config.c_advertise_version = advertise_version) && lsb_release &&
1956
0
      lsb_release[strlen(lsb_release) - 1] == '\n')
1957
0
    lsb_release[strlen(lsb_release) - 1] = '\0';
1958
0
  cfg->g_lsb_release = lsb_release;
1959
0
  if (descr_override) cfg->g_config.c_description = descr_override;
1960
1961
0
  if (platform_override) cfg->g_config.c_platform = platform_override;
1962
1963
  /* Set system capabilities */
1964
0
  log_debug("main", "set system capabilities");
1965
0
  if ((lchassis = (struct lldpd_chassis *)calloc(1,
1966
0
     sizeof(struct lldpd_chassis))) == NULL)
1967
0
    fatal("localchassis", NULL);
1968
0
  cfg->g_config.c_cap_advertise = 1;
1969
0
  cfg->g_config.c_cap_override = 0;
1970
0
  lchassis->c_cap_available =
1971
0
      LLDP_CAP_BRIDGE | LLDP_CAP_WLAN | LLDP_CAP_ROUTER | LLDP_CAP_STATION;
1972
0
  cfg->g_config.c_mgmt_advertise = 1;
1973
0
  TAILQ_INIT(&lchassis->c_mgmt);
1974
0
#ifdef ENABLE_LLDPMED
1975
0
  if (lldpmed > 0) {
1976
0
    if (lldpmed == LLDP_MED_CLASS_III)
1977
0
      lchassis->c_cap_available |= LLDP_CAP_TELEPHONE;
1978
0
    lchassis->c_med_type = lldpmed;
1979
0
    lchassis->c_med_cap_available = LLDP_MED_CAP_CAP | LLDP_MED_CAP_IV |
1980
0
        LLDP_MED_CAP_LOCATION | LLDP_MED_CAP_POLICY | LLDP_MED_CAP_MDI_PSE |
1981
0
        LLDP_MED_CAP_MDI_PD;
1982
0
    cfg->g_config.c_noinventory = noinventory;
1983
0
  } else
1984
0
    cfg->g_config.c_noinventory = 1;
1985
0
#endif
1986
1987
0
  log_debug("main", "initialize protocols");
1988
0
  cfg->g_protocols = protos;
1989
0
  for (i = 0; protos[i].mode != 0; i++) {
1990
1991
    /* With -ll, disable LLDP */
1992
0
    if (protos[i].mode == LLDPD_MODE_LLDP) protos[i].enabled %= 3;
1993
    /* With -ccc force CDPV2, enable CDPV1 */
1994
0
    if (protos[i].mode == LLDPD_MODE_CDPV1 && protos[i].enabled == 3) {
1995
0
      protos[i].enabled = 1;
1996
0
    }
1997
    /* With -cc force CDPV1, enable CDPV2 */
1998
0
    if (protos[i].mode == LLDPD_MODE_CDPV2 && protos[i].enabled == 2) {
1999
0
      protos[i].enabled = 1;
2000
0
    }
2001
2002
    /* With -cccc disable CDPV1, enable CDPV2 */
2003
0
    if (protos[i].mode == LLDPD_MODE_CDPV1 && protos[i].enabled >= 4) {
2004
0
      protos[i].enabled = 0;
2005
0
    }
2006
2007
    /* With -cccc disable CDPV1, enable CDPV2; -ccccc will force CDPv2 */
2008
0
    if (protos[i].mode == LLDPD_MODE_CDPV2 && protos[i].enabled == 4) {
2009
0
      protos[i].enabled = 1;
2010
0
    }
2011
2012
0
    if (protos[i].enabled > 1)
2013
0
      log_info("main", "protocol %s enabled and forced",
2014
0
          protos[i].name);
2015
0
    else if (protos[i].enabled)
2016
0
      log_info("main", "protocol %s enabled", protos[i].name);
2017
0
    else
2018
0
      log_info("main", "protocol %s disabled", protos[i].name);
2019
0
  }
2020
2021
0
  TAILQ_INIT(&cfg->g_hardware);
2022
0
  TAILQ_INIT(&cfg->g_chassis);
2023
0
  TAILQ_INSERT_TAIL(&cfg->g_chassis, lchassis, c_entries);
2024
0
  lchassis->c_refcount++; /* We should always keep a reference to local chassis */
2025
2026
  /* Main loop */
2027
0
  log_debug("main", "start main loop");
2028
0
  levent_loop(cfg);
2029
0
  lchassis->c_refcount--;
2030
0
  lldpd_exit(cfg);
2031
0
  free(cfg);
2032
2033
0
  return (0);
2034
0
}