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