]> git.ipfire.org Git - thirdparty/lldpd.git/blame - src/lldpd.c
Harden lldpd with the use of RELRO and NOW linker options.
[thirdparty/lldpd.git] / src / lldpd.c
CommitLineData
43c02e7b
VB
1/*
2 * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include "lldpd.h"
18
19#include <stdio.h>
20#include <unistd.h>
21#include <errno.h>
22#include <signal.h>
23#include <sys/stat.h>
24#include <fcntl.h>
43c02e7b 25#include <time.h>
a2993d83 26#include <libgen.h>
43c02e7b
VB
27#include <sys/utsname.h>
28#include <sys/types.h>
c036b15d 29#include <sys/wait.h>
43c02e7b
VB
30#include <sys/socket.h>
31#include <sys/select.h>
32#include <sys/time.h>
33#include <sys/ioctl.h>
34#include <arpa/inet.h>
43c02e7b 35#include <net/if_arp.h>
43c02e7b 36
bc598c23
VB
37#if LLDPD_FD_SETSIZE != FD_SETSIZE
38# warning "FD_SETSIZE is set to an inconsistent value."
39#endif
40
43c02e7b
VB
41#ifdef USE_SNMP
42#include <net-snmp/net-snmp-config.h>
43#include <net-snmp/net-snmp-includes.h>
44#include <net-snmp/agent/net-snmp-agent-includes.h>
45#include <net-snmp/agent/snmp_vars.h>
46#endif /* USE_SNMP */
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
6e75df87
VB
76static void lldpd_update_localchassis(struct lldpd *);
77static void lldpd_update_localports(struct lldpd *);
78static void lldpd_cleanup(struct lldpd *);
8888d191
VB
79static void lldpd_loop(struct lldpd *);
80static void lldpd_shutdown(int);
6f1046d1 81static void lldpd_exit(void);
8888d191
VB
82static void lldpd_send_all(struct lldpd *);
83static void lldpd_recv_all(struct lldpd *);
42b39485 84static void lldpd_hide_all(struct lldpd *);
8888d191
VB
85static int lldpd_guess_type(struct lldpd *, char *, int);
86static void lldpd_decode(struct lldpd *, char *, int,
0bc32943 87 struct lldpd_hardware *);
16f910e1
VB
88static void lldpd_update_chassis(struct lldpd_chassis *,
89 const struct lldpd_chassis *);
24f27a98 90static char *lldpd_get_lsb_release(void);
89840df0 91#ifdef ENABLE_LLDPMED
8888d191 92static void lldpd_med(struct lldpd_chassis *);
89840df0 93#endif
43c02e7b 94
8888d191 95static char **saved_argv;
6bb9c4e0
VB
96#ifdef HAVE___PROGNAME
97extern const char *__progname;
98#else
99# define __progname "lldpd"
100#endif
43c02e7b 101
8888d191 102static void
43c02e7b
VB
103usage(void)
104{
53132616
VB
105 fprintf(stderr, "Usage: %s [OPTIONS ...]\n", __progname);
106
107 fprintf(stderr, "\n");
108
109 fprintf(stderr, "-d Do not daemonize.\n");
110 fprintf(stderr, "-i Disable LLDP-MED inventory TLV transmission.\n");
111 fprintf(stderr, "-k Disable advertising of kernel release, version, machine.\n");
fde7a7ce 112 fprintf(stderr, "-S descr Override the default system description.\n");
53132616 113 fprintf(stderr, "-m IP Specify the management address of this system.\n");
42b39485 114 fprintf(stderr, "-H mode Specify the behaviour when detecting multiple neighbors.\n");
8347587d 115#ifdef ENABLE_LLDPMED
53132616
VB
116 fprintf(stderr, "-M class Enable emission of LLDP-MED frame. 'class' should be one of:\n");
117 fprintf(stderr, " 1 Generic Endpoint (Class I)\n");
118 fprintf(stderr, " 2 Media Endpoint (Class II)\n");
119 fprintf(stderr, " 3 Communication Device Endpoints (Class III)\n");
120 fprintf(stderr, " 4 Network Connectivity Device\n");
8347587d
VB
121#endif
122#ifdef USE_SNMP
53132616 123 fprintf(stderr, "-x Enable SNMP subagent.\n");
53132616
VB
124#endif
125 fprintf(stderr, "\n");
126
8347587d
VB
127#if defined ENABLE_CDP || defined ENABLE_EDP || defined ENABLE_FDP || defined ENABLE_SONMP
128 fprintf(stderr, "Additional protocol support.\n");
129#ifdef ENABLE_CDP
53132616 130 fprintf(stderr, "-c Enable the support of CDP protocol. (Cisco)\n");
8347587d
VB
131#endif
132#ifdef ENABLE_EDP
53132616 133 fprintf(stderr, "-e Enable the support of EDP protocol. (Extreme)\n");
8347587d
VB
134#endif
135#ifdef ENABLE_FDP
53132616 136 fprintf(stderr, "-f Enable the support of FDP protocol. (Foundry)\n");
8347587d
VB
137#endif
138#ifdef ENABLE_SONMP
53132616 139 fprintf(stderr, "-s Enable the support of SONMP protocol. (Nortel)\n");
8347587d 140#endif
53132616
VB
141
142 fprintf(stderr, "\n");
8347587d 143#endif
53132616 144
e809a587 145 fprintf(stderr, "see manual page lldpd(8) for more information\n");
43c02e7b
VB
146 exit(1);
147}
148
6e75df87 149struct lldpd_hardware *
44002d66 150lldpd_get_hardware(struct lldpd *cfg, char *name, int index, struct lldpd_ops *ops)
43c02e7b 151{
6e75df87
VB
152 struct lldpd_hardware *hardware;
153 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
849954d7 154 if ((strcmp(hardware->h_ifname, name) == 0) &&
44002d66 155 (hardware->h_ifindex == index) &&
849954d7 156 ((!ops) || (ops == hardware->h_ops)))
6e75df87 157 break;
43c02e7b 158 }
6e75df87 159 return hardware;
43c02e7b
VB
160}
161
6e75df87
VB
162struct lldpd_hardware *
163lldpd_alloc_hardware(struct lldpd *cfg, char *name)
43c02e7b 164{
6e75df87 165 struct lldpd_hardware *hardware;
43c02e7b 166
6e75df87
VB
167 if ((hardware = (struct lldpd_hardware *)
168 calloc(1, sizeof(struct lldpd_hardware))) == NULL)
169 return NULL;
43c02e7b 170
6e75df87
VB
171 strlcpy(hardware->h_ifname, name, sizeof(hardware->h_ifname));
172 hardware->h_lport.p_chassis = LOCAL_CHASSIS(cfg);
9df5ec3d 173 hardware->h_lport.p_chassis->c_refcount++;
6e75df87 174 TAILQ_INIT(&hardware->h_rports);
43c02e7b 175
6e75df87
VB
176#ifdef ENABLE_LLDPMED
177 if (LOCAL_CHASSIS(cfg)->c_med_cap_available) {
178 hardware->h_lport.p_med_cap_enabled = LLDPMED_CAP_CAP;
179 if (!cfg->g_noinventory)
180 hardware->h_lport.p_med_cap_enabled |= LLDPMED_CAP_IV;
181 }
182#endif
183#ifdef ENABLE_DOT1
184 TAILQ_INIT(&hardware->h_lport.p_vlans);
185#endif
186 return hardware;
43c02e7b
VB
187}
188
a1347cd8 189#ifdef ENABLE_DOT1
43c02e7b
VB
190void
191lldpd_vlan_cleanup(struct lldpd_port *port)
192{
193 struct lldpd_vlan *vlan, *vlan_next;
194 for (vlan = TAILQ_FIRST(&port->p_vlans);
195 vlan != NULL;
196 vlan = vlan_next) {
197 free(vlan->v_name);
198 vlan_next = TAILQ_NEXT(vlan, v_entries);
199 TAILQ_REMOVE(&port->p_vlans, vlan, v_entries);
200 free(vlan);
201 }
202}
a1347cd8 203#endif
43c02e7b 204
a0edeaf8 205/* If `all' is true, clear all information, including information that
4e624dc2 206 are not refreshed periodically. Port should be freed manually. */
43c02e7b 207void
9898ac07 208lldpd_port_cleanup(struct lldpd *cfg, struct lldpd_port *port, int all)
43c02e7b 209{
740593ff
VB
210#ifdef ENABLE_LLDPMED
211 int i;
a0edeaf8
VB
212 if (all)
213 for (i=0; i < LLDPMED_LOCFORMAT_LAST; i++)
214 free(port->p_med_location[i].data);
740593ff 215#endif
a1347cd8 216#ifdef ENABLE_DOT1
43c02e7b 217 lldpd_vlan_cleanup(port);
a1347cd8 218#endif
43c02e7b
VB
219 free(port->p_id);
220 free(port->p_descr);
77507b69
VB
221 if (all) {
222 free(port->p_lastframe);
9898ac07 223 if (port->p_chassis) { /* chassis may not have been attributed, yet */
77507b69 224 port->p_chassis->c_refcount--;
9898ac07
V
225 port->p_chassis = NULL;
226 }
77507b69 227 }
43c02e7b
VB
228}
229
230void
77507b69 231lldpd_chassis_cleanup(struct lldpd_chassis *chassis, int all)
43c02e7b 232{
89840df0
VB
233#ifdef ENABLE_LLDPMED
234 free(chassis->c_med_hw);
517d524b 235 free(chassis->c_med_sw);
89840df0
VB
236 free(chassis->c_med_fw);
237 free(chassis->c_med_sn);
238 free(chassis->c_med_manuf);
239 free(chassis->c_med_model);
240 free(chassis->c_med_asset);
241#endif
43c02e7b
VB
242 free(chassis->c_id);
243 free(chassis->c_name);
244 free(chassis->c_descr);
77507b69
VB
245 if (all)
246 free(chassis);
43c02e7b
VB
247}
248
249void
77507b69 250lldpd_remote_cleanup(struct lldpd *cfg, struct lldpd_hardware *hardware, int all)
43c02e7b 251{
77507b69
VB
252 struct lldpd_port *port, *port_next;
253 int del;
254 for (port = TAILQ_FIRST(&hardware->h_rports);
255 port != NULL;
256 port = port_next) {
257 port_next = TAILQ_NEXT(port, p_entries);
258 del = all;
259 if (!del &&
260 (time(NULL) - port->p_lastupdate > port->p_chassis->c_ttl)) {
261 hardware->h_rx_ageout_cnt++;
262 del = 1;
263 }
264 if (del) {
265 TAILQ_REMOVE(&hardware->h_rports, port, p_entries);
9898ac07 266 lldpd_port_cleanup(cfg, port, 1);
4e624dc2 267 free(port);
77507b69 268 }
43c02e7b 269 }
43c02e7b
VB
270}
271
d9be8ea0 272void
6e75df87 273lldpd_hardware_cleanup(struct lldpd *cfg, struct lldpd_hardware *hardware)
d9be8ea0 274{
6e75df87 275 int i;
9898ac07 276 lldpd_port_cleanup(cfg, &hardware->h_lport, 1);
6e75df87
VB
277 /* If we have a dedicated cleanup function, use it. Otherwise,
278 we just free the hardware-dependent data and close all FD
279 in h_recvfds and h_sendfd. */
280 if (hardware->h_ops->cleanup)
281 hardware->h_ops->cleanup(cfg, hardware);
282 else {
283 free(hardware->h_data);
bc598c23 284 for (i=0; i < LLDPD_FD_SETSIZE; i++)
6e75df87
VB
285 if (FD_ISSET(i, &hardware->h_recvfds))
286 close(i);
287 if (hardware->h_sendfd) close(hardware->h_sendfd);
288 }
d9be8ea0
VB
289 free(hardware);
290}
291
6e75df87 292static void
43c02e7b
VB
293lldpd_cleanup(struct lldpd *cfg)
294{
295 struct lldpd_hardware *hardware, *hardware_next;
aadc9936 296 struct lldpd_chassis *chassis, *chassis_next;
43c02e7b
VB
297
298 for (hardware = TAILQ_FIRST(&cfg->g_hardware); hardware != NULL;
299 hardware = hardware_next) {
300 hardware_next = TAILQ_NEXT(hardware, h_entries);
6e75df87 301 if (!hardware->h_flags) {
43c02e7b 302 TAILQ_REMOVE(&cfg->g_hardware, hardware, h_entries);
77507b69 303 lldpd_remote_cleanup(cfg, hardware, 1);
6e75df87 304 lldpd_hardware_cleanup(cfg, hardware);
77507b69
VB
305 } else
306 lldpd_remote_cleanup(cfg, hardware, 0);
43c02e7b 307 }
aadc9936
VB
308
309 for (chassis = TAILQ_FIRST(&cfg->g_chassis); chassis;
310 chassis = chassis_next) {
311 chassis_next = TAILQ_NEXT(chassis, c_entries);
312 if (chassis->c_refcount == 0) {
313 TAILQ_REMOVE(&cfg->g_chassis, chassis, c_entries);
314 lldpd_chassis_cleanup(chassis, 1);
315 }
316 }
43c02e7b
VB
317}
318
8888d191 319static int
43c02e7b
VB
320lldpd_guess_type(struct lldpd *cfg, char *frame, int s)
321{
322 int i;
323 if (s < ETH_ALEN)
324 return -1;
325 for (i=0; cfg->g_protocols[i].mode != 0; i++) {
326 if (!cfg->g_protocols[i].enabled)
327 continue;
328 if (cfg->g_protocols[i].guess == NULL) {
329 if (memcmp(frame, cfg->g_protocols[i].mac, ETH_ALEN) == 0)
330 return cfg->g_protocols[i].mode;
331 } else {
332 if (cfg->g_protocols[i].guess(frame, s))
333 return cfg->g_protocols[i].mode;
334 }
335 }
336 return -1;
337}
338
8888d191 339static void
43c02e7b 340lldpd_decode(struct lldpd *cfg, char *frame, int s,
0bc32943 341 struct lldpd_hardware *hardware)
43c02e7b 342{
77507b69
VB
343 int i, result;
344 struct lldpd_chassis *chassis, *ochassis = NULL;
345 struct lldpd_port *port, *oport = NULL;
43c02e7b
VB
346 int guess = LLDPD_MODE_LLDP;
347
49697208
VB
348 if (s < sizeof(struct ethhdr) + 4)
349 /* Too short, just discard it */
50a89ca7 350 return;
49697208
VB
351 /* Decapsulate VLAN frames */
352 if (((struct ethhdr*)frame)->h_proto == htons(ETHERTYPE_VLAN)) {
353 /* VLAN decapsulation means to shift 4 bytes left the frame from
354 * offset 2*ETH_ALEN */
355 memmove(frame + 2*ETH_ALEN, frame + 2*ETH_ALEN + 4, s - 2*ETH_ALEN);
356 s -= 4;
357 }
50a89ca7 358
77507b69
VB
359 TAILQ_FOREACH(oport, &hardware->h_rports, p_entries) {
360 if ((oport->p_lastframe != NULL) &&
361 (oport->p_lastframe->size == s) &&
362 (memcmp(oport->p_lastframe->frame, frame, s) == 0)) {
363 /* Already received the same frame */
364 oport->p_lastupdate = time(NULL);
365 return;
366 }
43c02e7b
VB
367 }
368
f2dcb180
VB
369 guess = lldpd_guess_type(cfg, frame, s);
370 for (i=0; cfg->g_protocols[i].mode != 0; i++) {
371 if (!cfg->g_protocols[i].enabled)
372 continue;
373 if (cfg->g_protocols[i].mode == guess) {
374 if ((result = cfg->g_protocols[i].decode(cfg, frame,
375 s, hardware, &chassis, &port)) == -1)
376 return;
77507b69
VB
377 chassis->c_protocol = port->p_protocol =
378 cfg->g_protocols[i].mode;
f2dcb180 379 break;
43c02e7b 380 }
f2dcb180
VB
381 }
382 if (cfg->g_protocols[i].mode == 0) {
383 LLOG_INFO("unable to guess frame type");
43c02e7b 384 return;
f2dcb180 385 }
43c02e7b 386
77507b69
VB
387 /* Do we already have the same MSAP somewhere? */
388 TAILQ_FOREACH(oport, &hardware->h_rports, p_entries) {
389 if ((port->p_protocol == oport->p_protocol) &&
390 (port->p_id_subtype == oport->p_id_subtype) &&
391 (port->p_id_len == oport->p_id_len) &&
392 (memcmp(port->p_id, oport->p_id, port->p_id_len) == 0) &&
393 (chassis->c_id_subtype == oport->p_chassis->c_id_subtype) &&
394 (chassis->c_id_len == oport->p_chassis->c_id_len) &&
395 (memcmp(chassis->c_id, oport->p_chassis->c_id,
396 chassis->c_id_len) == 0)) {
397 ochassis = oport->p_chassis;
398 break;
399 }
43c02e7b 400 }
77507b69
VB
401 /* No, but do we already know the system? */
402 if (!oport) {
403 TAILQ_FOREACH(ochassis, &cfg->g_chassis, c_entries) {
404 if ((chassis->c_protocol == ochassis->c_protocol) &&
405 (chassis->c_id_subtype == ochassis->c_id_subtype) &&
406 (chassis->c_id_len == ochassis->c_id_len) &&
407 (memcmp(chassis->c_id, ochassis->c_id,
408 chassis->c_id_len) == 0))
409 break;
43c02e7b 410 }
43c02e7b 411 }
43c02e7b 412
77507b69
VB
413 if (oport) {
414 /* The port is known, remove it before adding it back */
415 TAILQ_REMOVE(&hardware->h_rports, oport, p_entries);
9898ac07 416 lldpd_port_cleanup(cfg, oport, 1);
4e624dc2 417 free(oport);
77507b69
VB
418 }
419 if (ochassis) {
16f910e1 420 lldpd_update_chassis(ochassis, chassis);
77507b69
VB
421 free(chassis);
422 chassis = ochassis;
423 } else {
424 /* Chassis not known, add it */
425 chassis->c_index = ++cfg->g_lastrid;
77507b69
VB
426 chassis->c_refcount = 0;
427 TAILQ_INSERT_TAIL(&cfg->g_chassis, chassis, c_entries);
f4c43902
VB
428 i = 0; TAILQ_FOREACH(ochassis, &cfg->g_chassis, c_entries) i++;
429 LLOG_DEBUG("Currently, we know %d different systems", i);
77507b69
VB
430 }
431 /* Add port */
432 port->p_lastchange = port->p_lastupdate = time(NULL);
433 if ((port->p_lastframe = (struct lldpd_frame *)malloc(s +
434 sizeof(int))) != NULL) {
435 port->p_lastframe->size = s;
436 memcpy(port->p_lastframe->frame, frame, s);
437 }
438 TAILQ_INSERT_TAIL(&hardware->h_rports, port, p_entries);
439 port->p_chassis = chassis;
440 port->p_chassis->c_refcount++;
9df5ec3d
VB
441 /* Several cases are possible :
442 1. chassis is new, its refcount was 0. It is now attached
443 to this port, its refcount is 1.
444 2. chassis already exists and was attached to another
445 port, we increase its refcount accordingly.
446 3. chassis already exists and was attached to the same
447 port, its refcount was decreased with
448 lldpd_port_cleanup() and is now increased again.
449
450 In all cases, if the port already existed, it has been
451 freed with lldpd_port_cleanup() and therefore, the refcount
452 of the chassis that was attached to it is decreased.
453 */
42b39485
VB
454 i = 0; TAILQ_FOREACH(oport, &hardware->h_rports, p_entries)
455 i++;
456 LLOG_DEBUG("Currently, %s knows %d neighbors",
f4c43902 457 hardware->h_ifname, i);
43c02e7b
VB
458 return;
459}
460
16f910e1
VB
461/* Update chassis `ochassis' with values from `chassis'. */
462static void
463lldpd_update_chassis(struct lldpd_chassis *ochassis,
464 const struct lldpd_chassis *chassis) {
465 TAILQ_ENTRY(lldpd_chassis) entries;
466 /* We want to keep refcount, index and list stuff from the current
467 * chassis */
468 int refcount = ochassis->c_refcount;
469 int index = ochassis->c_index;
470 memcpy(&entries, &ochassis->c_entries,
471 sizeof(entries));
472 /* Make the copy */
473 lldpd_chassis_cleanup(ochassis, 0);
474 memcpy(ochassis, chassis, sizeof(struct lldpd_chassis));
475 /* Restore saved values */
476 ochassis->c_refcount = refcount;
477 ochassis->c_index = index;
478 memcpy(&ochassis->c_entries, &entries, sizeof(entries));
479}
480
c036b15d
VB
481/* Get the output of lsb_release -s -d. This is a slow function. It should be
482 called once. It return NULL if any problem happens. Otherwise, this is a
483 statically allocated buffer. The result includes the trailing \n */
484static char *
485lldpd_get_lsb_release() {
486 static char release[1024];
487 char *const command[] = { "lsb_release", "-s", "-d", NULL };
488 int pid, status, devnull, count;
489 int pipefd[2];
490
491 if (pipe(pipefd)) {
492 LLOG_WARN("unable to get a pair of pipes");
493 return NULL;
494 }
495
496 if ((pid = fork()) < 0) {
497 LLOG_WARN("unable to fork");
498 return NULL;
499 }
500 switch (pid) {
501 case 0:
502 /* Child, exec lsb_release */
503 close(pipefd[0]);
504 if ((devnull = open("/dev/null", O_RDWR, 0)) != -1) {
505 dup2(devnull, STDIN_FILENO);
506 dup2(devnull, STDERR_FILENO);
507 dup2(pipefd[1], STDOUT_FILENO);
508 if (devnull > 2) close(devnull);
509 if (pipefd[1] > 2) close(pipefd[1]);
510 execvp("lsb_release", command);
511 }
512 exit(127);
513 break;
514 default:
515 /* Father, read the output from the children */
516 close(pipefd[1]);
517 count = 0;
518 do {
519 status = read(pipefd[0], release+count, sizeof(release)-count);
520 if ((status == -1) && (errno == EINTR)) continue;
521 if (status > 0)
522 count += status;
523 } while (count < sizeof(release) && (status > 0));
524 if (status < 0) {
525 LLOG_WARN("unable to read from lsb_release");
526 close(pipefd[0]);
527 waitpid(pid, &status, 0);
528 return NULL;
529 }
530 close(pipefd[0]);
531 if (count >= sizeof(release)) {
532 LLOG_INFO("output of lsb_release is too large");
533 waitpid(pid, &status, 0);
534 return NULL;
535 }
536 status = -1;
537 if (waitpid(pid, &status, 0) != pid)
538 return NULL;
539 if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) {
540 LLOG_INFO("lsb_release information not available");
541 return NULL;
542 }
543 if (!count) {
544 LLOG_INFO("lsb_release returned an empty string");
545 return NULL;
546 }
547 release[count] = '\0';
548 return release;
549 }
550 /* Should not be here */
551 return NULL;
552}
553
77d7090e
VB
554int
555lldpd_callback_add(struct lldpd *cfg, int fd, void(*fn)(CALLBACK_SIG), void *data)
556{
557 struct lldpd_callback *callback;
558 if ((callback = (struct lldpd_callback *)
559 malloc(sizeof(struct lldpd_callback))) == NULL)
560 return -1;
561 callback->fd = fd;
562 callback->function = fn;
563 callback->data = data;
564 TAILQ_INSERT_TAIL(&cfg->g_callbacks, callback, next);
565 return 0;
566}
567
568void
569lldpd_callback_del(struct lldpd *cfg, int fd, void(*fn)(CALLBACK_SIG))
570{
571 struct lldpd_callback *callback, *callback_next;
572 for (callback = TAILQ_FIRST(&cfg->g_callbacks);
573 callback;
574 callback = callback_next) {
575 callback_next = TAILQ_NEXT(callback, next);
576 if ((callback->fd == fd) &&
577 (callback->function = fn)) {
578 free(callback->data);
579 TAILQ_REMOVE(&cfg->g_callbacks, callback, next);
580 free(callback);
581 }
582 }
583}
16f910e1 584
42b39485
VB
585/* Hide unwanted ports depending on smart mode set by the user */
586static void
587lldpd_hide_all(struct lldpd *cfg)
588{
589 struct lldpd_hardware *hardware;
590 struct lldpd_port *port;
591 int protocols[LLDPD_MODE_MAX+1];
592 int i, j, found;
593 unsigned int min;
594
595 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
596 /* Compute the number of occurrences of each protocol */
597 for (i = 0; i <= LLDPD_MODE_MAX; i++)
598 protocols[i] = 0;
599 TAILQ_FOREACH(port, &hardware->h_rports, p_entries)
600 protocols[port->p_protocol]++;
601
602 /* Turn the protocols[] array into an array of
603 enabled/disabled protocols. 1 means enabled, 0
604 means disabled. */
605 min = (unsigned int)-1;
606 for (i = 0; i <= LLDPD_MODE_MAX; i++)
607 if (protocols[i] && (protocols[i] < min))
608 min = protocols[i];
609 found = 0;
610 for (i = 0; i <= LLDPD_MODE_MAX; i++)
611 if ((protocols[i] == min) && !found) {
612 /* If we need a tie breaker, we take
613 the first protocol only */
614 if (cfg->g_smart & SMART_FILTER_NO_TIE)
615 found = 1;
616 protocols[i] = 1;
617 } else protocols[i] = 0;
618
619 /* We set the p_hidden flag to 1 if the protocol is disabled */
620 TAILQ_FOREACH(port, &hardware->h_rports, p_entries)
621 port->p_hidden = protocols[port->p_protocol]?0:1;
622
623 /* If we want only one neighbor, we take the first one */
624 if (cfg->g_smart & SMART_FILTER_ONE_NEIGH) {
625 found = 0;
626 TAILQ_FOREACH(port, &hardware->h_rports, p_entries) {
627 if (!port->p_hidden) {
628 if (found)
629 port->p_hidden = 1;
630 else
631 found = 1;
632 }
633 }
634 }
635
636 /* Print a debug message summarizing the operation */
637 i = j = 0;
638 TAILQ_FOREACH(port, &hardware->h_rports, p_entries) {
639 if (port->p_hidden) i++;
640 j++;
641 }
642 if (i) {
643 LLOG_DEBUG("On %s, out of %d neighbors, %d are hidden",
644 hardware->h_ifname, j, i);
645 for (i=0; protos[i].mode != 0; i++) {
646 if (protos[i].enabled)
647 LLOG_DEBUG("On %s, %s is %s",
648 hardware->h_ifname, protos[i].name,
649 protocols[protos[i].mode]?"enabled":"disabled");
650 }
651 }
652 }
653}
654
8888d191 655static void
43c02e7b
VB
656lldpd_recv_all(struct lldpd *cfg)
657{
658 struct lldpd_hardware *hardware;
77d7090e 659 struct lldpd_callback *callback, *callback_next;
43c02e7b
VB
660 fd_set rfds;
661 struct timeval tv;
43c02e7b 662#ifdef USE_SNMP
630b4134
VB
663 struct timeval snmptv;
664 int snmpblock = 0;
43c02e7b 665#endif
0bc32943 666 int rc, nfds, n;
43c02e7b
VB
667 char *buffer;
668
669 do {
670 tv.tv_sec = cfg->g_delay - (time(NULL) - cfg->g_lastsent);
671 if (tv.tv_sec < 0)
672 tv.tv_sec = LLDPD_TX_DELAY;
673 if (tv.tv_sec >= cfg->g_delay)
674 tv.tv_sec = cfg->g_delay;
675 tv.tv_usec = 0;
676
677 FD_ZERO(&rfds);
678 nfds = -1;
679
680 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
681 /* Ignore if interface is down */
6e75df87 682 if ((hardware->h_flags & IFF_RUNNING) == 0)
43c02e7b 683 continue;
6e75df87
VB
684 /* This is quite expensive but we don't rely on internal
685 * structure of fd_set. */
bc598c23 686 for (n = 0; n < LLDPD_FD_SETSIZE; n++)
6e75df87
VB
687 if (FD_ISSET(n, &hardware->h_recvfds)) {
688 FD_SET(n, &rfds);
689 if (nfds < n)
690 nfds = n;
691 }
43c02e7b 692 }
77d7090e
VB
693 TAILQ_FOREACH(callback, &cfg->g_callbacks, next) {
694 FD_SET(callback->fd, &rfds);
695 if (nfds < callback->fd)
696 nfds = callback->fd;
43c02e7b 697 }
43c02e7b
VB
698
699#ifdef USE_SNMP
630b4134
VB
700 if (cfg->g_snmp) {
701 snmpblock = 0;
702 memcpy(&snmptv, &tv, sizeof(struct timeval));
703 snmp_select_info(&nfds, &rfds, &snmptv, &snmpblock);
704 if (snmpblock == 0)
705 memcpy(&tv, &snmptv, sizeof(struct timeval));
706 }
43c02e7b
VB
707#endif /* USE_SNMP */
708 if (nfds == -1) {
709 sleep(cfg->g_delay);
710 return;
711 }
712
713 rc = select(nfds + 1, &rfds, NULL, NULL, &tv);
714 if (rc == -1) {
715 if (errno == EINTR)
716 continue;
717 LLOG_WARN("failure on select");
718 break;
719 }
720#ifdef USE_SNMP
721 if (cfg->g_snmp) {
722 if (rc > 0)
723 snmp_read(&rfds);
724 else if (rc == 0)
725 snmp_timeout();
726 }
727#endif /* USE_SNMP */
728 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
bc598c23 729 for (n = 0; n < LLDPD_FD_SETSIZE; n++)
6e75df87
VB
730 if ((FD_ISSET(n, &hardware->h_recvfds)) &&
731 (FD_ISSET(n, &rfds))) break;
bc598c23 732 if (n == LLDPD_FD_SETSIZE) continue;
6e75df87
VB
733 if ((buffer = (char *)malloc(
734 hardware->h_mtu)) == NULL) {
735 LLOG_WARN("failed to alloc reception buffer");
736 continue;
737 }
738 if ((n = hardware->h_ops->recv(cfg, hardware,
739 n, buffer, hardware->h_mtu)) == -1) {
43c02e7b 740 free(buffer);
6e75df87 741 continue;
43c02e7b 742 }
6e75df87
VB
743 hardware->h_rx_cnt++;
744 lldpd_decode(cfg, buffer, n, hardware);
745 free(buffer);
746 break;
43c02e7b 747 }
77d7090e
VB
748 for (callback = TAILQ_FIRST(&cfg->g_callbacks);
749 callback;
750 callback = callback_next) {
751 /* Callback function can use TAILQ_REMOVE */
752 callback_next = TAILQ_NEXT(callback, next);
753 if (FD_ISSET(callback->fd, &rfds))
754 callback->function(cfg, callback);
43c02e7b
VB
755 }
756
757#ifdef USE_SNMP
758 if (cfg->g_snmp) {
759 run_alarms();
760 netsnmp_check_outstanding_agent_requests();
761 }
762#endif /* USE_SNMP */
763 } while ((rc != 0) || (time(NULL) - cfg->g_lastsent < cfg->g_delay));
764}
765
8888d191 766static void
43c02e7b
VB
767lldpd_send_all(struct lldpd *cfg)
768{
769 struct lldpd_hardware *hardware;
77507b69 770 struct lldpd_port *port;
0d86e62f 771 int i, sent;
f7db0dd8 772
43c02e7b
VB
773 cfg->g_lastsent = time(NULL);
774 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
775 /* Ignore if interface is down */
6e75df87 776 if ((hardware->h_flags & IFF_RUNNING) == 0)
43c02e7b
VB
777 continue;
778
0d86e62f 779 sent = 0;
43c02e7b
VB
780 for (i=0; cfg->g_protocols[i].mode != 0; i++) {
781 if (!cfg->g_protocols[i].enabled)
782 continue;
77507b69 783 /* We send only if we have at least one remote system
0c877af0
VB
784 * speaking this protocol or if the protocol is forced */
785 if (cfg->g_protocols[i].enabled > 1) {
786 cfg->g_protocols[i].send(cfg, hardware);
787 sent++;
788 continue;
789 }
77507b69 790 TAILQ_FOREACH(port, &hardware->h_rports, p_entries) {
42b39485
VB
791 /* If this remote port is disabled, we don't
792 * consider it */
793 if (port->p_hidden &&
794 (cfg->g_smart & SMART_FILTER_EMISSION))
795 continue;
77507b69
VB
796 if (port->p_protocol ==
797 cfg->g_protocols[i].mode) {
798 cfg->g_protocols[i].send(cfg,
799 hardware);
0c877af0 800 sent++;
77507b69
VB
801 break;
802 }
803 }
43c02e7b 804 }
77507b69
VB
805
806 if (!sent)
807 /* Nothing was sent for this port, let's speak LLDP */
808 cfg->g_protocols[0].send(cfg,
809 hardware);
43c02e7b
VB
810 }
811}
812
89840df0 813#ifdef ENABLE_LLDPMED
8888d191 814static void
89840df0
VB
815lldpd_med(struct lldpd_chassis *chassis)
816{
817 free(chassis->c_med_hw);
818 free(chassis->c_med_fw);
819 free(chassis->c_med_sn);
820 free(chassis->c_med_manuf);
821 free(chassis->c_med_model);
822 free(chassis->c_med_asset);
823 chassis->c_med_hw = dmi_hw();
824 chassis->c_med_fw = dmi_fw();
825 chassis->c_med_sn = dmi_sn();
826 chassis->c_med_manuf = dmi_manuf();
827 chassis->c_med_model = dmi_model();
828 chassis->c_med_asset = dmi_asset();
829}
830#endif
831
8888d191 832static void
6e75df87 833lldpd_update_localchassis(struct lldpd *cfg)
43c02e7b 834{
6e75df87
VB
835 struct utsname un;
836 char *hp;
43c02e7b
VB
837 int f;
838 char status;
6e75df87 839 struct lldpd_hardware *hardware;
43c02e7b
VB
840
841 /* Set system name and description */
6e75df87 842 if (uname(&un) != 0)
43c02e7b 843 fatal("failed to get system information");
b5562b23 844 if ((hp = priv_gethostbyname()) == NULL)
43c02e7b 845 fatal("failed to get system name");
77507b69
VB
846 free(LOCAL_CHASSIS(cfg)->c_name);
847 free(LOCAL_CHASSIS(cfg)->c_descr);
848 if ((LOCAL_CHASSIS(cfg)->c_name = strdup(hp)) == NULL)
249644a4 849 fatal(NULL);
40ce835b
ST
850 if (cfg->g_descr_override) {
851 if (asprintf(&LOCAL_CHASSIS(cfg)->c_descr, "%s",
852 cfg->g_descr_override) == -1)
de1b1b3a 853 fatal("failed to set full system description");
40ce835b
ST
854 } else {
855 if (cfg->g_advertise_version) {
c036b15d
VB
856 if (asprintf(&LOCAL_CHASSIS(cfg)->c_descr, "%s%s %s %s",
857 cfg->g_lsb_release?cfg->g_lsb_release:"",
858 un.sysname, un.release, un.machine)
40ce835b
ST
859 == -1)
860 fatal("failed to set full system description");
861 } else {
862 if (asprintf(&LOCAL_CHASSIS(cfg)->c_descr, "%s",
c036b15d 863 cfg->g_lsb_release?cfg->g_lsb_release:un.sysname) == -1)
40ce835b
ST
864 fatal("failed to set minimal system description");
865 }
866 }
43c02e7b
VB
867
868 /* Check forwarding */
b5562b23 869 if ((f = priv_open("/proc/sys/net/ipv4/ip_forward")) >= 0) {
4afe659e 870 if ((read(f, &status, 1) == 1) && (status == '1')) {
77507b69 871 LOCAL_CHASSIS(cfg)->c_cap_enabled = LLDP_CAP_ROUTER;
4afe659e 872 }
43c02e7b
VB
873 close(f);
874 }
89840df0 875#ifdef ENABLE_LLDPMED
77507b69
VB
876 if (LOCAL_CHASSIS(cfg)->c_cap_available & LLDP_CAP_TELEPHONE)
877 LOCAL_CHASSIS(cfg)->c_cap_enabled |= LLDP_CAP_TELEPHONE;
878 lldpd_med(LOCAL_CHASSIS(cfg));
879 free(LOCAL_CHASSIS(cfg)->c_med_sw);
de1b1b3a
VB
880 if (cfg->g_advertise_version)
881 LOCAL_CHASSIS(cfg)->c_med_sw = strdup(un.release);
882 else
883 LOCAL_CHASSIS(cfg)->c_med_sw = strdup("Unknown");
89840df0 884#endif
43c02e7b 885
6e75df87
VB
886 /* Set chassis ID if needed */
887 if ((LOCAL_CHASSIS(cfg)->c_id == NULL) &&
888 (hardware = TAILQ_FIRST(&cfg->g_hardware))) {
889 if ((LOCAL_CHASSIS(cfg)->c_id =
890 malloc(sizeof(hardware->h_lladdr))) == NULL)
891 fatal(NULL);
892 LOCAL_CHASSIS(cfg)->c_id_subtype = LLDP_CHASSISID_SUBTYPE_LLADDR;
893 LOCAL_CHASSIS(cfg)->c_id_len = sizeof(hardware->h_lladdr);
894 memcpy(LOCAL_CHASSIS(cfg)->c_id,
895 hardware->h_lladdr, sizeof(hardware->h_lladdr));
896 }
897}
898
899static void
900lldpd_update_localports(struct lldpd *cfg)
901{
902 struct ifaddrs *ifap;
903 struct lldpd_hardware *hardware;
904 lldpd_ifhandlers ifhs[] = {
849954d7 905 lldpd_ifh_bond, /* Handle bond */
6e75df87 906 lldpd_ifh_eth, /* Handle classic ethernet interfaces */
5994b27d 907#ifdef ENABLE_DOT1
6e75df87 908 lldpd_ifh_vlan, /* Handle VLAN */
5994b27d 909#endif
6e75df87
VB
910 lldpd_ifh_mgmt, /* Handle management address (if not already handled) */
911 NULL
912 };
913 lldpd_ifhandlers *ifh;
914
915 /* h_flags is set to 0 for each port. If the port is updated, h_flags
916 * will be set to a non-zero value. This will allow us to clean up any
917 * non up-to-date port */
43c02e7b
VB
918 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries)
919 hardware->h_flags = 0;
920
77507b69 921 LOCAL_CHASSIS(cfg)->c_mgmt.s_addr = INADDR_ANY;
6e75df87
VB
922 if (getifaddrs(&ifap) != 0)
923 fatal("lldpd_update_localports: failed to get interface list");
924
925 /* We will run the list of interfaces through a list of interface
926 * handlers. Each handler will create or update some hardware port (and
927 * will set h_flags to a non zero value. The handler can use the list of
928 * interfaces but this is not mandatory. If the interface handler
929 * handles an interface from the list, it should set ifa_flags to 0 to
930 * let know the other handlers that it took care of this interface. This
931 * means that more specific handlers should be before less specific
932 * ones. */
933 for (ifh = ifhs; *ifh != NULL; ifh++)
934 (*ifh)(cfg, ifap);
43c02e7b 935 freeifaddrs(ifap);
6e75df87 936}
43c02e7b 937
6e75df87
VB
938static void
939lldpd_loop(struct lldpd *cfg)
940{
941 /* Main loop.
942
943 1. Update local ports information
944 2. Clean unwanted (removed) local ports
945 3. Update local chassis information
946 4. Send packets
947 5. Receive packets
42b39485 948 6. Update smart mode
6e75df87 949 */
849954d7 950 LOCAL_CHASSIS(cfg)->c_cap_enabled = 0;
6e75df87 951 lldpd_update_localports(cfg);
43c02e7b 952 lldpd_cleanup(cfg);
6e75df87 953 lldpd_update_localchassis(cfg);
43c02e7b
VB
954 lldpd_send_all(cfg);
955 lldpd_recv_all(cfg);
42b39485
VB
956 if (cfg->g_smart != SMART_NOFILTER)
957 lldpd_hide_all(cfg);
43c02e7b
VB
958}
959
8888d191 960static void
43c02e7b
VB
961lldpd_shutdown(int sig)
962{
963 LLOG_INFO("signal received, exiting");
964 exit(0);
965}
966
967/* For signal handling */
8888d191 968static struct lldpd *gcfg = NULL;
43c02e7b 969
8888d191 970static void
43c02e7b
VB
971lldpd_exit()
972{
6e75df87 973 struct lldpd_hardware *hardware, *hardware_next;
b5562b23
VB
974 close(gcfg->g_ctl);
975 priv_ctl_cleanup();
6e75df87
VB
976 for (hardware = TAILQ_FIRST(&gcfg->g_hardware); hardware != NULL;
977 hardware = hardware_next) {
978 hardware_next = TAILQ_NEXT(hardware, h_entries);
979 lldpd_hardware_cleanup(gcfg, hardware);
43c02e7b
VB
980 }
981#ifdef USE_SNMP
982 if (gcfg->g_snmp)
983 agent_shutdown();
984#endif /* USE_SNMP */
985}
986
987int
2acc1418 988lldpd_main(int argc, char *argv[])
43c02e7b
VB
989{
990 struct lldpd *cfg;
77507b69 991 struct lldpd_chassis *lchassis;
e809a587
VB
992 int ch, debug = 0;
993#ifdef USE_SNMP
994 int snmp = 0;
bbea66e1 995 char *agentx = NULL; /* AgentX socket */
e809a587 996#endif
43c02e7b 997 char *mgmtp = NULL;
993a6e50 998 char *popt, opts[] =
42b39485 999 "H:hkdxX:m:p:M:S:i@ ";
de1b1b3a 1000 int i, found, advertise_version = 1;
89840df0 1001#ifdef ENABLE_LLDPMED
e809a587 1002 int lldpmed = 0, noinventory = 0;
89840df0 1003#endif
40ce835b 1004 char *descr_override = NULL;
c036b15d 1005 char *lsb_release = NULL;
42b39485 1006 int smart = SMART_FILTER_NO_TIE | SMART_FILTER_EMISSION | SMART_FILTER_RECEPTION;
43c02e7b
VB
1007
1008 saved_argv = argv;
1009
1010 /*
1011 * Get and parse command line options
1012 */
f0bd3505 1013 popt = strchr(opts, '@');
0c877af0 1014 for (i=0; protos[i].mode != 0; i++)
43c02e7b 1015 *(popt++) = protos[i].arg;
43c02e7b
VB
1016 *popt = '\0';
1017 while ((ch = getopt(argc, argv, opts)) != -1) {
1018 switch (ch) {
b162b740
VB
1019 case 'h':
1020 usage();
1021 break;
43c02e7b
VB
1022 case 'd':
1023 debug++;
1024 break;
1025 case 'm':
1026 mgmtp = optarg;
1027 break;
de1b1b3a
VB
1028 case 'k':
1029 advertise_version = 0;
1030 break;
e809a587 1031#ifdef ENABLE_LLDPMED
115ff55c 1032 case 'M':
89840df0 1033 lldpmed = atoi(optarg);
e809a587
VB
1034 if ((lldpmed < 1) || (lldpmed > 4)) {
1035 fprintf(stderr, "-M requires an argument between 1 and 4\n");
89840df0 1036 usage();
e809a587 1037 }
89840df0 1038 break;
e809a587 1039 case 'i':
e809a587 1040 noinventory = 1;
115ff55c 1041 break;
e809a587 1042#else
115ff55c
VB
1043 case 'M':
1044 case 'i':
115ff55c 1045 case 'P':
e809a587
VB
1046 fprintf(stderr, "LLDP-MED support is not built-in\n");
1047 usage();
e809a587 1048 break;
115ff55c 1049#endif
e809a587 1050#ifdef USE_SNMP
bbea66e1
V
1051 case 'x':
1052 snmp = 1;
1053 break;
1054 case 'X':
43c02e7b 1055 snmp = 1;
bbea66e1
V
1056 agentx = optarg;
1057 break;
e809a587 1058#else
bbea66e1
V
1059 case 'x':
1060 case 'X':
e809a587
VB
1061 fprintf(stderr, "SNMP support is not built-in\n");
1062 usage();
1063#endif
43c02e7b 1064 break;
40ce835b
ST
1065 case 'S':
1066 descr_override = strdup(optarg);
1067 break;
42b39485
VB
1068 case 'H':
1069 smart = SMART_NOFILTER;
1070 i = atoi(optarg);
1071 if (i == 0) break;
1072 if ((i < 0) || (i > 9)) {
1073 fprintf(stderr, "Incorrect mode for -H\n");
1074 usage();
1075 }
1076 if (i%3 != 0)
1077 smart |= SMART_FILTER_RECEPTION;
1078 if ((i + 1)%3 != 0)
1079 smart |= SMART_FILTER_EMISSION;
1080 if (i > 6)
1081 smart |= SMART_FILTER_ONE_NEIGH | SMART_FILTER_NO_TIE;
1082 if (i < 4)
1083 smart |= SMART_FILTER_NO_TIE;
1084 break;
43c02e7b
VB
1085 default:
1086 found = 0;
1087 for (i=0; protos[i].mode != 0; i++) {
43c02e7b 1088 if (ch == protos[i].arg) {
0c877af0
VB
1089 protos[i].enabled++;
1090 /* When an argument enable
1091 several protocols, only the
1092 first one can be forced. */
1093 if (found && protos[i].enabled > 1)
1094 protos[i].enabled = 1;
43c02e7b
VB
1095 found = 1;
1096 }
1097 }
1098 if (!found)
1099 usage();
1100 }
1101 }
115ff55c 1102
6bb9c4e0 1103 log_init(debug, __progname);
4b9a5a23 1104 tzset(); /* Get timezone info before chroot */
a2993d83 1105
eac2f38a
VB
1106 if (!debug) {
1107 int pid;
1108 char *spid;
1109 if (daemon(0, 0) != 0)
1110 fatal("failed to detach daemon");
1111 if ((pid = open(LLDPD_PID_FILE,
0aa5f676 1112 O_TRUNC | O_CREAT | O_WRONLY, 0644)) == -1)
eac2f38a
VB
1113 fatal("unable to open pid file " LLDPD_PID_FILE);
1114 if (asprintf(&spid, "%d\n", getpid()) == -1)
1115 fatal("unable to create pid file " LLDPD_PID_FILE);
1116 if (write(pid, spid, strlen(spid)) == -1)
1117 fatal("unable to write pid file " LLDPD_PID_FILE);
1118 free(spid);
1119 close(pid);
1120 }
1121
c036b15d
VB
1122 lsb_release = lldpd_get_lsb_release();
1123
a2993d83 1124 priv_init(PRIVSEP_CHROOT);
43c02e7b 1125
43c02e7b
VB
1126 if ((cfg = (struct lldpd *)
1127 calloc(1, sizeof(struct lldpd))) == NULL)
1128 fatal(NULL);
1129
766f32b3 1130 cfg->g_mgmt_pattern = mgmtp;
42b39485 1131 cfg->g_smart = smart;
43c02e7b
VB
1132
1133 /* Get ioctl socket */
1134 if ((cfg->g_sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
1135 fatal("failed to get ioctl socket");
1136 cfg->g_delay = LLDPD_TX_DELAY;
1137
c036b15d
VB
1138 /* Description */
1139 if (!(cfg->g_advertise_version = advertise_version))
1140 /* Remove the \n */
1141 lsb_release[strlen(lsb_release) - 1] = '\0';
1142 cfg->g_lsb_release = lsb_release;
40ce835b
ST
1143 if (descr_override)
1144 cfg->g_descr_override = descr_override;
1145
43c02e7b 1146 /* Set system capabilities */
77507b69
VB
1147 if ((lchassis = (struct lldpd_chassis*)
1148 calloc(1, sizeof(struct lldpd_chassis))) == NULL)
1149 fatal(NULL);
1150 lchassis->c_cap_available = LLDP_CAP_BRIDGE | LLDP_CAP_WLAN |
43c02e7b 1151 LLDP_CAP_ROUTER;
89840df0
VB
1152#ifdef ENABLE_LLDPMED
1153 if (lldpmed > 0) {
1154 if (lldpmed == LLDPMED_CLASS_III)
77507b69
VB
1155 lchassis->c_cap_available |= LLDP_CAP_TELEPHONE;
1156 lchassis->c_med_type = lldpmed;
1157 lchassis->c_med_cap_available = LLDPMED_CAP_CAP |
4c0d2715
VB
1158 LLDPMED_CAP_IV | LLDPMED_CAP_LOCATION |
1159 LLDPMED_CAP_POLICY | LLDPMED_CAP_MDI_PSE | LLDPMED_CAP_MDI_PD;
740593ff 1160 cfg->g_noinventory = noinventory;
42bddd41
VB
1161 } else
1162 cfg->g_noinventory = 1;
89840df0 1163#endif
43c02e7b
VB
1164
1165 /* Set TTL */
77507b69 1166 lchassis->c_ttl = LLDPD_TTL;
43c02e7b
VB
1167
1168 cfg->g_protocols = protos;
43c02e7b 1169 for (i=0; protos[i].mode != 0; i++)
0c877af0
VB
1170 if (protos[i].enabled > 1)
1171 LLOG_INFO("protocol %s enabled and forced", protos[i].name);
1172 else if (protos[i].enabled)
43c02e7b 1173 LLOG_INFO("protocol %s enabled", protos[i].name);
0c877af0 1174 else
43c02e7b 1175 LLOG_INFO("protocol %s disabled", protos[i].name);
43c02e7b
VB
1176
1177 TAILQ_INIT(&cfg->g_hardware);
77507b69
VB
1178 TAILQ_INIT(&cfg->g_chassis);
1179 TAILQ_INSERT_TAIL(&cfg->g_chassis, lchassis, c_entries);
9898ac07 1180 lchassis->c_refcount++; /* We should always keep a reference to local chassis */
43c02e7b 1181
77d7090e
VB
1182 TAILQ_INIT(&cfg->g_callbacks);
1183
43c02e7b
VB
1184#ifdef USE_SNMP
1185 if (snmp) {
1186 cfg->g_snmp = 1;
bbea66e1 1187 agent_init(cfg, agentx, debug);
43c02e7b
VB
1188 }
1189#endif /* USE_SNMP */
1190
1191 /* Create socket */
6f1046d1 1192 if ((cfg->g_ctl = priv_ctl_create()) == -1)
b5562b23 1193 fatalx("unable to create control socket " LLDPD_CTL_SOCKET);
77d7090e
VB
1194 if (lldpd_callback_add(cfg, cfg->g_ctl, ctl_accept, NULL) != 0)
1195 fatalx("unable to add callback for control socket");
43c02e7b 1196
43c02e7b
VB
1197 gcfg = cfg;
1198 if (atexit(lldpd_exit) != 0) {
b5562b23
VB
1199 close(cfg->g_ctl);
1200 priv_ctl_cleanup();
43c02e7b
VB
1201 fatal("unable to set exit function");
1202 }
43c02e7b
VB
1203
1204 /* Signal handling */
b5562b23 1205 signal(SIGHUP, lldpd_shutdown);
43c02e7b
VB
1206 signal(SIGINT, lldpd_shutdown);
1207 signal(SIGTERM, lldpd_shutdown);
1208
1209 for (;;)
1210 lldpd_loop(cfg);
1211
1212 return (0);
1213}