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