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