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