2 * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
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.
27 #include <sys/utsname.h>
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <sys/select.h>
32 #include <sys/ioctl.h>
33 #include <arpa/inet.h>
34 #include <net/if_arp.h>
36 #if LLDPD_FD_SETSIZE != FD_SETSIZE
37 # warning "FD_SETSIZE is set to an inconsistent value."
41 #include <net-snmp/net-snmp-config.h>
42 #include <net-snmp/net-snmp-includes.h>
43 #include <net-snmp/agent/net-snmp-agent-includes.h>
44 #include <net-snmp/agent/snmp_vars.h>
47 static void usage(void);
49 static struct protocol protos
[] =
51 { LLDPD_MODE_LLDP
, 1, "LLDP", ' ', lldp_send
, lldp_decode
, NULL
,
52 LLDP_MULTICAST_ADDR
},
54 { LLDPD_MODE_CDPV1
, 0, "CDPv1", 'c', cdpv1_send
, cdp_decode
, cdpv1_guess
,
56 { LLDPD_MODE_CDPV2
, 0, "CDPv2", 'c', cdpv2_send
, cdp_decode
, cdpv2_guess
,
60 { LLDPD_MODE_SONMP
, 0, "SONMP", 's', sonmp_send
, sonmp_decode
, NULL
,
61 SONMP_MULTICAST_ADDR
},
64 { LLDPD_MODE_EDP
, 0, "EDP", 'e', edp_send
, edp_decode
, NULL
,
68 { LLDPD_MODE_FDP
, 0, "FDP", 'f', fdp_send
, cdp_decode
, NULL
,
71 { 0, 0, "any", ' ', NULL
, NULL
, NULL
,
75 static void lldpd_update_localchassis(struct lldpd
*);
76 static void lldpd_update_localports(struct lldpd
*);
77 static void lldpd_cleanup(struct lldpd
*);
78 static void lldpd_loop(struct lldpd
*);
79 static void lldpd_shutdown(int);
80 static void lldpd_exit(void);
81 static void lldpd_send_all(struct lldpd
*);
82 static void lldpd_recv_all(struct lldpd
*);
83 static int lldpd_guess_type(struct lldpd
*, char *, int);
84 static void lldpd_decode(struct lldpd
*, char *, int,
85 struct lldpd_hardware
*);
86 static void lldpd_update_chassis(struct lldpd_chassis
*,
87 const struct lldpd_chassis
*);
89 static void lldpd_med(struct lldpd_chassis
*);
92 static char **saved_argv
;
93 #ifdef HAVE___PROGNAME
94 extern const char *__progname
;
96 # define __progname "lldpd"
102 fprintf(stderr
, "Usage: %s [OPTIONS ...]\n", __progname
);
104 fprintf(stderr
, "\n");
106 fprintf(stderr
, "-d Do not daemonize.\n");
107 fprintf(stderr
, "-i Disable LLDP-MED inventory TLV transmission.\n");
108 fprintf(stderr
, "-k Disable advertising of kernel release, version, machine.\n");
109 fprintf(stderr
, "-m IP Specify the management address of this system.\n");
110 #ifdef ENABLE_LLDPMED
111 fprintf(stderr
, "-M class Enable emission of LLDP-MED frame. 'class' should be one of:\n");
112 fprintf(stderr
, " 1 Generic Endpoint (Class I)\n");
113 fprintf(stderr
, " 2 Media Endpoint (Class II)\n");
114 fprintf(stderr
, " 3 Communication Device Endpoints (Class III)\n");
115 fprintf(stderr
, " 4 Network Connectivity Device\n");
118 fprintf(stderr
, "-x Enable SNMP subagent.\n");
120 #ifdef ENABLE_LISTENVLAN
121 fprintf(stderr
, "-v Listen on VLAN as well.\n");
123 fprintf(stderr
, "\n");
125 #if defined ENABLE_CDP || defined ENABLE_EDP || defined ENABLE_FDP || defined ENABLE_SONMP
126 fprintf(stderr
, "Additional protocol support.\n");
128 fprintf(stderr
, "-c Enable the support of CDP protocol. (Cisco)\n");
131 fprintf(stderr
, "-e Enable the support of EDP protocol. (Extreme)\n");
134 fprintf(stderr
, "-f Enable the support of FDP protocol. (Foundry)\n");
137 fprintf(stderr
, "-s Enable the support of SONMP protocol. (Nortel)\n");
140 fprintf(stderr
, "\n");
143 fprintf(stderr
, "see manual page lldpd(8) for more information\n");
147 struct lldpd_hardware
*
148 lldpd_get_hardware(struct lldpd
*cfg
, char *name
, int index
, struct lldpd_ops
*ops
)
150 struct lldpd_hardware
*hardware
;
151 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
152 if ((strcmp(hardware
->h_ifname
, name
) == 0) &&
153 (hardware
->h_ifindex
== index
) &&
154 ((!ops
) || (ops
== hardware
->h_ops
)))
160 struct lldpd_hardware
*
161 lldpd_alloc_hardware(struct lldpd
*cfg
, char *name
)
163 struct lldpd_hardware
*hardware
;
165 if ((hardware
= (struct lldpd_hardware
*)
166 calloc(1, sizeof(struct lldpd_hardware
))) == NULL
)
169 strlcpy(hardware
->h_ifname
, name
, sizeof(hardware
->h_ifname
));
170 hardware
->h_lport
.p_chassis
= LOCAL_CHASSIS(cfg
);
171 hardware
->h_lport
.p_chassis
->c_refcount
++;
172 TAILQ_INIT(&hardware
->h_rports
);
174 #ifdef ENABLE_LLDPMED
175 if (LOCAL_CHASSIS(cfg
)->c_med_cap_available
) {
176 hardware
->h_lport
.p_med_cap_enabled
= LLDPMED_CAP_CAP
;
177 if (!cfg
->g_noinventory
)
178 hardware
->h_lport
.p_med_cap_enabled
|= LLDPMED_CAP_IV
;
182 TAILQ_INIT(&hardware
->h_lport
.p_vlans
);
189 lldpd_vlan_cleanup(struct lldpd_port
*port
)
191 struct lldpd_vlan
*vlan
, *vlan_next
;
192 for (vlan
= TAILQ_FIRST(&port
->p_vlans
);
196 vlan_next
= TAILQ_NEXT(vlan
, v_entries
);
197 TAILQ_REMOVE(&port
->p_vlans
, vlan
, v_entries
);
203 /* If `all' is true, clear all information, including information that
204 are not refreshed periodically. Port should be freed manually. */
206 lldpd_port_cleanup(struct lldpd
*cfg
, struct lldpd_port
*port
, int all
)
208 #ifdef ENABLE_LLDPMED
211 for (i
=0; i
< LLDPMED_LOCFORMAT_LAST
; i
++)
212 free(port
->p_med_location
[i
].data
);
215 lldpd_vlan_cleanup(port
);
220 free(port
->p_lastframe
);
221 if (port
->p_chassis
) { /* chassis may not have been attributed, yet */
222 port
->p_chassis
->c_refcount
--;
223 port
->p_chassis
= NULL
;
229 lldpd_chassis_cleanup(struct lldpd_chassis
*chassis
, int all
)
231 #ifdef ENABLE_LLDPMED
232 free(chassis
->c_med_hw
);
233 free(chassis
->c_med_sw
);
234 free(chassis
->c_med_fw
);
235 free(chassis
->c_med_sn
);
236 free(chassis
->c_med_manuf
);
237 free(chassis
->c_med_model
);
238 free(chassis
->c_med_asset
);
241 free(chassis
->c_name
);
242 free(chassis
->c_descr
);
248 lldpd_remote_cleanup(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
, int all
)
250 struct lldpd_port
*port
, *port_next
;
252 for (port
= TAILQ_FIRST(&hardware
->h_rports
);
255 port_next
= TAILQ_NEXT(port
, p_entries
);
258 (time(NULL
) - port
->p_lastupdate
> port
->p_chassis
->c_ttl
)) {
259 hardware
->h_rx_ageout_cnt
++;
263 TAILQ_REMOVE(&hardware
->h_rports
, port
, p_entries
);
264 lldpd_port_cleanup(cfg
, port
, 1);
271 lldpd_hardware_cleanup(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
)
274 lldpd_port_cleanup(cfg
, &hardware
->h_lport
, 1);
275 /* If we have a dedicated cleanup function, use it. Otherwise,
276 we just free the hardware-dependent data and close all FD
277 in h_recvfds and h_sendfd. */
278 if (hardware
->h_ops
->cleanup
)
279 hardware
->h_ops
->cleanup(cfg
, hardware
);
281 free(hardware
->h_data
);
282 for (i
=0; i
< LLDPD_FD_SETSIZE
; i
++)
283 if (FD_ISSET(i
, &hardware
->h_recvfds
))
285 if (hardware
->h_sendfd
) close(hardware
->h_sendfd
);
291 lldpd_cleanup(struct lldpd
*cfg
)
293 struct lldpd_hardware
*hardware
, *hardware_next
;
294 struct lldpd_chassis
*chassis
, *chassis_next
;
296 for (hardware
= TAILQ_FIRST(&cfg
->g_hardware
); hardware
!= NULL
;
297 hardware
= hardware_next
) {
298 hardware_next
= TAILQ_NEXT(hardware
, h_entries
);
299 if (!hardware
->h_flags
) {
300 TAILQ_REMOVE(&cfg
->g_hardware
, hardware
, h_entries
);
301 lldpd_remote_cleanup(cfg
, hardware
, 1);
302 lldpd_hardware_cleanup(cfg
, hardware
);
304 lldpd_remote_cleanup(cfg
, hardware
, 0);
307 for (chassis
= TAILQ_FIRST(&cfg
->g_chassis
); chassis
;
308 chassis
= chassis_next
) {
309 chassis_next
= TAILQ_NEXT(chassis
, c_entries
);
310 if (chassis
->c_refcount
== 0) {
311 TAILQ_REMOVE(&cfg
->g_chassis
, chassis
, c_entries
);
312 lldpd_chassis_cleanup(chassis
, 1);
318 lldpd_guess_type(struct lldpd
*cfg
, char *frame
, int s
)
323 for (i
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
324 if (!cfg
->g_protocols
[i
].enabled
)
326 if (cfg
->g_protocols
[i
].guess
== NULL
) {
327 if (memcmp(frame
, cfg
->g_protocols
[i
].mac
, ETH_ALEN
) == 0)
328 return cfg
->g_protocols
[i
].mode
;
330 if (cfg
->g_protocols
[i
].guess(frame
, s
))
331 return cfg
->g_protocols
[i
].mode
;
338 lldpd_decode(struct lldpd
*cfg
, char *frame
, int s
,
339 struct lldpd_hardware
*hardware
)
342 struct lldpd_chassis
*chassis
, *ochassis
= NULL
;
343 struct lldpd_port
*port
, *oport
= NULL
;
344 int guess
= LLDPD_MODE_LLDP
;
346 /* Discard VLAN frames */
347 if ((s
>= sizeof(struct ethhdr
)) &&
348 (((struct ethhdr
*)frame
)->h_proto
== htons(ETHERTYPE_VLAN
)))
351 TAILQ_FOREACH(oport
, &hardware
->h_rports
, p_entries
) {
352 if ((oport
->p_lastframe
!= NULL
) &&
353 (oport
->p_lastframe
->size
== s
) &&
354 (memcmp(oport
->p_lastframe
->frame
, frame
, s
) == 0)) {
355 /* Already received the same frame */
356 oport
->p_lastupdate
= time(NULL
);
361 guess
= lldpd_guess_type(cfg
, frame
, s
);
362 for (i
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
363 if (!cfg
->g_protocols
[i
].enabled
)
365 if (cfg
->g_protocols
[i
].mode
== guess
) {
366 if ((result
= cfg
->g_protocols
[i
].decode(cfg
, frame
,
367 s
, hardware
, &chassis
, &port
)) == -1)
369 chassis
->c_protocol
= port
->p_protocol
=
370 cfg
->g_protocols
[i
].mode
;
374 if (cfg
->g_protocols
[i
].mode
== 0) {
375 LLOG_INFO("unable to guess frame type");
379 /* Do we already have the same MSAP somewhere? */
380 TAILQ_FOREACH(oport
, &hardware
->h_rports
, p_entries
) {
381 if ((port
->p_protocol
== oport
->p_protocol
) &&
382 (port
->p_id_subtype
== oport
->p_id_subtype
) &&
383 (port
->p_id_len
== oport
->p_id_len
) &&
384 (memcmp(port
->p_id
, oport
->p_id
, port
->p_id_len
) == 0) &&
385 (chassis
->c_id_subtype
== oport
->p_chassis
->c_id_subtype
) &&
386 (chassis
->c_id_len
== oport
->p_chassis
->c_id_len
) &&
387 (memcmp(chassis
->c_id
, oport
->p_chassis
->c_id
,
388 chassis
->c_id_len
) == 0)) {
389 ochassis
= oport
->p_chassis
;
393 /* No, but do we already know the system? */
395 TAILQ_FOREACH(ochassis
, &cfg
->g_chassis
, c_entries
) {
396 if ((chassis
->c_protocol
== ochassis
->c_protocol
) &&
397 (chassis
->c_id_subtype
== ochassis
->c_id_subtype
) &&
398 (chassis
->c_id_len
== ochassis
->c_id_len
) &&
399 (memcmp(chassis
->c_id
, ochassis
->c_id
,
400 chassis
->c_id_len
) == 0))
406 /* The port is known, remove it before adding it back */
407 TAILQ_REMOVE(&hardware
->h_rports
, oport
, p_entries
);
408 lldpd_port_cleanup(cfg
, oport
, 1);
412 lldpd_update_chassis(ochassis
, chassis
);
416 /* Chassis not known, add it */
417 chassis
->c_index
= ++cfg
->g_lastrid
;
418 chassis
->c_refcount
= 0;
419 TAILQ_INSERT_TAIL(&cfg
->g_chassis
, chassis
, c_entries
);
420 i
= 0; TAILQ_FOREACH(ochassis
, &cfg
->g_chassis
, c_entries
) i
++;
421 LLOG_DEBUG("Currently, we know %d different systems", i
);
424 port
->p_lastchange
= port
->p_lastupdate
= time(NULL
);
425 if ((port
->p_lastframe
= (struct lldpd_frame
*)malloc(s
+
426 sizeof(int))) != NULL
) {
427 port
->p_lastframe
->size
= s
;
428 memcpy(port
->p_lastframe
->frame
, frame
, s
);
430 TAILQ_INSERT_TAIL(&hardware
->h_rports
, port
, p_entries
);
431 port
->p_chassis
= chassis
;
432 port
->p_chassis
->c_refcount
++;
433 /* Several cases are possible :
434 1. chassis is new, its refcount was 0. It is now attached
435 to this port, its refcount is 1.
436 2. chassis already exists and was attached to another
437 port, we increase its refcount accordingly.
438 3. chassis already exists and was attached to the same
439 port, its refcount was decreased with
440 lldpd_port_cleanup() and is now increased again.
442 In all cases, if the port already existed, it has been
443 freed with lldpd_port_cleanup() and therefore, the refcount
444 of the chassis that was attached to it is decreased.
446 i
= 0; TAILQ_FOREACH(oport
, &hardware
->h_rports
, p_entries
) i
++;
447 LLOG_DEBUG("Currently, %s known %d neighbors",
448 hardware
->h_ifname
, i
);
452 /* Update chassis `ochassis' with values from `chassis'. */
454 lldpd_update_chassis(struct lldpd_chassis
*ochassis
,
455 const struct lldpd_chassis
*chassis
) {
456 TAILQ_ENTRY(lldpd_chassis
) entries
;
457 /* We want to keep refcount, index and list stuff from the current
459 int refcount
= ochassis
->c_refcount
;
460 int index
= ochassis
->c_index
;
461 memcpy(&entries
, &ochassis
->c_entries
,
464 lldpd_chassis_cleanup(ochassis
, 0);
465 memcpy(ochassis
, chassis
, sizeof(struct lldpd_chassis
));
466 /* Restore saved values */
467 ochassis
->c_refcount
= refcount
;
468 ochassis
->c_index
= index
;
469 memcpy(&ochassis
->c_entries
, &entries
, sizeof(entries
));
473 lldpd_callback_add(struct lldpd
*cfg
, int fd
, void(*fn
)(CALLBACK_SIG
), void *data
)
475 struct lldpd_callback
*callback
;
476 if ((callback
= (struct lldpd_callback
*)
477 malloc(sizeof(struct lldpd_callback
))) == NULL
)
480 callback
->function
= fn
;
481 callback
->data
= data
;
482 TAILQ_INSERT_TAIL(&cfg
->g_callbacks
, callback
, next
);
487 lldpd_callback_del(struct lldpd
*cfg
, int fd
, void(*fn
)(CALLBACK_SIG
))
489 struct lldpd_callback
*callback
, *callback_next
;
490 for (callback
= TAILQ_FIRST(&cfg
->g_callbacks
);
492 callback
= callback_next
) {
493 callback_next
= TAILQ_NEXT(callback
, next
);
494 if ((callback
->fd
== fd
) &&
495 (callback
->function
= fn
)) {
496 free(callback
->data
);
497 TAILQ_REMOVE(&cfg
->g_callbacks
, callback
, next
);
504 lldpd_recv_all(struct lldpd
*cfg
)
506 struct lldpd_hardware
*hardware
;
507 struct lldpd_callback
*callback
, *callback_next
;
512 struct timeval
*tvp
= &tv
;
518 tv
.tv_sec
= cfg
->g_delay
- (time(NULL
) - cfg
->g_lastsent
);
520 tv
.tv_sec
= LLDPD_TX_DELAY
;
521 if (tv
.tv_sec
>= cfg
->g_delay
)
522 tv
.tv_sec
= cfg
->g_delay
;
528 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
529 /* Ignore if interface is down */
530 if ((hardware
->h_flags
& IFF_RUNNING
) == 0)
532 /* This is quite expensive but we don't rely on internal
533 * structure of fd_set. */
534 for (n
= 0; n
< LLDPD_FD_SETSIZE
; n
++)
535 if (FD_ISSET(n
, &hardware
->h_recvfds
)) {
541 TAILQ_FOREACH(callback
, &cfg
->g_callbacks
, next
) {
542 FD_SET(callback
->fd
, &rfds
);
543 if (nfds
< callback
->fd
)
549 snmp_select_info(&nfds
, &rfds
, tvp
, &fakeblock
);
550 #endif /* USE_SNMP */
556 rc
= select(nfds
+ 1, &rfds
, NULL
, NULL
, &tv
);
560 LLOG_WARN("failure on select");
570 #endif /* USE_SNMP */
571 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
572 for (n
= 0; n
< LLDPD_FD_SETSIZE
; n
++)
573 if ((FD_ISSET(n
, &hardware
->h_recvfds
)) &&
574 (FD_ISSET(n
, &rfds
))) break;
575 if (n
== LLDPD_FD_SETSIZE
) continue;
576 if ((buffer
= (char *)malloc(
577 hardware
->h_mtu
)) == NULL
) {
578 LLOG_WARN("failed to alloc reception buffer");
581 if ((n
= hardware
->h_ops
->recv(cfg
, hardware
,
582 n
, buffer
, hardware
->h_mtu
)) == -1) {
586 hardware
->h_rx_cnt
++;
587 lldpd_decode(cfg
, buffer
, n
, hardware
);
591 for (callback
= TAILQ_FIRST(&cfg
->g_callbacks
);
593 callback
= callback_next
) {
594 /* Callback function can use TAILQ_REMOVE */
595 callback_next
= TAILQ_NEXT(callback
, next
);
596 if (FD_ISSET(callback
->fd
, &rfds
))
597 callback
->function(cfg
, callback
);
603 netsnmp_check_outstanding_agent_requests();
605 #endif /* USE_SNMP */
606 } while ((rc
!= 0) || (time(NULL
) - cfg
->g_lastsent
< cfg
->g_delay
));
610 lldpd_send_all(struct lldpd
*cfg
)
612 struct lldpd_hardware
*hardware
;
613 struct lldpd_port
*port
;
616 cfg
->g_lastsent
= time(NULL
);
617 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
618 /* Ignore if interface is down */
619 if ((hardware
->h_flags
& IFF_RUNNING
) == 0)
623 for (i
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
624 if (!cfg
->g_protocols
[i
].enabled
)
626 /* We send only if we have at least one remote system
627 * speaking this protocol */
628 TAILQ_FOREACH(port
, &hardware
->h_rports
, p_entries
) {
629 if (port
->p_protocol
==
630 cfg
->g_protocols
[i
].mode
) {
631 cfg
->g_protocols
[i
].send(cfg
,
640 /* Nothing was sent for this port, let's speak LLDP */
641 cfg
->g_protocols
[0].send(cfg
,
646 #ifdef ENABLE_LLDPMED
648 lldpd_med(struct lldpd_chassis
*chassis
)
650 free(chassis
->c_med_hw
);
651 free(chassis
->c_med_fw
);
652 free(chassis
->c_med_sn
);
653 free(chassis
->c_med_manuf
);
654 free(chassis
->c_med_model
);
655 free(chassis
->c_med_asset
);
656 chassis
->c_med_hw
= dmi_hw();
657 chassis
->c_med_fw
= dmi_fw();
658 chassis
->c_med_sn
= dmi_sn();
659 chassis
->c_med_manuf
= dmi_manuf();
660 chassis
->c_med_model
= dmi_model();
661 chassis
->c_med_asset
= dmi_asset();
666 lldpd_update_localchassis(struct lldpd
*cfg
)
672 struct lldpd_hardware
*hardware
;
674 /* Set system name and description */
676 fatal("failed to get system information");
677 if ((hp
= priv_gethostbyname()) == NULL
)
678 fatal("failed to get system name");
679 free(LOCAL_CHASSIS(cfg
)->c_name
);
680 free(LOCAL_CHASSIS(cfg
)->c_descr
);
681 if ((LOCAL_CHASSIS(cfg
)->c_name
= strdup(hp
)) == NULL
)
683 if (cfg
->g_advertise_version
) {
684 if (asprintf(&LOCAL_CHASSIS(cfg
)->c_descr
, "%s %s %s %s",
685 un
.sysname
, un
.release
, un
.version
, un
.machine
) == -1)
686 fatal("failed to set full system description");
688 if (asprintf(&LOCAL_CHASSIS(cfg
)->c_descr
, "%s", un
.sysname
) == -1)
689 fatal("failed to set minimal system description");
692 /* Check forwarding */
693 if ((f
= priv_open("/proc/sys/net/ipv4/ip_forward")) >= 0) {
694 if ((read(f
, &status
, 1) == 1) && (status
== '1')) {
695 LOCAL_CHASSIS(cfg
)->c_cap_enabled
= LLDP_CAP_ROUTER
;
699 #ifdef ENABLE_LLDPMED
700 if (LOCAL_CHASSIS(cfg
)->c_cap_available
& LLDP_CAP_TELEPHONE
)
701 LOCAL_CHASSIS(cfg
)->c_cap_enabled
|= LLDP_CAP_TELEPHONE
;
702 lldpd_med(LOCAL_CHASSIS(cfg
));
703 free(LOCAL_CHASSIS(cfg
)->c_med_sw
);
704 if (cfg
->g_advertise_version
)
705 LOCAL_CHASSIS(cfg
)->c_med_sw
= strdup(un
.release
);
707 LOCAL_CHASSIS(cfg
)->c_med_sw
= strdup("Unknown");
710 /* Set chassis ID if needed */
711 if ((LOCAL_CHASSIS(cfg
)->c_id
== NULL
) &&
712 (hardware
= TAILQ_FIRST(&cfg
->g_hardware
))) {
713 if ((LOCAL_CHASSIS(cfg
)->c_id
=
714 malloc(sizeof(hardware
->h_lladdr
))) == NULL
)
716 LOCAL_CHASSIS(cfg
)->c_id_subtype
= LLDP_CHASSISID_SUBTYPE_LLADDR
;
717 LOCAL_CHASSIS(cfg
)->c_id_len
= sizeof(hardware
->h_lladdr
);
718 memcpy(LOCAL_CHASSIS(cfg
)->c_id
,
719 hardware
->h_lladdr
, sizeof(hardware
->h_lladdr
));
724 lldpd_update_localports(struct lldpd
*cfg
)
726 struct ifaddrs
*ifap
;
727 struct lldpd_hardware
*hardware
;
728 lldpd_ifhandlers ifhs
[] = {
729 lldpd_ifh_bond
, /* Handle bond */
730 lldpd_ifh_eth
, /* Handle classic ethernet interfaces */
732 lldpd_ifh_vlan
, /* Handle VLAN */
734 lldpd_ifh_mgmt
, /* Handle management address (if not already handled) */
737 lldpd_ifhandlers
*ifh
;
739 /* h_flags is set to 0 for each port. If the port is updated, h_flags
740 * will be set to a non-zero value. This will allow us to clean up any
741 * non up-to-date port */
742 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
)
743 hardware
->h_flags
= 0;
745 LOCAL_CHASSIS(cfg
)->c_mgmt
.s_addr
= INADDR_ANY
;
746 if (getifaddrs(&ifap
) != 0)
747 fatal("lldpd_update_localports: failed to get interface list");
749 /* We will run the list of interfaces through a list of interface
750 * handlers. Each handler will create or update some hardware port (and
751 * will set h_flags to a non zero value. The handler can use the list of
752 * interfaces but this is not mandatory. If the interface handler
753 * handles an interface from the list, it should set ifa_flags to 0 to
754 * let know the other handlers that it took care of this interface. This
755 * means that more specific handlers should be before less specific
757 for (ifh
= ifhs
; *ifh
!= NULL
; ifh
++)
763 lldpd_loop(struct lldpd
*cfg
)
767 1. Update local ports information
768 2. Clean unwanted (removed) local ports
769 3. Update local chassis information
773 LOCAL_CHASSIS(cfg
)->c_cap_enabled
= 0;
774 lldpd_update_localports(cfg
);
776 lldpd_update_localchassis(cfg
);
782 lldpd_shutdown(int sig
)
784 LLOG_INFO("signal received, exiting");
788 /* For signal handling */
789 static struct lldpd
*gcfg
= NULL
;
794 struct lldpd_hardware
*hardware
, *hardware_next
;
797 for (hardware
= TAILQ_FIRST(&gcfg
->g_hardware
); hardware
!= NULL
;
798 hardware
= hardware_next
) {
799 hardware_next
= TAILQ_NEXT(hardware
, h_entries
);
800 lldpd_hardware_cleanup(gcfg
, hardware
);
805 #endif /* USE_SNMP */
809 lldpd_main(int argc
, char *argv
[])
812 struct lldpd_chassis
*lchassis
;
816 char *agentx
= NULL
; /* AgentX socket */
820 #ifdef ENABLE_LISTENVLAN
824 int i
, found
, advertise_version
= 1;
825 #ifdef ENABLE_LISTENVLAN
828 #ifdef ENABLE_LLDPMED
829 int lldpmed
= 0, noinventory
= 0;
835 * Get and parse command line options
837 popt
= strchr(opts
, '@');
838 for (i
=0; protos
[i
].mode
!= 0; i
++) {
839 if (protos
[i
].enabled
== 1) continue;
840 *(popt
++) = protos
[i
].arg
;
843 while ((ch
= getopt(argc
, argv
, opts
)) != -1) {
848 #ifdef ENABLE_LISTENVLAN
860 advertise_version
= 0;
862 #ifdef ENABLE_LLDPMED
864 lldpmed
= atoi(optarg
);
865 if ((lldpmed
< 1) || (lldpmed
> 4)) {
866 fprintf(stderr
, "-M requires an argument between 1 and 4\n");
877 fprintf(stderr
, "LLDP-MED support is not built-in\n");
892 fprintf(stderr
, "SNMP support is not built-in\n");
898 for (i
=0; protos
[i
].mode
!= 0; i
++) {
899 if (protos
[i
].enabled
) continue;
900 if (ch
== protos
[i
].arg
) {
901 protos
[i
].enabled
= 1;
910 log_init(debug
, __progname
);
911 tzset(); /* Get timezone info before chroot */
916 if (daemon(0, 0) != 0)
917 fatal("failed to detach daemon");
918 if ((pid
= open(LLDPD_PID_FILE
,
919 O_TRUNC
| O_CREAT
| O_WRONLY
, 0644)) == -1)
920 fatal("unable to open pid file " LLDPD_PID_FILE
);
921 if (asprintf(&spid
, "%d\n", getpid()) == -1)
922 fatal("unable to create pid file " LLDPD_PID_FILE
);
923 if (write(pid
, spid
, strlen(spid
)) == -1)
924 fatal("unable to write pid file " LLDPD_PID_FILE
);
929 priv_init(PRIVSEP_CHROOT
);
931 if ((cfg
= (struct lldpd
*)
932 calloc(1, sizeof(struct lldpd
))) == NULL
)
935 cfg
->g_mgmt_pattern
= mgmtp
;
936 cfg
->g_advertise_version
= advertise_version
;
937 #ifdef ENABLE_LISTENVLAN
938 cfg
->g_listen_vlans
= vlan
;
941 /* Get ioctl socket */
942 if ((cfg
->g_sock
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1)
943 fatal("failed to get ioctl socket");
944 cfg
->g_delay
= LLDPD_TX_DELAY
;
946 /* Set system capabilities */
947 if ((lchassis
= (struct lldpd_chassis
*)
948 calloc(1, sizeof(struct lldpd_chassis
))) == NULL
)
950 lchassis
->c_cap_available
= LLDP_CAP_BRIDGE
| LLDP_CAP_WLAN
|
952 #ifdef ENABLE_LLDPMED
954 if (lldpmed
== LLDPMED_CLASS_III
)
955 lchassis
->c_cap_available
|= LLDP_CAP_TELEPHONE
;
956 lchassis
->c_med_type
= lldpmed
;
957 lchassis
->c_med_cap_available
= LLDPMED_CAP_CAP
|
958 LLDPMED_CAP_IV
| LLDPMED_CAP_LOCATION
;
959 cfg
->g_noinventory
= noinventory
;
961 cfg
->g_noinventory
= 1;
965 lchassis
->c_ttl
= LLDPD_TTL
;
967 cfg
->g_protocols
= protos
;
968 for (i
=0; protos
[i
].mode
!= 0; i
++)
969 if (protos
[i
].enabled
) {
970 LLOG_INFO("protocol %s enabled", protos
[i
].name
);
972 LLOG_INFO("protocol %s disabled", protos
[i
].name
);
974 TAILQ_INIT(&cfg
->g_hardware
);
975 TAILQ_INIT(&cfg
->g_chassis
);
976 TAILQ_INSERT_TAIL(&cfg
->g_chassis
, lchassis
, c_entries
);
977 lchassis
->c_refcount
++; /* We should always keep a reference to local chassis */
979 TAILQ_INIT(&cfg
->g_callbacks
);
984 agent_init(cfg
, agentx
, debug
);
986 #endif /* USE_SNMP */
989 if ((cfg
->g_ctl
= priv_ctl_create()) == -1)
990 fatalx("unable to create control socket " LLDPD_CTL_SOCKET
);
991 if (lldpd_callback_add(cfg
, cfg
->g_ctl
, ctl_accept
, NULL
) != 0)
992 fatalx("unable to add callback for control socket");
995 if (atexit(lldpd_exit
) != 0) {
998 fatal("unable to set exit function");
1001 /* Signal handling */
1002 signal(SIGHUP
, lldpd_shutdown
);
1003 signal(SIGINT
, lldpd_shutdown
);
1004 signal(SIGTERM
, lldpd_shutdown
);