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