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", 'l', 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
, "-S descr Override the default system description.\n");
110 fprintf(stderr
, "-m IP Specify the management address of this system.\n");
111 #ifdef ENABLE_LLDPMED
112 fprintf(stderr
, "-M class Enable emission of LLDP-MED frame. 'class' should be one of:\n");
113 fprintf(stderr
, " 1 Generic Endpoint (Class I)\n");
114 fprintf(stderr
, " 2 Media Endpoint (Class II)\n");
115 fprintf(stderr
, " 3 Communication Device Endpoints (Class III)\n");
116 fprintf(stderr
, " 4 Network Connectivity Device\n");
119 fprintf(stderr
, "-x Enable SNMP subagent.\n");
121 #ifdef ENABLE_LISTENVLAN
122 fprintf(stderr
, "-v Listen on VLAN as well.\n");
124 fprintf(stderr
, "\n");
126 #if defined ENABLE_CDP || defined ENABLE_EDP || defined ENABLE_FDP || defined ENABLE_SONMP
127 fprintf(stderr
, "Additional protocol support.\n");
129 fprintf(stderr
, "-c Enable the support of CDP protocol. (Cisco)\n");
132 fprintf(stderr
, "-e Enable the support of EDP protocol. (Extreme)\n");
135 fprintf(stderr
, "-f Enable the support of FDP protocol. (Foundry)\n");
138 fprintf(stderr
, "-s Enable the support of SONMP protocol. (Nortel)\n");
141 fprintf(stderr
, "\n");
144 fprintf(stderr
, "see manual page lldpd(8) for more information\n");
148 struct lldpd_hardware
*
149 lldpd_get_hardware(struct lldpd
*cfg
, char *name
, int index
, struct lldpd_ops
*ops
)
151 struct lldpd_hardware
*hardware
;
152 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
153 if ((strcmp(hardware
->h_ifname
, name
) == 0) &&
154 (hardware
->h_ifindex
== index
) &&
155 ((!ops
) || (ops
== hardware
->h_ops
)))
161 struct lldpd_hardware
*
162 lldpd_alloc_hardware(struct lldpd
*cfg
, char *name
)
164 struct lldpd_hardware
*hardware
;
166 if ((hardware
= (struct lldpd_hardware
*)
167 calloc(1, sizeof(struct lldpd_hardware
))) == NULL
)
170 strlcpy(hardware
->h_ifname
, name
, sizeof(hardware
->h_ifname
));
171 hardware
->h_lport
.p_chassis
= LOCAL_CHASSIS(cfg
);
172 hardware
->h_lport
.p_chassis
->c_refcount
++;
173 TAILQ_INIT(&hardware
->h_rports
);
175 #ifdef ENABLE_LLDPMED
176 if (LOCAL_CHASSIS(cfg
)->c_med_cap_available
) {
177 hardware
->h_lport
.p_med_cap_enabled
= LLDPMED_CAP_CAP
;
178 if (!cfg
->g_noinventory
)
179 hardware
->h_lport
.p_med_cap_enabled
|= LLDPMED_CAP_IV
;
183 TAILQ_INIT(&hardware
->h_lport
.p_vlans
);
190 lldpd_vlan_cleanup(struct lldpd_port
*port
)
192 struct lldpd_vlan
*vlan
, *vlan_next
;
193 for (vlan
= TAILQ_FIRST(&port
->p_vlans
);
197 vlan_next
= TAILQ_NEXT(vlan
, v_entries
);
198 TAILQ_REMOVE(&port
->p_vlans
, vlan
, v_entries
);
204 /* If `all' is true, clear all information, including information that
205 are not refreshed periodically. Port should be freed manually. */
207 lldpd_port_cleanup(struct lldpd
*cfg
, struct lldpd_port
*port
, int all
)
209 #ifdef ENABLE_LLDPMED
212 for (i
=0; i
< LLDPMED_LOCFORMAT_LAST
; i
++)
213 free(port
->p_med_location
[i
].data
);
216 lldpd_vlan_cleanup(port
);
221 free(port
->p_lastframe
);
222 if (port
->p_chassis
) { /* chassis may not have been attributed, yet */
223 port
->p_chassis
->c_refcount
--;
224 port
->p_chassis
= NULL
;
230 lldpd_chassis_cleanup(struct lldpd_chassis
*chassis
, int all
)
232 #ifdef ENABLE_LLDPMED
233 free(chassis
->c_med_hw
);
234 free(chassis
->c_med_sw
);
235 free(chassis
->c_med_fw
);
236 free(chassis
->c_med_sn
);
237 free(chassis
->c_med_manuf
);
238 free(chassis
->c_med_model
);
239 free(chassis
->c_med_asset
);
242 free(chassis
->c_name
);
243 free(chassis
->c_descr
);
249 lldpd_remote_cleanup(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
, int all
)
251 struct lldpd_port
*port
, *port_next
;
253 for (port
= TAILQ_FIRST(&hardware
->h_rports
);
256 port_next
= TAILQ_NEXT(port
, p_entries
);
259 (time(NULL
) - port
->p_lastupdate
> port
->p_chassis
->c_ttl
)) {
260 hardware
->h_rx_ageout_cnt
++;
264 TAILQ_REMOVE(&hardware
->h_rports
, port
, p_entries
);
265 lldpd_port_cleanup(cfg
, port
, 1);
272 lldpd_hardware_cleanup(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
)
275 lldpd_port_cleanup(cfg
, &hardware
->h_lport
, 1);
276 /* If we have a dedicated cleanup function, use it. Otherwise,
277 we just free the hardware-dependent data and close all FD
278 in h_recvfds and h_sendfd. */
279 if (hardware
->h_ops
->cleanup
)
280 hardware
->h_ops
->cleanup(cfg
, hardware
);
282 free(hardware
->h_data
);
283 for (i
=0; i
< LLDPD_FD_SETSIZE
; i
++)
284 if (FD_ISSET(i
, &hardware
->h_recvfds
))
286 if (hardware
->h_sendfd
) close(hardware
->h_sendfd
);
292 lldpd_cleanup(struct lldpd
*cfg
)
294 struct lldpd_hardware
*hardware
, *hardware_next
;
295 struct lldpd_chassis
*chassis
, *chassis_next
;
297 for (hardware
= TAILQ_FIRST(&cfg
->g_hardware
); hardware
!= NULL
;
298 hardware
= hardware_next
) {
299 hardware_next
= TAILQ_NEXT(hardware
, h_entries
);
300 if (!hardware
->h_flags
) {
301 TAILQ_REMOVE(&cfg
->g_hardware
, hardware
, h_entries
);
302 lldpd_remote_cleanup(cfg
, hardware
, 1);
303 lldpd_hardware_cleanup(cfg
, hardware
);
305 lldpd_remote_cleanup(cfg
, hardware
, 0);
308 for (chassis
= TAILQ_FIRST(&cfg
->g_chassis
); chassis
;
309 chassis
= chassis_next
) {
310 chassis_next
= TAILQ_NEXT(chassis
, c_entries
);
311 if (chassis
->c_refcount
== 0) {
312 TAILQ_REMOVE(&cfg
->g_chassis
, chassis
, c_entries
);
313 lldpd_chassis_cleanup(chassis
, 1);
319 lldpd_guess_type(struct lldpd
*cfg
, char *frame
, int s
)
324 for (i
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
325 if (!cfg
->g_protocols
[i
].enabled
)
327 if (cfg
->g_protocols
[i
].guess
== NULL
) {
328 if (memcmp(frame
, cfg
->g_protocols
[i
].mac
, ETH_ALEN
) == 0)
329 return cfg
->g_protocols
[i
].mode
;
331 if (cfg
->g_protocols
[i
].guess(frame
, s
))
332 return cfg
->g_protocols
[i
].mode
;
339 lldpd_decode(struct lldpd
*cfg
, char *frame
, int s
,
340 struct lldpd_hardware
*hardware
)
343 struct lldpd_chassis
*chassis
, *ochassis
= NULL
;
344 struct lldpd_port
*port
, *oport
= NULL
;
345 int guess
= LLDPD_MODE_LLDP
;
347 /* Discard VLAN frames */
348 if ((s
>= sizeof(struct ethhdr
)) &&
349 (((struct ethhdr
*)frame
)->h_proto
== htons(ETHERTYPE_VLAN
)))
352 TAILQ_FOREACH(oport
, &hardware
->h_rports
, p_entries
) {
353 if ((oport
->p_lastframe
!= NULL
) &&
354 (oport
->p_lastframe
->size
== s
) &&
355 (memcmp(oport
->p_lastframe
->frame
, frame
, s
) == 0)) {
356 /* Already received the same frame */
357 oport
->p_lastupdate
= time(NULL
);
362 guess
= lldpd_guess_type(cfg
, frame
, s
);
363 for (i
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
364 if (!cfg
->g_protocols
[i
].enabled
)
366 if (cfg
->g_protocols
[i
].mode
== guess
) {
367 if ((result
= cfg
->g_protocols
[i
].decode(cfg
, frame
,
368 s
, hardware
, &chassis
, &port
)) == -1)
370 chassis
->c_protocol
= port
->p_protocol
=
371 cfg
->g_protocols
[i
].mode
;
375 if (cfg
->g_protocols
[i
].mode
== 0) {
376 LLOG_INFO("unable to guess frame type");
380 /* Do we already have the same MSAP somewhere? */
381 TAILQ_FOREACH(oport
, &hardware
->h_rports
, p_entries
) {
382 if ((port
->p_protocol
== oport
->p_protocol
) &&
383 (port
->p_id_subtype
== oport
->p_id_subtype
) &&
384 (port
->p_id_len
== oport
->p_id_len
) &&
385 (memcmp(port
->p_id
, oport
->p_id
, port
->p_id_len
) == 0) &&
386 (chassis
->c_id_subtype
== oport
->p_chassis
->c_id_subtype
) &&
387 (chassis
->c_id_len
== oport
->p_chassis
->c_id_len
) &&
388 (memcmp(chassis
->c_id
, oport
->p_chassis
->c_id
,
389 chassis
->c_id_len
) == 0)) {
390 ochassis
= oport
->p_chassis
;
394 /* No, but do we already know the system? */
396 TAILQ_FOREACH(ochassis
, &cfg
->g_chassis
, c_entries
) {
397 if ((chassis
->c_protocol
== ochassis
->c_protocol
) &&
398 (chassis
->c_id_subtype
== ochassis
->c_id_subtype
) &&
399 (chassis
->c_id_len
== ochassis
->c_id_len
) &&
400 (memcmp(chassis
->c_id
, ochassis
->c_id
,
401 chassis
->c_id_len
) == 0))
407 /* The port is known, remove it before adding it back */
408 TAILQ_REMOVE(&hardware
->h_rports
, oport
, p_entries
);
409 lldpd_port_cleanup(cfg
, oport
, 1);
413 lldpd_update_chassis(ochassis
, chassis
);
417 /* Chassis not known, add it */
418 chassis
->c_index
= ++cfg
->g_lastrid
;
419 chassis
->c_refcount
= 0;
420 TAILQ_INSERT_TAIL(&cfg
->g_chassis
, chassis
, c_entries
);
421 i
= 0; TAILQ_FOREACH(ochassis
, &cfg
->g_chassis
, c_entries
) i
++;
422 LLOG_DEBUG("Currently, we know %d different systems", i
);
425 port
->p_lastchange
= port
->p_lastupdate
= time(NULL
);
426 if ((port
->p_lastframe
= (struct lldpd_frame
*)malloc(s
+
427 sizeof(int))) != NULL
) {
428 port
->p_lastframe
->size
= s
;
429 memcpy(port
->p_lastframe
->frame
, frame
, s
);
431 TAILQ_INSERT_TAIL(&hardware
->h_rports
, port
, p_entries
);
432 port
->p_chassis
= chassis
;
433 port
->p_chassis
->c_refcount
++;
434 /* Several cases are possible :
435 1. chassis is new, its refcount was 0. It is now attached
436 to this port, its refcount is 1.
437 2. chassis already exists and was attached to another
438 port, we increase its refcount accordingly.
439 3. chassis already exists and was attached to the same
440 port, its refcount was decreased with
441 lldpd_port_cleanup() and is now increased again.
443 In all cases, if the port already existed, it has been
444 freed with lldpd_port_cleanup() and therefore, the refcount
445 of the chassis that was attached to it is decreased.
447 i
= 0; TAILQ_FOREACH(oport
, &hardware
->h_rports
, p_entries
) i
++;
448 LLOG_DEBUG("Currently, %s known %d neighbors",
449 hardware
->h_ifname
, i
);
453 /* Update chassis `ochassis' with values from `chassis'. */
455 lldpd_update_chassis(struct lldpd_chassis
*ochassis
,
456 const struct lldpd_chassis
*chassis
) {
457 TAILQ_ENTRY(lldpd_chassis
) entries
;
458 /* We want to keep refcount, index and list stuff from the current
460 int refcount
= ochassis
->c_refcount
;
461 int index
= ochassis
->c_index
;
462 memcpy(&entries
, &ochassis
->c_entries
,
465 lldpd_chassis_cleanup(ochassis
, 0);
466 memcpy(ochassis
, chassis
, sizeof(struct lldpd_chassis
));
467 /* Restore saved values */
468 ochassis
->c_refcount
= refcount
;
469 ochassis
->c_index
= index
;
470 memcpy(&ochassis
->c_entries
, &entries
, sizeof(entries
));
474 lldpd_callback_add(struct lldpd
*cfg
, int fd
, void(*fn
)(CALLBACK_SIG
), void *data
)
476 struct lldpd_callback
*callback
;
477 if ((callback
= (struct lldpd_callback
*)
478 malloc(sizeof(struct lldpd_callback
))) == NULL
)
481 callback
->function
= fn
;
482 callback
->data
= data
;
483 TAILQ_INSERT_TAIL(&cfg
->g_callbacks
, callback
, next
);
488 lldpd_callback_del(struct lldpd
*cfg
, int fd
, void(*fn
)(CALLBACK_SIG
))
490 struct lldpd_callback
*callback
, *callback_next
;
491 for (callback
= TAILQ_FIRST(&cfg
->g_callbacks
);
493 callback
= callback_next
) {
494 callback_next
= TAILQ_NEXT(callback
, next
);
495 if ((callback
->fd
== fd
) &&
496 (callback
->function
= fn
)) {
497 free(callback
->data
);
498 TAILQ_REMOVE(&cfg
->g_callbacks
, callback
, next
);
505 lldpd_recv_all(struct lldpd
*cfg
)
507 struct lldpd_hardware
*hardware
;
508 struct lldpd_callback
*callback
, *callback_next
;
512 struct timeval snmptv
;
519 tv
.tv_sec
= cfg
->g_delay
- (time(NULL
) - cfg
->g_lastsent
);
521 tv
.tv_sec
= LLDPD_TX_DELAY
;
522 if (tv
.tv_sec
>= cfg
->g_delay
)
523 tv
.tv_sec
= cfg
->g_delay
;
529 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
530 /* Ignore if interface is down */
531 if ((hardware
->h_flags
& IFF_RUNNING
) == 0)
533 /* This is quite expensive but we don't rely on internal
534 * structure of fd_set. */
535 for (n
= 0; n
< LLDPD_FD_SETSIZE
; n
++)
536 if (FD_ISSET(n
, &hardware
->h_recvfds
)) {
542 TAILQ_FOREACH(callback
, &cfg
->g_callbacks
, next
) {
543 FD_SET(callback
->fd
, &rfds
);
544 if (nfds
< callback
->fd
)
551 memcpy(&snmptv
, &tv
, sizeof(struct timeval
));
552 snmp_select_info(&nfds
, &rfds
, &snmptv
, &snmpblock
);
554 memcpy(&tv
, &snmptv
, sizeof(struct timeval
));
556 #endif /* USE_SNMP */
562 rc
= select(nfds
+ 1, &rfds
, NULL
, NULL
, &tv
);
566 LLOG_WARN("failure on select");
576 #endif /* USE_SNMP */
577 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
578 for (n
= 0; n
< LLDPD_FD_SETSIZE
; n
++)
579 if ((FD_ISSET(n
, &hardware
->h_recvfds
)) &&
580 (FD_ISSET(n
, &rfds
))) break;
581 if (n
== LLDPD_FD_SETSIZE
) continue;
582 if ((buffer
= (char *)malloc(
583 hardware
->h_mtu
)) == NULL
) {
584 LLOG_WARN("failed to alloc reception buffer");
587 if ((n
= hardware
->h_ops
->recv(cfg
, hardware
,
588 n
, buffer
, hardware
->h_mtu
)) == -1) {
592 hardware
->h_rx_cnt
++;
593 lldpd_decode(cfg
, buffer
, n
, hardware
);
597 for (callback
= TAILQ_FIRST(&cfg
->g_callbacks
);
599 callback
= callback_next
) {
600 /* Callback function can use TAILQ_REMOVE */
601 callback_next
= TAILQ_NEXT(callback
, next
);
602 if (FD_ISSET(callback
->fd
, &rfds
))
603 callback
->function(cfg
, callback
);
609 netsnmp_check_outstanding_agent_requests();
611 #endif /* USE_SNMP */
612 } while ((rc
!= 0) || (time(NULL
) - cfg
->g_lastsent
< cfg
->g_delay
));
616 lldpd_send_all(struct lldpd
*cfg
)
618 struct lldpd_hardware
*hardware
;
619 struct lldpd_port
*port
;
622 cfg
->g_lastsent
= time(NULL
);
623 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
624 /* Ignore if interface is down */
625 if ((hardware
->h_flags
& IFF_RUNNING
) == 0)
629 for (i
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
630 if (!cfg
->g_protocols
[i
].enabled
)
632 /* We send only if we have at least one remote system
633 * speaking this protocol or if the protocol is forced */
634 if (cfg
->g_protocols
[i
].enabled
> 1) {
635 cfg
->g_protocols
[i
].send(cfg
, hardware
);
639 TAILQ_FOREACH(port
, &hardware
->h_rports
, p_entries
) {
640 if (port
->p_protocol
==
641 cfg
->g_protocols
[i
].mode
) {
642 cfg
->g_protocols
[i
].send(cfg
,
651 /* Nothing was sent for this port, let's speak LLDP */
652 cfg
->g_protocols
[0].send(cfg
,
657 #ifdef ENABLE_LLDPMED
659 lldpd_med(struct lldpd_chassis
*chassis
)
661 free(chassis
->c_med_hw
);
662 free(chassis
->c_med_fw
);
663 free(chassis
->c_med_sn
);
664 free(chassis
->c_med_manuf
);
665 free(chassis
->c_med_model
);
666 free(chassis
->c_med_asset
);
667 chassis
->c_med_hw
= dmi_hw();
668 chassis
->c_med_fw
= dmi_fw();
669 chassis
->c_med_sn
= dmi_sn();
670 chassis
->c_med_manuf
= dmi_manuf();
671 chassis
->c_med_model
= dmi_model();
672 chassis
->c_med_asset
= dmi_asset();
677 lldpd_update_localchassis(struct lldpd
*cfg
)
683 struct lldpd_hardware
*hardware
;
685 /* Set system name and description */
687 fatal("failed to get system information");
688 if ((hp
= priv_gethostbyname()) == NULL
)
689 fatal("failed to get system name");
690 free(LOCAL_CHASSIS(cfg
)->c_name
);
691 free(LOCAL_CHASSIS(cfg
)->c_descr
);
692 if ((LOCAL_CHASSIS(cfg
)->c_name
= strdup(hp
)) == NULL
)
694 if (cfg
->g_descr_override
) {
695 if (asprintf(&LOCAL_CHASSIS(cfg
)->c_descr
, "%s",
696 cfg
->g_descr_override
) == -1)
697 fatal("failed to set full system description");
699 if (cfg
->g_advertise_version
) {
700 if (asprintf(&LOCAL_CHASSIS(cfg
)->c_descr
, "%s %s %s %s",
701 un
.sysname
, un
.release
, un
.version
, un
.machine
)
703 fatal("failed to set full system description");
705 if (asprintf(&LOCAL_CHASSIS(cfg
)->c_descr
, "%s",
707 fatal("failed to set minimal system description");
711 /* Check forwarding */
712 if ((f
= priv_open("/proc/sys/net/ipv4/ip_forward")) >= 0) {
713 if ((read(f
, &status
, 1) == 1) && (status
== '1')) {
714 LOCAL_CHASSIS(cfg
)->c_cap_enabled
= LLDP_CAP_ROUTER
;
718 #ifdef ENABLE_LLDPMED
719 if (LOCAL_CHASSIS(cfg
)->c_cap_available
& LLDP_CAP_TELEPHONE
)
720 LOCAL_CHASSIS(cfg
)->c_cap_enabled
|= LLDP_CAP_TELEPHONE
;
721 lldpd_med(LOCAL_CHASSIS(cfg
));
722 free(LOCAL_CHASSIS(cfg
)->c_med_sw
);
723 if (cfg
->g_advertise_version
)
724 LOCAL_CHASSIS(cfg
)->c_med_sw
= strdup(un
.release
);
726 LOCAL_CHASSIS(cfg
)->c_med_sw
= strdup("Unknown");
729 /* Set chassis ID if needed */
730 if ((LOCAL_CHASSIS(cfg
)->c_id
== NULL
) &&
731 (hardware
= TAILQ_FIRST(&cfg
->g_hardware
))) {
732 if ((LOCAL_CHASSIS(cfg
)->c_id
=
733 malloc(sizeof(hardware
->h_lladdr
))) == NULL
)
735 LOCAL_CHASSIS(cfg
)->c_id_subtype
= LLDP_CHASSISID_SUBTYPE_LLADDR
;
736 LOCAL_CHASSIS(cfg
)->c_id_len
= sizeof(hardware
->h_lladdr
);
737 memcpy(LOCAL_CHASSIS(cfg
)->c_id
,
738 hardware
->h_lladdr
, sizeof(hardware
->h_lladdr
));
743 lldpd_update_localports(struct lldpd
*cfg
)
745 struct ifaddrs
*ifap
;
746 struct lldpd_hardware
*hardware
;
747 lldpd_ifhandlers ifhs
[] = {
748 lldpd_ifh_bond
, /* Handle bond */
749 lldpd_ifh_eth
, /* Handle classic ethernet interfaces */
751 lldpd_ifh_vlan
, /* Handle VLAN */
753 lldpd_ifh_mgmt
, /* Handle management address (if not already handled) */
756 lldpd_ifhandlers
*ifh
;
758 /* h_flags is set to 0 for each port. If the port is updated, h_flags
759 * will be set to a non-zero value. This will allow us to clean up any
760 * non up-to-date port */
761 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
)
762 hardware
->h_flags
= 0;
764 LOCAL_CHASSIS(cfg
)->c_mgmt
.s_addr
= INADDR_ANY
;
765 if (getifaddrs(&ifap
) != 0)
766 fatal("lldpd_update_localports: failed to get interface list");
768 /* We will run the list of interfaces through a list of interface
769 * handlers. Each handler will create or update some hardware port (and
770 * will set h_flags to a non zero value. The handler can use the list of
771 * interfaces but this is not mandatory. If the interface handler
772 * handles an interface from the list, it should set ifa_flags to 0 to
773 * let know the other handlers that it took care of this interface. This
774 * means that more specific handlers should be before less specific
776 for (ifh
= ifhs
; *ifh
!= NULL
; ifh
++)
782 lldpd_loop(struct lldpd
*cfg
)
786 1. Update local ports information
787 2. Clean unwanted (removed) local ports
788 3. Update local chassis information
792 LOCAL_CHASSIS(cfg
)->c_cap_enabled
= 0;
793 lldpd_update_localports(cfg
);
795 lldpd_update_localchassis(cfg
);
801 lldpd_shutdown(int sig
)
803 LLOG_INFO("signal received, exiting");
807 /* For signal handling */
808 static struct lldpd
*gcfg
= NULL
;
813 struct lldpd_hardware
*hardware
, *hardware_next
;
816 for (hardware
= TAILQ_FIRST(&gcfg
->g_hardware
); hardware
!= NULL
;
817 hardware
= hardware_next
) {
818 hardware_next
= TAILQ_NEXT(hardware
, h_entries
);
819 lldpd_hardware_cleanup(gcfg
, hardware
);
824 #endif /* USE_SNMP */
828 lldpd_main(int argc
, char *argv
[])
831 struct lldpd_chassis
*lchassis
;
835 char *agentx
= NULL
; /* AgentX socket */
839 #ifdef ENABLE_LISTENVLAN
843 int i
, found
, advertise_version
= 1;
844 #ifdef ENABLE_LISTENVLAN
847 #ifdef ENABLE_LLDPMED
848 int lldpmed
= 0, noinventory
= 0;
850 char *descr_override
= NULL
;
855 * Get and parse command line options
857 popt
= strchr(opts
, '@');
858 for (i
=0; protos
[i
].mode
!= 0; i
++)
859 *(popt
++) = protos
[i
].arg
;
861 while ((ch
= getopt(argc
, argv
, opts
)) != -1) {
866 #ifdef ENABLE_LISTENVLAN
878 advertise_version
= 0;
880 #ifdef ENABLE_LLDPMED
882 lldpmed
= atoi(optarg
);
883 if ((lldpmed
< 1) || (lldpmed
> 4)) {
884 fprintf(stderr
, "-M requires an argument between 1 and 4\n");
895 fprintf(stderr
, "LLDP-MED support is not built-in\n");
910 fprintf(stderr
, "SNMP support is not built-in\n");
915 descr_override
= strdup(optarg
);
919 for (i
=0; protos
[i
].mode
!= 0; i
++) {
920 if (ch
== protos
[i
].arg
) {
922 /* When an argument enable
923 several protocols, only the
924 first one can be forced. */
925 if (found
&& protos
[i
].enabled
> 1)
926 protos
[i
].enabled
= 1;
935 log_init(debug
, __progname
);
936 tzset(); /* Get timezone info before chroot */
941 if (daemon(0, 0) != 0)
942 fatal("failed to detach daemon");
943 if ((pid
= open(LLDPD_PID_FILE
,
944 O_TRUNC
| O_CREAT
| O_WRONLY
, 0644)) == -1)
945 fatal("unable to open pid file " LLDPD_PID_FILE
);
946 if (asprintf(&spid
, "%d\n", getpid()) == -1)
947 fatal("unable to create pid file " LLDPD_PID_FILE
);
948 if (write(pid
, spid
, strlen(spid
)) == -1)
949 fatal("unable to write pid file " LLDPD_PID_FILE
);
954 priv_init(PRIVSEP_CHROOT
);
956 if ((cfg
= (struct lldpd
*)
957 calloc(1, sizeof(struct lldpd
))) == NULL
)
960 cfg
->g_mgmt_pattern
= mgmtp
;
961 cfg
->g_advertise_version
= advertise_version
;
962 #ifdef ENABLE_LISTENVLAN
963 cfg
->g_listen_vlans
= vlan
;
966 /* Get ioctl socket */
967 if ((cfg
->g_sock
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1)
968 fatal("failed to get ioctl socket");
969 cfg
->g_delay
= LLDPD_TX_DELAY
;
972 cfg
->g_descr_override
= descr_override
;
974 /* Set system capabilities */
975 if ((lchassis
= (struct lldpd_chassis
*)
976 calloc(1, sizeof(struct lldpd_chassis
))) == NULL
)
978 lchassis
->c_cap_available
= LLDP_CAP_BRIDGE
| LLDP_CAP_WLAN
|
980 #ifdef ENABLE_LLDPMED
982 if (lldpmed
== LLDPMED_CLASS_III
)
983 lchassis
->c_cap_available
|= LLDP_CAP_TELEPHONE
;
984 lchassis
->c_med_type
= lldpmed
;
985 lchassis
->c_med_cap_available
= LLDPMED_CAP_CAP
|
986 LLDPMED_CAP_IV
| LLDPMED_CAP_LOCATION
|
987 LLDPMED_CAP_POLICY
| LLDPMED_CAP_MDI_PSE
| LLDPMED_CAP_MDI_PD
;
988 cfg
->g_noinventory
= noinventory
;
990 cfg
->g_noinventory
= 1;
994 lchassis
->c_ttl
= LLDPD_TTL
;
996 cfg
->g_protocols
= protos
;
997 for (i
=0; protos
[i
].mode
!= 0; i
++)
998 if (protos
[i
].enabled
> 1)
999 LLOG_INFO("protocol %s enabled and forced", protos
[i
].name
);
1000 else if (protos
[i
].enabled
)
1001 LLOG_INFO("protocol %s enabled", protos
[i
].name
);
1003 LLOG_INFO("protocol %s disabled", protos
[i
].name
);
1005 TAILQ_INIT(&cfg
->g_hardware
);
1006 TAILQ_INIT(&cfg
->g_chassis
);
1007 TAILQ_INSERT_TAIL(&cfg
->g_chassis
, lchassis
, c_entries
);
1008 lchassis
->c_refcount
++; /* We should always keep a reference to local chassis */
1010 TAILQ_INIT(&cfg
->g_callbacks
);
1015 agent_init(cfg
, agentx
, debug
);
1017 #endif /* USE_SNMP */
1020 if ((cfg
->g_ctl
= priv_ctl_create()) == -1)
1021 fatalx("unable to create control socket " LLDPD_CTL_SOCKET
);
1022 if (lldpd_callback_add(cfg
, cfg
->g_ctl
, ctl_accept
, NULL
) != 0)
1023 fatalx("unable to add callback for control socket");
1026 if (atexit(lldpd_exit
) != 0) {
1029 fatal("unable to set exit function");
1032 /* Signal handling */
1033 signal(SIGHUP
, lldpd_shutdown
);
1034 signal(SIGINT
, lldpd_shutdown
);
1035 signal(SIGTERM
, lldpd_shutdown
);