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