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