1 /* -*- mode: c; c-file-style: "openbsd" -*- */
3 * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
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.
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.
29 #include <sys/utsname.h>
30 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <sys/select.h>
35 #include <sys/ioctl.h>
36 #include <arpa/inet.h>
37 #include <net/if_arp.h>
41 static void usage(void);
43 static struct protocol protos
[] =
45 { LLDPD_MODE_LLDP
, 1, "LLDP", 'l', lldp_send
, lldp_decode
, NULL
,
46 LLDP_MULTICAST_ADDR
},
48 { LLDPD_MODE_CDPV1
, 0, "CDPv1", 'c', cdpv1_send
, cdp_decode
, cdpv1_guess
,
50 { LLDPD_MODE_CDPV2
, 0, "CDPv2", 'c', cdpv2_send
, cdp_decode
, cdpv2_guess
,
54 { LLDPD_MODE_SONMP
, 0, "SONMP", 's', sonmp_send
, sonmp_decode
, NULL
,
55 SONMP_MULTICAST_ADDR
},
58 { LLDPD_MODE_EDP
, 0, "EDP", 'e', edp_send
, edp_decode
, NULL
,
62 { LLDPD_MODE_FDP
, 0, "FDP", 'f', fdp_send
, cdp_decode
, NULL
,
65 { 0, 0, "any", ' ', NULL
, NULL
, NULL
,
69 static char **saved_argv
;
70 #ifdef HAVE___PROGNAME
71 extern const char *__progname
;
73 # define __progname "lldpd"
79 fprintf(stderr
, "Usage: %s [OPTIONS ...]\n", __progname
);
80 fprintf(stderr
, "Version: %s\n", PACKAGE_STRING
);
82 fprintf(stderr
, "\n");
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");
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");
101 fprintf(stderr
, "-x Enable SNMP subagent.\n");
103 fprintf(stderr
, "\n");
105 #if defined ENABLE_CDP || defined ENABLE_EDP || defined ENABLE_FDP || defined ENABLE_SONMP
106 fprintf(stderr
, "Additional protocol support.\n");
108 fprintf(stderr
, "-c Enable the support of CDP protocol. (Cisco)\n");
111 fprintf(stderr
, "-e Enable the support of EDP protocol. (Extreme)\n");
114 fprintf(stderr
, "-f Enable the support of FDP protocol. (Foundry)\n");
117 fprintf(stderr
, "-s Enable the support of SONMP protocol. (Nortel)\n");
120 fprintf(stderr
, "\n");
123 fprintf(stderr
, "see manual page lldpd(8) for more information\n");
127 struct lldpd_hardware
*
128 lldpd_get_hardware(struct lldpd
*cfg
, char *name
, int index
, struct lldpd_ops
*ops
)
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
)))
140 struct lldpd_hardware
*
141 lldpd_alloc_hardware(struct lldpd
*cfg
, char *name
)
143 struct lldpd_hardware
*hardware
;
145 if ((hardware
= (struct lldpd_hardware
*)
146 calloc(1, sizeof(struct lldpd_hardware
))) == NULL
)
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
);
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
;
163 TAILQ_INIT(&hardware
->h_lport
.p_vlans
);
164 TAILQ_INIT(&hardware
->h_lport
.p_ppvids
);
165 TAILQ_INIT(&hardware
->h_lport
.p_pids
);
168 levent_hardware_init(hardware
);
173 lldpd_alloc_mgmt(int family
, void *addrptr
, size_t addrsize
, u_int32_t iface
)
175 struct lldpd_mgmt
*mgmt
;
177 if (family
<= LLDPD_AF_UNSPEC
|| family
>= LLDPD_AF_LAST
) {
178 errno
= EAFNOSUPPORT
;
181 if (addrsize
> LLDPD_MGMT_MAXADDRSIZE
) {
185 mgmt
= calloc(1, sizeof(struct lldpd_mgmt
));
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
;
199 lldpd_hardware_cleanup(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
)
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
);
209 notify_clients_deletion(struct lldpd_hardware
*hardware
,
210 struct lldpd_port
*rport
)
212 levent_ctl_notify(hardware
->h_ifname
, NEIGHBOR_CHANGE_DELETED
,
215 agent_notify(hardware
, NEIGHBOR_CHANGE_DELETED
, rport
);
220 lldpd_cleanup(struct lldpd
*cfg
)
222 struct lldpd_hardware
*hardware
, *hardware_next
;
223 struct lldpd_chassis
*chassis
, *chassis_next
;
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
);
233 lldpd_remote_cleanup(hardware
, notify_clients_deletion
);
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);
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. */
249 lldpd_move_chassis(struct lldpd_chassis
*ochassis
,
250 struct lldpd_chassis
*chassis
) {
251 struct lldpd_mgmt
*mgmt
, *mgmt_next
;
253 /* We want to keep refcount, index and list stuff from the current
255 TAILQ_ENTRY(lldpd_chassis
) entries
;
256 int refcount
= ochassis
->c_refcount
;
257 int index
= ochassis
->c_index
;
258 memcpy(&entries
, &ochassis
->c_entries
,
260 lldpd_chassis_cleanup(ochassis
, 0);
263 /* WARNING: this is a kludgy hack, we need in-place copy and cannot use
265 memcpy(ochassis
, chassis
, sizeof(struct lldpd_chassis
));
266 TAILQ_INIT(&ochassis
->c_mgmt
);
268 /* Copy of management addresses */
269 for (mgmt
= TAILQ_FIRST(&chassis
->c_mgmt
);
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
);
277 /* Restore saved values */
278 ochassis
->c_refcount
= refcount
;
279 ochassis
->c_index
= index
;
280 memcpy(&ochassis
->c_entries
, &entries
, sizeof(entries
));
282 /* Get rid of the new chassis */
287 lldpd_guess_type(struct lldpd
*cfg
, char *frame
, int s
)
292 for (i
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
293 if (!cfg
->g_protocols
[i
].enabled
)
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
;
299 if (cfg
->g_protocols
[i
].guess(frame
, s
))
300 return cfg
->g_protocols
[i
].mode
;
307 lldpd_decode(struct lldpd
*cfg
, char *frame
, int s
,
308 struct lldpd_hardware
*hardware
)
311 struct lldpd_chassis
*chassis
, *ochassis
= NULL
;
312 struct lldpd_port
*port
, *oport
= NULL
, *aport
;
313 int guess
= LLDPD_MODE_LLDP
;
315 if (s
< sizeof(struct ethhdr
) + 4)
316 /* Too short, just discard it */
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
);
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
);
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
)
340 if (cfg
->g_protocols
[i
].mode
== guess
) {
341 if ((result
= cfg
->g_protocols
[i
].decode(cfg
, frame
,
342 s
, hardware
, &chassis
, &port
)) == -1)
344 chassis
->c_protocol
= port
->p_protocol
=
345 cfg
->g_protocols
[i
].mode
;
349 if (cfg
->g_protocols
[i
].mode
== 0) {
350 LLOG_DEBUG("unable to guess frame type on %s",
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
;
369 /* No, but do we already know the system? */
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))
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);
388 lldpd_move_chassis(ochassis
, chassis
);
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
);
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
);
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.
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.
421 i
= 0; TAILQ_FOREACH(aport
, &hardware
->h_rports
, p_entries
)
423 LLOG_DEBUG("Currently, %s knows %d neighbors",
424 hardware
->h_ifname
, i
);
426 if (!oport
) hardware
->h_insert_cnt
++;
429 i
= oport
?NEIGHBOR_CHANGE_UPDATED
:NEIGHBOR_CHANGE_ADDED
;
430 levent_ctl_notify(hardware
->h_ifname
, i
, port
);
432 agent_notify(hardware
, i
, port
);
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 */
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
;
449 LLOG_WARN("unable to get a pair of pipes");
453 if ((pid
= fork()) < 0) {
454 LLOG_WARN("unable to fork");
459 /* Child, exec lsb_release */
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
);
472 /* Father, read the output from the children */
476 status
= read(pipefd
[0], release
+count
, sizeof(release
)-count
);
477 if ((status
== -1) && (errno
== EINTR
)) continue;
480 } while (count
< sizeof(release
) && (status
> 0));
482 LLOG_WARN("unable to read from lsb_release");
484 waitpid(pid
, &status
, 0);
488 if (count
>= sizeof(release
)) {
489 LLOG_INFO("output of lsb_release is too large");
490 waitpid(pid
, &status
, 0);
494 if (waitpid(pid
, &status
, 0) != pid
)
496 if (!WIFEXITED(status
) || (WEXITSTATUS(status
) != 0)) {
497 LLOG_INFO("lsb_release information not available");
501 LLOG_INFO("lsb_release returned an empty string");
504 release
[count
] = '\0';
507 /* Should not be here */
511 /* Same like lldpd_get_lsb_release but reads /etc/os-release for PRETTY_NAME=. */
513 lldpd_get_os_release() {
514 static char release
[1024];
517 char *ptr1
= release
;
518 char *ptr2
= release
;
520 FILE *fp
= fopen("/etc/os-release", "r");
522 LLOG_WARN("could not open /etc/os-release");
526 while ((fgets(line
, 1024, fp
) != NULL
)) {
527 key
= strtok(line
, "=");
528 val
= strtok(NULL
, "=");
530 if (strncmp(key
, "PRETTY_NAME", 1024) == 0) {
531 strncpy(release
, val
, 1024);
537 /* Remove trailing newline and all " in the string. */
539 if ((*ptr1
== '"') || (*ptr1
== '\n')) {
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];
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
]++;
563 /* Turn the protocols[] array into an array of
564 enabled/disabled protocols. 1 means enabled, 0
566 min
= (unsigned int)-1;
567 for (i
= 0; i
<= LLDPD_MODE_MAX
; i
++)
568 if (protocols
[i
] && (protocols
[i
] < min
))
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
))
579 } else protocols
[i
] = 0;
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;
586 port
->p_hidden_in
= protocols
[port
->p_protocol
]?0:1;
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
)) {
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
)
599 if (mask
== SMART_INCOMING
) {
600 if (found
) port
->p_hidden_in
= 1;
601 if (!port
->p_hidden_in
)
607 /* Print a debug message summarizing the operation */
608 for (i
= 0; i
<= LLDPD_MODE_MAX
; i
++) protocols
[i
] = 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
))) {
614 protocols
[port
->p_protocol
] = 1;
619 for (i
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
620 if (cfg
->g_protocols
[i
].enabled
&& protocols
[cfg
->g_protocols
[i
].mode
]) {
622 strlen(cfg
->g_protocols
[i
].name
) + 3 > sizeof(buffer
)) {
623 /* Unlikely, our buffer is too small */
624 memcpy(buffer
+ sizeof(buffer
) - 4, "...", 4);
628 strcat(buffer
, ", ");
629 strcat(buffer
, cfg
->g_protocols
[i
].name
);
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)");
637 /* Hide unwanted ports depending on smart mode set by the user */
639 lldpd_hide_all(struct lldpd
*cfg
)
641 struct lldpd_hardware
*hardware
;
643 if (!cfg
->g_config
.c_smart
)
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
);
654 lldpd_recv(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
, int fd
)
658 if ((buffer
= (char *)malloc(hardware
->h_mtu
)) == NULL
) {
659 LLOG_WARN("failed to alloc reception buffer");
662 if ((n
= hardware
->h_ops
->recv(cfg
, hardware
,
664 hardware
->h_mtu
)) == -1) {
668 hardware
->h_rx_cnt
++;
669 lldpd_decode(cfg
, buffer
, n
, hardware
);
670 lldpd_hide_all(cfg
); /* Immediatly hide */
675 lldpd_send_all(struct lldpd
*cfg
)
677 struct lldpd_hardware
*hardware
;
678 struct lldpd_port
*port
;
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)
689 for (i
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
690 if (!cfg
->g_protocols
[i
].enabled
)
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
);
699 TAILQ_FOREACH(port
, &hardware
->h_rports
, p_entries
) {
700 /* If this remote port is disabled, we don't
702 if (port
->p_hidden_out
)
704 if (port
->p_protocol
==
705 cfg
->g_protocols
[i
].mode
) {
706 cfg
->g_protocols
[i
].send(cfg
,
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
,
723 if (cfg
->g_protocols
[i
].mode
== 0)
724 LLOG_WARNX("no protocol enabled, dunno what to send");
729 #ifdef ENABLE_LLDPMED
731 lldpd_med(struct lldpd_chassis
*chassis
)
733 #if __i386__ || __amd64__
734 static short int once
= 0;
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();
749 lldpd_update_localchassis(struct lldpd
*cfg
)
756 /* Set system name and description */
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
)
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");
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
)
775 fatal("failed to set full system description");
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");
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
;
788 LOCAL_CHASSIS(cfg
)->c_cap_enabled
&= ~LLDP_CAP_ROUTER
;
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
);
799 LOCAL_CHASSIS(cfg
)->c_med_sw
= strdup("Unknown");
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)
806 if (LOCAL_CHASSIS(cfg
)->c_id
== NULL
) {
807 if (!(LOCAL_CHASSIS(cfg
)->c_id
= strdup(LOCAL_CHASSIS(cfg
)->c_name
)))
809 LOCAL_CHASSIS(cfg
)->c_id_len
= strlen(LOCAL_CHASSIS(cfg
)->c_name
);
810 LOCAL_CHASSIS(cfg
)->c_id_subtype
= LLDP_CHASSISID_SUBTYPE_LOCAL
;
815 lldpd_update_localports(struct lldpd
*cfg
)
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 */
824 lldpd_ifh_vlan
, /* Handle VLAN */
826 lldpd_ifh_mgmt
, /* Handle management address (if not already handled) */
827 lldpd_ifh_chassis
, /* Handle chassis ID (if not already handled) */
830 lldpd_ifhandlers
*ifh
;
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;
838 if (getifaddrs(&ifap
) != 0)
839 fatal("lldpd_update_localports: failed to get interface list");
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
849 for (ifh
= ifhs
; *ifh
!= NULL
; ifh
++)
855 lldpd_loop(struct lldpd
*cfg
)
859 1. Update local ports information
860 2. Clean unwanted (removed) local ports
861 3. Update local chassis information
865 LLOG_DEBUG("start new loop");
866 LOCAL_CHASSIS(cfg
)->c_cap_enabled
= 0;
867 lldpd_update_localports(cfg
);
869 lldpd_update_localchassis(cfg
);
874 lldpd_exit(struct lldpd
*cfg
)
876 struct lldpd_hardware
*hardware
, *hardware_next
;
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
);
887 struct intint
{ int a
; int b
; };
888 static const struct intint filters
[] = {
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
},
924 lldpd_main(int argc
, char *argv
[])
927 struct lldpd_chassis
*lchassis
;
931 char *agentx
= NULL
; /* AgentX socket */
935 char *interfaces
= NULL
;
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;
942 char *descr_override
= NULL
;
943 char *platform_override
= NULL
;
944 char *lsb_release
= NULL
;
949 /* Non privileged user */
958 * Get and parse command line options
960 popt
= strchr(opts
, '@');
961 for (i
=0; protos
[i
].mode
!= 0; i
++)
962 *(popt
++) = protos
[i
].arg
;
964 while ((ch
= getopt(argc
, argv
, opts
)) != -1) {
970 fprintf(stdout
, "%s\n", PACKAGE_VERSION
);
989 advertise_version
= 0;
991 #ifdef ENABLE_LLDPMED
993 lldpmed
= atoi(optarg
);
994 if ((lldpmed
< 1) || (lldpmed
> 4)) {
995 fprintf(stderr
, "-M requires an argument between 1 and 4\n");
1005 fprintf(stderr
, "LLDP-MED support is not built-in\n");
1020 fprintf(stderr
, "SNMP support is not built-in\n");
1025 descr_override
= strdup(optarg
);
1028 platform_override
= strdup(optarg
);
1031 smart
= atoi(optarg
);
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;
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");
1058 smart
= filters
[i
].b
;
1060 log_init(debug
, __progname
);
1061 tzset(); /* Get timezone info before chroot */
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");
1067 if ((group
= getgrnam(PRIVSEP_GROUP
)) == NULL
)
1068 fatal("no " PRIVSEP_GROUP
" group for privilege separation");
1069 gid
= group
->gr_gid
;
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");
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");
1085 /* Disable SIGPIPE */
1086 signal(SIGPIPE
, SIG_IGN
);
1088 /* Detach if needed */
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
);
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();
1109 lsb_release
= lldpd_get_lsb_release();
1112 priv_init(PRIVSEP_CHROOT
, ctl
, uid
, gid
);
1114 /* Initialization of global configuration */
1115 if ((cfg
= (struct lldpd
*)
1116 calloc(1, sizeof(struct lldpd
))) == NULL
)
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
;
1127 cfg
->g_snmp_agentx
= agentx
;
1128 #endif /* USE_SNMP */
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
;
1136 if (!(cfg
->g_config
.c_advertise_version
= advertise_version
) && lsb_release
)
1138 lsb_release
[strlen(lsb_release
) - 1] = '\0';
1139 cfg
->g_lsb_release
= lsb_release
;
1141 cfg
->g_config
.c_description
= descr_override
;
1143 if (platform_override
)
1144 cfg
->g_config
.c_platform
= platform_override
;
1146 /* Set system capabilities */
1147 if ((lchassis
= (struct lldpd_chassis
*)
1148 calloc(1, sizeof(struct lldpd_chassis
))) == NULL
)
1150 lchassis
->c_cap_available
= LLDP_CAP_BRIDGE
| LLDP_CAP_WLAN
|
1152 TAILQ_INIT(&lchassis
->c_mgmt
);
1153 #ifdef ENABLE_LLDPMED
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
;
1163 cfg
->g_config
.c_noinventory
= 1;
1167 lchassis
->c_ttl
= LLDPD_TTL
;
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
);
1176 LLOG_INFO("protocol %s disabled", protos
[i
].name
);
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 */