]> git.ipfire.org Git - thirdparty/lldpd.git/blame_incremental - src/lldpd.c
Harden lldpd with the use of RELRO and NOW linker options.
[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 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 int lldpd_guess_type(struct lldpd *, char *, int);
86static void lldpd_decode(struct lldpd *, char *, int,
87 struct lldpd_hardware *);
88static void lldpd_update_chassis(struct lldpd_chassis *,
89 const struct lldpd_chassis *);
90static char *lldpd_get_lsb_release(void);
91#ifdef ENABLE_LLDPMED
92static void lldpd_med(struct lldpd_chassis *);
93#endif
94
95static char **saved_argv;
96#ifdef HAVE___PROGNAME
97extern const char *__progname;
98#else
99# define __progname "lldpd"
100#endif
101
102static void
103usage(void)
104{
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");
112 fprintf(stderr, "-S descr Override the default system description.\n");
113 fprintf(stderr, "-m IP Specify the management address of this system.\n");
114 fprintf(stderr, "-H mode Specify the behaviour when detecting multiple neighbors.\n");
115#ifdef ENABLE_LLDPMED
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");
121#endif
122#ifdef USE_SNMP
123 fprintf(stderr, "-x Enable SNMP subagent.\n");
124#endif
125 fprintf(stderr, "\n");
126
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
130 fprintf(stderr, "-c Enable the support of CDP protocol. (Cisco)\n");
131#endif
132#ifdef ENABLE_EDP
133 fprintf(stderr, "-e Enable the support of EDP protocol. (Extreme)\n");
134#endif
135#ifdef ENABLE_FDP
136 fprintf(stderr, "-f Enable the support of FDP protocol. (Foundry)\n");
137#endif
138#ifdef ENABLE_SONMP
139 fprintf(stderr, "-s Enable the support of SONMP protocol. (Nortel)\n");
140#endif
141
142 fprintf(stderr, "\n");
143#endif
144
145 fprintf(stderr, "see manual page lldpd(8) for more information\n");
146 exit(1);
147}
148
149struct lldpd_hardware *
150lldpd_get_hardware(struct lldpd *cfg, char *name, int index, struct lldpd_ops *ops)
151{
152 struct lldpd_hardware *hardware;
153 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
154 if ((strcmp(hardware->h_ifname, name) == 0) &&
155 (hardware->h_ifindex == index) &&
156 ((!ops) || (ops == hardware->h_ops)))
157 break;
158 }
159 return hardware;
160}
161
162struct lldpd_hardware *
163lldpd_alloc_hardware(struct lldpd *cfg, char *name)
164{
165 struct lldpd_hardware *hardware;
166
167 if ((hardware = (struct lldpd_hardware *)
168 calloc(1, sizeof(struct lldpd_hardware))) == NULL)
169 return NULL;
170
171 strlcpy(hardware->h_ifname, name, sizeof(hardware->h_ifname));
172 hardware->h_lport.p_chassis = LOCAL_CHASSIS(cfg);
173 hardware->h_lport.p_chassis->c_refcount++;
174 TAILQ_INIT(&hardware->h_rports);
175
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;
187}
188
189#ifdef ENABLE_DOT1
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}
203#endif
204
205/* If `all' is true, clear all information, including information that
206 are not refreshed periodically. Port should be freed manually. */
207void
208lldpd_port_cleanup(struct lldpd *cfg, struct lldpd_port *port, int all)
209{
210#ifdef ENABLE_LLDPMED
211 int i;
212 if (all)
213 for (i=0; i < LLDPMED_LOCFORMAT_LAST; i++)
214 free(port->p_med_location[i].data);
215#endif
216#ifdef ENABLE_DOT1
217 lldpd_vlan_cleanup(port);
218#endif
219 free(port->p_id);
220 free(port->p_descr);
221 if (all) {
222 free(port->p_lastframe);
223 if (port->p_chassis) { /* chassis may not have been attributed, yet */
224 port->p_chassis->c_refcount--;
225 port->p_chassis = NULL;
226 }
227 }
228}
229
230void
231lldpd_chassis_cleanup(struct lldpd_chassis *chassis, int all)
232{
233#ifdef ENABLE_LLDPMED
234 free(chassis->c_med_hw);
235 free(chassis->c_med_sw);
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
242 free(chassis->c_id);
243 free(chassis->c_name);
244 free(chassis->c_descr);
245 if (all)
246 free(chassis);
247}
248
249void
250lldpd_remote_cleanup(struct lldpd *cfg, struct lldpd_hardware *hardware, int all)
251{
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);
266 lldpd_port_cleanup(cfg, port, 1);
267 free(port);
268 }
269 }
270}
271
272void
273lldpd_hardware_cleanup(struct lldpd *cfg, struct lldpd_hardware *hardware)
274{
275 int i;
276 lldpd_port_cleanup(cfg, &hardware->h_lport, 1);
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);
284 for (i=0; i < LLDPD_FD_SETSIZE; i++)
285 if (FD_ISSET(i, &hardware->h_recvfds))
286 close(i);
287 if (hardware->h_sendfd) close(hardware->h_sendfd);
288 }
289 free(hardware);
290}
291
292static void
293lldpd_cleanup(struct lldpd *cfg)
294{
295 struct lldpd_hardware *hardware, *hardware_next;
296 struct lldpd_chassis *chassis, *chassis_next;
297
298 for (hardware = TAILQ_FIRST(&cfg->g_hardware); hardware != NULL;
299 hardware = hardware_next) {
300 hardware_next = TAILQ_NEXT(hardware, h_entries);
301 if (!hardware->h_flags) {
302 TAILQ_REMOVE(&cfg->g_hardware, hardware, h_entries);
303 lldpd_remote_cleanup(cfg, hardware, 1);
304 lldpd_hardware_cleanup(cfg, hardware);
305 } else
306 lldpd_remote_cleanup(cfg, hardware, 0);
307 }
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 }
317}
318
319static int
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
339static void
340lldpd_decode(struct lldpd *cfg, char *frame, int s,
341 struct lldpd_hardware *hardware)
342{
343 int i, result;
344 struct lldpd_chassis *chassis, *ochassis = NULL;
345 struct lldpd_port *port, *oport = NULL;
346 int guess = LLDPD_MODE_LLDP;
347
348 if (s < sizeof(struct ethhdr) + 4)
349 /* Too short, just discard it */
350 return;
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 }
358
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 }
367 }
368
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;
377 chassis->c_protocol = port->p_protocol =
378 cfg->g_protocols[i].mode;
379 break;
380 }
381 }
382 if (cfg->g_protocols[i].mode == 0) {
383 LLOG_INFO("unable to guess frame type");
384 return;
385 }
386
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 }
400 }
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;
410 }
411 }
412
413 if (oport) {
414 /* The port is known, remove it before adding it back */
415 TAILQ_REMOVE(&hardware->h_rports, oport, p_entries);
416 lldpd_port_cleanup(cfg, oport, 1);
417 free(oport);
418 }
419 if (ochassis) {
420 lldpd_update_chassis(ochassis, chassis);
421 free(chassis);
422 chassis = ochassis;
423 } else {
424 /* Chassis not known, add it */
425 chassis->c_index = ++cfg->g_lastrid;
426 chassis->c_refcount = 0;
427 TAILQ_INSERT_TAIL(&cfg->g_chassis, chassis, c_entries);
428 i = 0; TAILQ_FOREACH(ochassis, &cfg->g_chassis, c_entries) i++;
429 LLOG_DEBUG("Currently, we know %d different systems", i);
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++;
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 */
454 i = 0; TAILQ_FOREACH(oport, &hardware->h_rports, p_entries)
455 i++;
456 LLOG_DEBUG("Currently, %s knows %d neighbors",
457 hardware->h_ifname, i);
458 return;
459}
460
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
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
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}
584
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
655static void
656lldpd_recv_all(struct lldpd *cfg)
657{
658 struct lldpd_hardware *hardware;
659 struct lldpd_callback *callback, *callback_next;
660 fd_set rfds;
661 struct timeval tv;
662#ifdef USE_SNMP
663 struct timeval snmptv;
664 int snmpblock = 0;
665#endif
666 int rc, nfds, n;
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 */
682 if ((hardware->h_flags & IFF_RUNNING) == 0)
683 continue;
684 /* This is quite expensive but we don't rely on internal
685 * structure of fd_set. */
686 for (n = 0; n < LLDPD_FD_SETSIZE; n++)
687 if (FD_ISSET(n, &hardware->h_recvfds)) {
688 FD_SET(n, &rfds);
689 if (nfds < n)
690 nfds = n;
691 }
692 }
693 TAILQ_FOREACH(callback, &cfg->g_callbacks, next) {
694 FD_SET(callback->fd, &rfds);
695 if (nfds < callback->fd)
696 nfds = callback->fd;
697 }
698
699#ifdef USE_SNMP
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 }
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) {
729 for (n = 0; n < LLDPD_FD_SETSIZE; n++)
730 if ((FD_ISSET(n, &hardware->h_recvfds)) &&
731 (FD_ISSET(n, &rfds))) break;
732 if (n == LLDPD_FD_SETSIZE) continue;
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) {
740 free(buffer);
741 continue;
742 }
743 hardware->h_rx_cnt++;
744 lldpd_decode(cfg, buffer, n, hardware);
745 free(buffer);
746 break;
747 }
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);
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
766static void
767lldpd_send_all(struct lldpd *cfg)
768{
769 struct lldpd_hardware *hardware;
770 struct lldpd_port *port;
771 int i, sent;
772
773 cfg->g_lastsent = time(NULL);
774 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
775 /* Ignore if interface is down */
776 if ((hardware->h_flags & IFF_RUNNING) == 0)
777 continue;
778
779 sent = 0;
780 for (i=0; cfg->g_protocols[i].mode != 0; i++) {
781 if (!cfg->g_protocols[i].enabled)
782 continue;
783 /* We send only if we have at least one remote system
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 }
790 TAILQ_FOREACH(port, &hardware->h_rports, p_entries) {
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;
796 if (port->p_protocol ==
797 cfg->g_protocols[i].mode) {
798 cfg->g_protocols[i].send(cfg,
799 hardware);
800 sent++;
801 break;
802 }
803 }
804 }
805
806 if (!sent)
807 /* Nothing was sent for this port, let's speak LLDP */
808 cfg->g_protocols[0].send(cfg,
809 hardware);
810 }
811}
812
813#ifdef ENABLE_LLDPMED
814static void
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
832static void
833lldpd_update_localchassis(struct lldpd *cfg)
834{
835 struct utsname un;
836 char *hp;
837 int f;
838 char status;
839 struct lldpd_hardware *hardware;
840
841 /* Set system name and description */
842 if (uname(&un) != 0)
843 fatal("failed to get system information");
844 if ((hp = priv_gethostbyname()) == NULL)
845 fatal("failed to get system name");
846 free(LOCAL_CHASSIS(cfg)->c_name);
847 free(LOCAL_CHASSIS(cfg)->c_descr);
848 if ((LOCAL_CHASSIS(cfg)->c_name = strdup(hp)) == NULL)
849 fatal(NULL);
850 if (cfg->g_descr_override) {
851 if (asprintf(&LOCAL_CHASSIS(cfg)->c_descr, "%s",
852 cfg->g_descr_override) == -1)
853 fatal("failed to set full system description");
854 } else {
855 if (cfg->g_advertise_version) {
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)
859 == -1)
860 fatal("failed to set full system description");
861 } else {
862 if (asprintf(&LOCAL_CHASSIS(cfg)->c_descr, "%s",
863 cfg->g_lsb_release?cfg->g_lsb_release:un.sysname) == -1)
864 fatal("failed to set minimal system description");
865 }
866 }
867
868 /* Check forwarding */
869 if ((f = priv_open("/proc/sys/net/ipv4/ip_forward")) >= 0) {
870 if ((read(f, &status, 1) == 1) && (status == '1')) {
871 LOCAL_CHASSIS(cfg)->c_cap_enabled = LLDP_CAP_ROUTER;
872 }
873 close(f);
874 }
875#ifdef ENABLE_LLDPMED
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);
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");
884#endif
885
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[] = {
905 lldpd_ifh_bond, /* Handle bond */
906 lldpd_ifh_eth, /* Handle classic ethernet interfaces */
907#ifdef ENABLE_DOT1
908 lldpd_ifh_vlan, /* Handle VLAN */
909#endif
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 */
918 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries)
919 hardware->h_flags = 0;
920
921 LOCAL_CHASSIS(cfg)->c_mgmt.s_addr = INADDR_ANY;
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);
935 freeifaddrs(ifap);
936}
937
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
948 6. Update smart mode
949 */
950 LOCAL_CHASSIS(cfg)->c_cap_enabled = 0;
951 lldpd_update_localports(cfg);
952 lldpd_cleanup(cfg);
953 lldpd_update_localchassis(cfg);
954 lldpd_send_all(cfg);
955 lldpd_recv_all(cfg);
956 if (cfg->g_smart != SMART_NOFILTER)
957 lldpd_hide_all(cfg);
958}
959
960static void
961lldpd_shutdown(int sig)
962{
963 LLOG_INFO("signal received, exiting");
964 exit(0);
965}
966
967/* For signal handling */
968static struct lldpd *gcfg = NULL;
969
970static void
971lldpd_exit()
972{
973 struct lldpd_hardware *hardware, *hardware_next;
974 close(gcfg->g_ctl);
975 priv_ctl_cleanup();
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);
980 }
981#ifdef USE_SNMP
982 if (gcfg->g_snmp)
983 agent_shutdown();
984#endif /* USE_SNMP */
985}
986
987int
988lldpd_main(int argc, char *argv[])
989{
990 struct lldpd *cfg;
991 struct lldpd_chassis *lchassis;
992 int ch, debug = 0;
993#ifdef USE_SNMP
994 int snmp = 0;
995 char *agentx = NULL; /* AgentX socket */
996#endif
997 char *mgmtp = NULL;
998 char *popt, opts[] =
999 "H:hkdxX:m:p:M:S:i@ ";
1000 int i, found, advertise_version = 1;
1001#ifdef ENABLE_LLDPMED
1002 int lldpmed = 0, noinventory = 0;
1003#endif
1004 char *descr_override = NULL;
1005 char *lsb_release = NULL;
1006 int smart = SMART_FILTER_NO_TIE | SMART_FILTER_EMISSION | SMART_FILTER_RECEPTION;
1007
1008 saved_argv = argv;
1009
1010 /*
1011 * Get and parse command line options
1012 */
1013 popt = strchr(opts, '@');
1014 for (i=0; protos[i].mode != 0; i++)
1015 *(popt++) = protos[i].arg;
1016 *popt = '\0';
1017 while ((ch = getopt(argc, argv, opts)) != -1) {
1018 switch (ch) {
1019 case 'h':
1020 usage();
1021 break;
1022 case 'd':
1023 debug++;
1024 break;
1025 case 'm':
1026 mgmtp = optarg;
1027 break;
1028 case 'k':
1029 advertise_version = 0;
1030 break;
1031#ifdef ENABLE_LLDPMED
1032 case 'M':
1033 lldpmed = atoi(optarg);
1034 if ((lldpmed < 1) || (lldpmed > 4)) {
1035 fprintf(stderr, "-M requires an argument between 1 and 4\n");
1036 usage();
1037 }
1038 break;
1039 case 'i':
1040 noinventory = 1;
1041 break;
1042#else
1043 case 'M':
1044 case 'i':
1045 case 'P':
1046 fprintf(stderr, "LLDP-MED support is not built-in\n");
1047 usage();
1048 break;
1049#endif
1050#ifdef USE_SNMP
1051 case 'x':
1052 snmp = 1;
1053 break;
1054 case 'X':
1055 snmp = 1;
1056 agentx = optarg;
1057 break;
1058#else
1059 case 'x':
1060 case 'X':
1061 fprintf(stderr, "SNMP support is not built-in\n");
1062 usage();
1063#endif
1064 break;
1065 case 'S':
1066 descr_override = strdup(optarg);
1067 break;
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;
1085 default:
1086 found = 0;
1087 for (i=0; protos[i].mode != 0; i++) {
1088 if (ch == protos[i].arg) {
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;
1095 found = 1;
1096 }
1097 }
1098 if (!found)
1099 usage();
1100 }
1101 }
1102
1103 log_init(debug, __progname);
1104 tzset(); /* Get timezone info before chroot */
1105
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,
1112 O_TRUNC | O_CREAT | O_WRONLY, 0644)) == -1)
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
1122 lsb_release = lldpd_get_lsb_release();
1123
1124 priv_init(PRIVSEP_CHROOT);
1125
1126 if ((cfg = (struct lldpd *)
1127 calloc(1, sizeof(struct lldpd))) == NULL)
1128 fatal(NULL);
1129
1130 cfg->g_mgmt_pattern = mgmtp;
1131 cfg->g_smart = smart;
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
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;
1143 if (descr_override)
1144 cfg->g_descr_override = descr_override;
1145
1146 /* Set system capabilities */
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 |
1151 LLDP_CAP_ROUTER;
1152#ifdef ENABLE_LLDPMED
1153 if (lldpmed > 0) {
1154 if (lldpmed == LLDPMED_CLASS_III)
1155 lchassis->c_cap_available |= LLDP_CAP_TELEPHONE;
1156 lchassis->c_med_type = lldpmed;
1157 lchassis->c_med_cap_available = LLDPMED_CAP_CAP |
1158 LLDPMED_CAP_IV | LLDPMED_CAP_LOCATION |
1159 LLDPMED_CAP_POLICY | LLDPMED_CAP_MDI_PSE | LLDPMED_CAP_MDI_PD;
1160 cfg->g_noinventory = noinventory;
1161 } else
1162 cfg->g_noinventory = 1;
1163#endif
1164
1165 /* Set TTL */
1166 lchassis->c_ttl = LLDPD_TTL;
1167
1168 cfg->g_protocols = protos;
1169 for (i=0; protos[i].mode != 0; i++)
1170 if (protos[i].enabled > 1)
1171 LLOG_INFO("protocol %s enabled and forced", protos[i].name);
1172 else if (protos[i].enabled)
1173 LLOG_INFO("protocol %s enabled", protos[i].name);
1174 else
1175 LLOG_INFO("protocol %s disabled", protos[i].name);
1176
1177 TAILQ_INIT(&cfg->g_hardware);
1178 TAILQ_INIT(&cfg->g_chassis);
1179 TAILQ_INSERT_TAIL(&cfg->g_chassis, lchassis, c_entries);
1180 lchassis->c_refcount++; /* We should always keep a reference to local chassis */
1181
1182 TAILQ_INIT(&cfg->g_callbacks);
1183
1184#ifdef USE_SNMP
1185 if (snmp) {
1186 cfg->g_snmp = 1;
1187 agent_init(cfg, agentx, debug);
1188 }
1189#endif /* USE_SNMP */
1190
1191 /* Create socket */
1192 if ((cfg->g_ctl = priv_ctl_create()) == -1)
1193 fatalx("unable to create control socket " LLDPD_CTL_SOCKET);
1194 if (lldpd_callback_add(cfg, cfg->g_ctl, ctl_accept, NULL) != 0)
1195 fatalx("unable to add callback for control socket");
1196
1197 gcfg = cfg;
1198 if (atexit(lldpd_exit) != 0) {
1199 close(cfg->g_ctl);
1200 priv_ctl_cleanup();
1201 fatal("unable to set exit function");
1202 }
1203
1204 /* Signal handling */
1205 signal(SIGHUP, lldpd_shutdown);
1206 signal(SIGINT, lldpd_shutdown);
1207 signal(SIGTERM, lldpd_shutdown);
1208
1209 for (;;)
1210 lldpd_loop(cfg);
1211
1212 return (0);
1213}