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