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