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>
37 #include <net-snmp/net-snmp-config.h>
38 #include <net-snmp/net-snmp-includes.h>
39 #include <net-snmp/agent/net-snmp-agent-includes.h>
40 #include <net-snmp/agent/snmp_vars.h>
43 static void usage(void);
45 static struct protocol protos
[] =
47 { LLDPD_MODE_LLDP
, 1, "LLDP", ' ', lldp_send
, lldp_decode
, NULL
,
48 LLDP_MULTICAST_ADDR
},
50 { LLDPD_MODE_CDPV1
, 0, "CDPv1", 'c', cdpv1_send
, cdp_decode
, cdpv1_guess
,
52 { LLDPD_MODE_CDPV2
, 0, "CDPv2", 'c', cdpv2_send
, cdp_decode
, cdpv2_guess
,
56 { LLDPD_MODE_SONMP
, 0, "SONMP", 's', sonmp_send
, sonmp_decode
, NULL
,
57 SONMP_MULTICAST_ADDR
},
60 { LLDPD_MODE_EDP
, 0, "EDP", 'e', edp_send
, edp_decode
, NULL
,
64 { LLDPD_MODE_FDP
, 0, "FDP", 'f', fdp_send
, cdp_decode
, NULL
,
67 { 0, 0, "any", ' ', NULL
, NULL
, NULL
,
71 static void lldpd_update_localchassis(struct lldpd
*);
72 static void lldpd_update_localports(struct lldpd
*);
73 static void lldpd_cleanup(struct lldpd
*);
74 static void lldpd_loop(struct lldpd
*);
75 static void lldpd_shutdown(int);
76 static void lldpd_exit(void);
77 static void lldpd_send_all(struct lldpd
*);
78 static void lldpd_recv_all(struct lldpd
*);
79 static int lldpd_guess_type(struct lldpd
*, char *, int);
80 static void lldpd_decode(struct lldpd
*, char *, int,
81 struct lldpd_hardware
*);
82 static void lldpd_update_chassis(struct lldpd_chassis
*,
83 const struct lldpd_chassis
*);
85 static void lldpd_med(struct lldpd_chassis
*);
88 static char **saved_argv
;
89 #ifdef HAVE___PROGNAME
90 extern const char *__progname
;
92 # define __progname "lldpd"
98 fprintf(stderr
, "usage: %s [options]\n", __progname
);
99 fprintf(stderr
, "see manual page lldpd(8) for more information\n");
103 struct lldpd_hardware
*
104 lldpd_get_hardware(struct lldpd
*cfg
, char *name
, int index
, struct lldpd_ops
*ops
)
106 struct lldpd_hardware
*hardware
;
107 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
108 if ((strcmp(hardware
->h_ifname
, name
) == 0) &&
109 (hardware
->h_ifindex
== index
) &&
110 ((!ops
) || (ops
== hardware
->h_ops
)))
116 struct lldpd_hardware
*
117 lldpd_alloc_hardware(struct lldpd
*cfg
, char *name
)
119 struct lldpd_hardware
*hardware
;
121 if ((hardware
= (struct lldpd_hardware
*)
122 calloc(1, sizeof(struct lldpd_hardware
))) == NULL
)
125 strlcpy(hardware
->h_ifname
, name
, sizeof(hardware
->h_ifname
));
126 hardware
->h_lport
.p_chassis
= LOCAL_CHASSIS(cfg
);
127 TAILQ_INIT(&hardware
->h_rports
);
129 #ifdef ENABLE_LLDPMED
130 if (LOCAL_CHASSIS(cfg
)->c_med_cap_available
) {
131 hardware
->h_lport
.p_med_cap_enabled
= LLDPMED_CAP_CAP
;
132 if (!cfg
->g_noinventory
)
133 hardware
->h_lport
.p_med_cap_enabled
|= LLDPMED_CAP_IV
;
137 TAILQ_INIT(&hardware
->h_lport
.p_vlans
);
144 lldpd_vlan_cleanup(struct lldpd_port
*port
)
146 struct lldpd_vlan
*vlan
, *vlan_next
;
147 for (vlan
= TAILQ_FIRST(&port
->p_vlans
);
151 vlan_next
= TAILQ_NEXT(vlan
, v_entries
);
152 TAILQ_REMOVE(&port
->p_vlans
, vlan
, v_entries
);
158 /* If `all' is true, clear all information, including information that
159 are not refreshed periodically. Port should be freed manually. */
161 lldpd_port_cleanup(struct lldpd_port
*port
, int all
)
163 #ifdef ENABLE_LLDPMED
166 for (i
=0; i
< LLDPMED_LOCFORMAT_LAST
; i
++)
167 free(port
->p_med_location
[i
].data
);
170 lldpd_vlan_cleanup(port
);
175 free(port
->p_lastframe
);
176 if (port
->p_chassis
) /* chassis may not have been attributed, yet */
177 port
->p_chassis
->c_refcount
--;
182 lldpd_chassis_cleanup(struct lldpd_chassis
*chassis
, int all
)
184 #ifdef ENABLE_LLDPMED
185 free(chassis
->c_med_hw
);
186 free(chassis
->c_med_sw
);
187 free(chassis
->c_med_fw
);
188 free(chassis
->c_med_sn
);
189 free(chassis
->c_med_manuf
);
190 free(chassis
->c_med_model
);
191 free(chassis
->c_med_asset
);
194 free(chassis
->c_name
);
195 free(chassis
->c_descr
);
201 lldpd_remote_cleanup(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
, int all
)
203 struct lldpd_port
*port
, *port_next
;
205 for (port
= TAILQ_FIRST(&hardware
->h_rports
);
208 port_next
= TAILQ_NEXT(port
, p_entries
);
211 (time(NULL
) - port
->p_lastupdate
> port
->p_chassis
->c_ttl
)) {
212 hardware
->h_rx_ageout_cnt
++;
216 TAILQ_REMOVE(&hardware
->h_rports
, port
, p_entries
);
217 lldpd_port_cleanup(port
, 1);
224 lldpd_hardware_cleanup(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
)
227 lldpd_port_cleanup(&hardware
->h_lport
, 1);
228 /* If we have a dedicated cleanup function, use it. Otherwise,
229 we just free the hardware-dependent data and close all FD
230 in h_recvfds and h_sendfd. */
231 if (hardware
->h_ops
->cleanup
)
232 hardware
->h_ops
->cleanup(cfg
, hardware
);
234 free(hardware
->h_data
);
235 for (i
=0; i
< FD_SETSIZE
; i
++)
236 if (FD_ISSET(i
, &hardware
->h_recvfds
))
238 if (hardware
->h_sendfd
) close(hardware
->h_sendfd
);
244 lldpd_cleanup(struct lldpd
*cfg
)
246 struct lldpd_hardware
*hardware
, *hardware_next
;
248 for (hardware
= TAILQ_FIRST(&cfg
->g_hardware
); hardware
!= NULL
;
249 hardware
= hardware_next
) {
250 hardware_next
= TAILQ_NEXT(hardware
, h_entries
);
251 if (!hardware
->h_flags
) {
252 TAILQ_REMOVE(&cfg
->g_hardware
, hardware
, h_entries
);
253 lldpd_remote_cleanup(cfg
, hardware
, 1);
254 lldpd_hardware_cleanup(cfg
, hardware
);
256 lldpd_remote_cleanup(cfg
, hardware
, 0);
261 lldpd_guess_type(struct lldpd
*cfg
, char *frame
, int s
)
266 for (i
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
267 if (!cfg
->g_protocols
[i
].enabled
)
269 if (cfg
->g_protocols
[i
].guess
== NULL
) {
270 if (memcmp(frame
, cfg
->g_protocols
[i
].mac
, ETH_ALEN
) == 0)
271 return cfg
->g_protocols
[i
].mode
;
273 if (cfg
->g_protocols
[i
].guess(frame
, s
))
274 return cfg
->g_protocols
[i
].mode
;
281 lldpd_decode(struct lldpd
*cfg
, char *frame
, int s
,
282 struct lldpd_hardware
*hardware
)
285 struct lldpd_chassis
*chassis
, *ochassis
= NULL
;
286 struct lldpd_port
*port
, *oport
= NULL
;
287 int guess
= LLDPD_MODE_LLDP
;
289 /* Discard VLAN frames */
290 if ((s
>= sizeof(struct ethhdr
)) &&
291 (((struct ethhdr
*)frame
)->h_proto
== htons(ETHERTYPE_VLAN
)))
294 TAILQ_FOREACH(oport
, &hardware
->h_rports
, p_entries
) {
295 if ((oport
->p_lastframe
!= NULL
) &&
296 (oport
->p_lastframe
->size
== s
) &&
297 (memcmp(oport
->p_lastframe
->frame
, frame
, s
) == 0)) {
298 /* Already received the same frame */
299 oport
->p_lastupdate
= time(NULL
);
304 guess
= lldpd_guess_type(cfg
, frame
, s
);
305 for (i
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
306 if (!cfg
->g_protocols
[i
].enabled
)
308 if (cfg
->g_protocols
[i
].mode
== guess
) {
309 if ((result
= cfg
->g_protocols
[i
].decode(cfg
, frame
,
310 s
, hardware
, &chassis
, &port
)) == -1)
312 chassis
->c_protocol
= port
->p_protocol
=
313 cfg
->g_protocols
[i
].mode
;
317 if (cfg
->g_protocols
[i
].mode
== 0) {
318 LLOG_INFO("unable to guess frame type");
322 /* Do we already have the same MSAP somewhere? */
323 TAILQ_FOREACH(oport
, &hardware
->h_rports
, p_entries
) {
324 if ((port
->p_protocol
== oport
->p_protocol
) &&
325 (port
->p_id_subtype
== oport
->p_id_subtype
) &&
326 (port
->p_id_len
== oport
->p_id_len
) &&
327 (memcmp(port
->p_id
, oport
->p_id
, port
->p_id_len
) == 0) &&
328 (chassis
->c_id_subtype
== oport
->p_chassis
->c_id_subtype
) &&
329 (chassis
->c_id_len
== oport
->p_chassis
->c_id_len
) &&
330 (memcmp(chassis
->c_id
, oport
->p_chassis
->c_id
,
331 chassis
->c_id_len
) == 0)) {
332 ochassis
= oport
->p_chassis
;
336 /* No, but do we already know the system? */
338 TAILQ_FOREACH(ochassis
, &cfg
->g_chassis
, c_entries
) {
339 if ((chassis
->c_protocol
== ochassis
->c_protocol
) &&
340 (chassis
->c_id_subtype
== ochassis
->c_id_subtype
) &&
341 (chassis
->c_id_len
== ochassis
->c_id_len
) &&
342 (memcmp(chassis
->c_id
, ochassis
->c_id
,
343 chassis
->c_id_len
) == 0))
349 /* The port is known, remove it before adding it back */
350 TAILQ_REMOVE(&hardware
->h_rports
, oport
, p_entries
);
351 lldpd_port_cleanup(oport
, 1);
355 lldpd_update_chassis(ochassis
, chassis
);
359 /* Chassis not known, add it */
360 chassis
->c_index
= ++cfg
->g_lastrid
;
361 port
->p_chassis
= chassis
;
362 chassis
->c_refcount
= 0;
363 TAILQ_INSERT_TAIL(&cfg
->g_chassis
, chassis
, c_entries
);
364 i
= 0; TAILQ_FOREACH(ochassis
, &cfg
->g_chassis
, c_entries
) i
++;
365 LLOG_DEBUG("Currently, we know %d different systems", i
);
368 port
->p_lastchange
= port
->p_lastupdate
= time(NULL
);
369 if ((port
->p_lastframe
= (struct lldpd_frame
*)malloc(s
+
370 sizeof(int))) != NULL
) {
371 port
->p_lastframe
->size
= s
;
372 memcpy(port
->p_lastframe
->frame
, frame
, s
);
374 TAILQ_INSERT_TAIL(&hardware
->h_rports
, port
, p_entries
);
375 port
->p_chassis
= chassis
;
376 port
->p_chassis
->c_refcount
++;
377 i
= 0; TAILQ_FOREACH(oport
, &hardware
->h_rports
, p_entries
) i
++;
378 LLOG_DEBUG("Currently, %s known %d neighbors",
379 hardware
->h_ifname
, i
);
383 /* Update chassis `ochassis' with values from `chassis'. */
385 lldpd_update_chassis(struct lldpd_chassis
*ochassis
,
386 const struct lldpd_chassis
*chassis
) {
387 TAILQ_ENTRY(lldpd_chassis
) entries
;
388 /* We want to keep refcount, index and list stuff from the current
390 int refcount
= ochassis
->c_refcount
;
391 int index
= ochassis
->c_index
;
392 memcpy(&entries
, &ochassis
->c_entries
,
395 lldpd_chassis_cleanup(ochassis
, 0);
396 memcpy(ochassis
, chassis
, sizeof(struct lldpd_chassis
));
397 /* Restore saved values */
398 ochassis
->c_refcount
= refcount
;
399 ochassis
->c_index
= index
;
400 memcpy(&ochassis
->c_entries
, &entries
, sizeof(entries
));
404 lldpd_callback_add(struct lldpd
*cfg
, int fd
, void(*fn
)(CALLBACK_SIG
), void *data
)
406 struct lldpd_callback
*callback
;
407 if ((callback
= (struct lldpd_callback
*)
408 malloc(sizeof(struct lldpd_callback
))) == NULL
)
411 callback
->function
= fn
;
412 callback
->data
= data
;
413 TAILQ_INSERT_TAIL(&cfg
->g_callbacks
, callback
, next
);
418 lldpd_callback_del(struct lldpd
*cfg
, int fd
, void(*fn
)(CALLBACK_SIG
))
420 struct lldpd_callback
*callback
, *callback_next
;
421 for (callback
= TAILQ_FIRST(&cfg
->g_callbacks
);
423 callback
= callback_next
) {
424 callback_next
= TAILQ_NEXT(callback
, next
);
425 if ((callback
->fd
== fd
) &&
426 (callback
->function
= fn
)) {
427 free(callback
->data
);
428 TAILQ_REMOVE(&cfg
->g_callbacks
, callback
, next
);
435 lldpd_recv_all(struct lldpd
*cfg
)
437 struct lldpd_hardware
*hardware
;
438 struct lldpd_callback
*callback
, *callback_next
;
443 struct timeval
*tvp
= &tv
;
449 tv
.tv_sec
= cfg
->g_delay
- (time(NULL
) - cfg
->g_lastsent
);
451 tv
.tv_sec
= LLDPD_TX_DELAY
;
452 if (tv
.tv_sec
>= cfg
->g_delay
)
453 tv
.tv_sec
= cfg
->g_delay
;
459 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
460 /* Ignore if interface is down */
461 if ((hardware
->h_flags
& IFF_RUNNING
) == 0)
463 /* This is quite expensive but we don't rely on internal
464 * structure of fd_set. */
465 for (n
= 0; n
< FD_SETSIZE
; n
++)
466 if (FD_ISSET(n
, &hardware
->h_recvfds
)) {
472 TAILQ_FOREACH(callback
, &cfg
->g_callbacks
, next
) {
473 FD_SET(callback
->fd
, &rfds
);
474 if (nfds
< callback
->fd
)
480 snmp_select_info(&nfds
, &rfds
, tvp
, &fakeblock
);
481 #endif /* USE_SNMP */
487 rc
= select(nfds
+ 1, &rfds
, NULL
, NULL
, &tv
);
491 LLOG_WARN("failure on select");
501 #endif /* USE_SNMP */
502 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
503 for (n
= 0; n
< FD_SETSIZE
; n
++)
504 if ((FD_ISSET(n
, &hardware
->h_recvfds
)) &&
505 (FD_ISSET(n
, &rfds
))) break;
506 if (n
== FD_SETSIZE
) continue;
507 if ((buffer
= (char *)malloc(
508 hardware
->h_mtu
)) == NULL
) {
509 LLOG_WARN("failed to alloc reception buffer");
512 if ((n
= hardware
->h_ops
->recv(cfg
, hardware
,
513 n
, buffer
, hardware
->h_mtu
)) == -1) {
517 hardware
->h_rx_cnt
++;
518 lldpd_decode(cfg
, buffer
, n
, hardware
);
522 for (callback
= TAILQ_FIRST(&cfg
->g_callbacks
);
524 callback
= callback_next
) {
525 /* Callback function can use TAILQ_REMOVE */
526 callback_next
= TAILQ_NEXT(callback
, next
);
527 if (FD_ISSET(callback
->fd
, &rfds
))
528 callback
->function(cfg
, callback
);
534 netsnmp_check_outstanding_agent_requests();
536 #endif /* USE_SNMP */
537 } while ((rc
!= 0) || (time(NULL
) - cfg
->g_lastsent
< cfg
->g_delay
));
541 lldpd_send_all(struct lldpd
*cfg
)
543 struct lldpd_hardware
*hardware
;
544 struct lldpd_port
*port
;
547 cfg
->g_lastsent
= time(NULL
);
548 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
549 /* Ignore if interface is down */
550 if ((hardware
->h_flags
& IFF_RUNNING
) == 0)
554 for (i
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
555 if (!cfg
->g_protocols
[i
].enabled
)
557 /* We send only if we have at least one remote system
558 * speaking this protocol */
559 TAILQ_FOREACH(port
, &hardware
->h_rports
, p_entries
) {
560 if (port
->p_protocol
==
561 cfg
->g_protocols
[i
].mode
) {
562 cfg
->g_protocols
[i
].send(cfg
,
571 /* Nothing was sent for this port, let's speak LLDP */
572 cfg
->g_protocols
[0].send(cfg
,
577 #ifdef ENABLE_LLDPMED
579 lldpd_med(struct lldpd_chassis
*chassis
)
581 free(chassis
->c_med_hw
);
582 free(chassis
->c_med_fw
);
583 free(chassis
->c_med_sn
);
584 free(chassis
->c_med_manuf
);
585 free(chassis
->c_med_model
);
586 free(chassis
->c_med_asset
);
587 chassis
->c_med_hw
= dmi_hw();
588 chassis
->c_med_fw
= dmi_fw();
589 chassis
->c_med_sn
= dmi_sn();
590 chassis
->c_med_manuf
= dmi_manuf();
591 chassis
->c_med_model
= dmi_model();
592 chassis
->c_med_asset
= dmi_asset();
597 lldpd_update_localchassis(struct lldpd
*cfg
)
603 struct lldpd_hardware
*hardware
;
605 /* Set system name and description */
607 fatal("failed to get system information");
608 if ((hp
= priv_gethostbyname()) == NULL
)
609 fatal("failed to get system name");
610 free(LOCAL_CHASSIS(cfg
)->c_name
);
611 free(LOCAL_CHASSIS(cfg
)->c_descr
);
612 if ((LOCAL_CHASSIS(cfg
)->c_name
= strdup(hp
)) == NULL
)
614 if (cfg
->g_advertise_version
) {
615 if (asprintf(&LOCAL_CHASSIS(cfg
)->c_descr
, "%s %s %s %s",
616 un
.sysname
, un
.release
, un
.version
, un
.machine
) == -1)
617 fatal("failed to set full system description");
619 if (asprintf(&LOCAL_CHASSIS(cfg
)->c_descr
, "%s", un
.sysname
) == -1)
620 fatal("failed to set minimal system description");
623 /* Check forwarding */
624 if ((f
= priv_open("/proc/sys/net/ipv4/ip_forward")) >= 0) {
625 if ((read(f
, &status
, 1) == 1) && (status
== '1')) {
626 LOCAL_CHASSIS(cfg
)->c_cap_enabled
= LLDP_CAP_ROUTER
;
630 #ifdef ENABLE_LLDPMED
631 if (LOCAL_CHASSIS(cfg
)->c_cap_available
& LLDP_CAP_TELEPHONE
)
632 LOCAL_CHASSIS(cfg
)->c_cap_enabled
|= LLDP_CAP_TELEPHONE
;
633 lldpd_med(LOCAL_CHASSIS(cfg
));
634 free(LOCAL_CHASSIS(cfg
)->c_med_sw
);
635 if (cfg
->g_advertise_version
)
636 LOCAL_CHASSIS(cfg
)->c_med_sw
= strdup(un
.release
);
638 LOCAL_CHASSIS(cfg
)->c_med_sw
= strdup("Unknown");
641 /* Set chassis ID if needed */
642 if ((LOCAL_CHASSIS(cfg
)->c_id
== NULL
) &&
643 (hardware
= TAILQ_FIRST(&cfg
->g_hardware
))) {
644 if ((LOCAL_CHASSIS(cfg
)->c_id
=
645 malloc(sizeof(hardware
->h_lladdr
))) == NULL
)
647 LOCAL_CHASSIS(cfg
)->c_id_subtype
= LLDP_CHASSISID_SUBTYPE_LLADDR
;
648 LOCAL_CHASSIS(cfg
)->c_id_len
= sizeof(hardware
->h_lladdr
);
649 memcpy(LOCAL_CHASSIS(cfg
)->c_id
,
650 hardware
->h_lladdr
, sizeof(hardware
->h_lladdr
));
655 lldpd_update_localports(struct lldpd
*cfg
)
657 struct ifaddrs
*ifap
;
658 struct lldpd_hardware
*hardware
;
659 lldpd_ifhandlers ifhs
[] = {
660 lldpd_ifh_bond
, /* Handle bond */
661 lldpd_ifh_eth
, /* Handle classic ethernet interfaces */
663 lldpd_ifh_vlan
, /* Handle VLAN */
665 lldpd_ifh_mgmt
, /* Handle management address (if not already handled) */
668 lldpd_ifhandlers
*ifh
;
670 /* h_flags is set to 0 for each port. If the port is updated, h_flags
671 * will be set to a non-zero value. This will allow us to clean up any
672 * non up-to-date port */
673 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
)
674 hardware
->h_flags
= 0;
676 LOCAL_CHASSIS(cfg
)->c_mgmt
.s_addr
= INADDR_ANY
;
677 if (getifaddrs(&ifap
) != 0)
678 fatal("lldpd_update_localports: failed to get interface list");
680 /* We will run the list of interfaces through a list of interface
681 * handlers. Each handler will create or update some hardware port (and
682 * will set h_flags to a non zero value. The handler can use the list of
683 * interfaces but this is not mandatory. If the interface handler
684 * handles an interface from the list, it should set ifa_flags to 0 to
685 * let know the other handlers that it took care of this interface. This
686 * means that more specific handlers should be before less specific
688 for (ifh
= ifhs
; *ifh
!= NULL
; ifh
++)
694 lldpd_loop(struct lldpd
*cfg
)
698 1. Update local ports information
699 2. Clean unwanted (removed) local ports
700 3. Update local chassis information
704 LOCAL_CHASSIS(cfg
)->c_cap_enabled
= 0;
705 lldpd_update_localports(cfg
);
707 lldpd_update_localchassis(cfg
);
713 lldpd_shutdown(int sig
)
715 LLOG_INFO("signal received, exiting");
719 /* For signal handling */
720 static struct lldpd
*gcfg
= NULL
;
725 struct lldpd_hardware
*hardware
, *hardware_next
;
728 for (hardware
= TAILQ_FIRST(&gcfg
->g_hardware
); hardware
!= NULL
;
729 hardware
= hardware_next
) {
730 hardware_next
= TAILQ_NEXT(hardware
, h_entries
);
731 lldpd_hardware_cleanup(gcfg
, hardware
);
736 #endif /* USE_SNMP */
740 lldpd_main(int argc
, char *argv
[])
743 struct lldpd_chassis
*lchassis
;
750 #ifdef ENABLE_LISTENVLAN
754 int i
, found
, advertise_version
= 1;
755 #ifdef ENABLE_LISTENVLAN
758 #ifdef ENABLE_LLDPMED
759 int lldpmed
= 0, noinventory
= 0;
765 * Get and parse command line options
767 popt
= strchr(opts
, '@');
768 for (i
=0; protos
[i
].mode
!= 0; i
++) {
769 if (protos
[i
].enabled
== 1) continue;
770 *(popt
++) = protos
[i
].arg
;
773 while ((ch
= getopt(argc
, argv
, opts
)) != -1) {
775 #ifdef ENABLE_LISTENVLAN
787 advertise_version
= 0;
789 #ifdef ENABLE_LLDPMED
791 lldpmed
= atoi(optarg
);
792 if ((lldpmed
< 1) || (lldpmed
> 4)) {
793 fprintf(stderr
, "-M requires an argument between 1 and 4\n");
804 fprintf(stderr
, "LLDP-MED support is not built-in\n");
812 fprintf(stderr
, "SNMP support is not built-in\n");
818 for (i
=0; protos
[i
].mode
!= 0; i
++) {
819 if (protos
[i
].enabled
) continue;
820 if (ch
== protos
[i
].arg
) {
821 protos
[i
].enabled
= 1;
830 log_init(debug
, __progname
);
835 if (daemon(0, 0) != 0)
836 fatal("failed to detach daemon");
837 if ((pid
= open(LLDPD_PID_FILE
,
838 O_TRUNC
| O_CREAT
| O_WRONLY
, 0644)) == -1)
839 fatal("unable to open pid file " LLDPD_PID_FILE
);
840 if (asprintf(&spid
, "%d\n", getpid()) == -1)
841 fatal("unable to create pid file " LLDPD_PID_FILE
);
842 if (write(pid
, spid
, strlen(spid
)) == -1)
843 fatal("unable to write pid file " LLDPD_PID_FILE
);
848 priv_init(PRIVSEP_CHROOT
);
850 if ((cfg
= (struct lldpd
*)
851 calloc(1, sizeof(struct lldpd
))) == NULL
)
854 cfg
->g_mgmt_pattern
= mgmtp
;
855 cfg
->g_advertise_version
= advertise_version
;
856 #ifdef ENABLE_LISTENVLAN
857 cfg
->g_listen_vlans
= vlan
;
860 /* Get ioctl socket */
861 if ((cfg
->g_sock
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1)
862 fatal("failed to get ioctl socket");
863 cfg
->g_delay
= LLDPD_TX_DELAY
;
865 /* Set system capabilities */
866 if ((lchassis
= (struct lldpd_chassis
*)
867 calloc(1, sizeof(struct lldpd_chassis
))) == NULL
)
869 lchassis
->c_cap_available
= LLDP_CAP_BRIDGE
| LLDP_CAP_WLAN
|
871 #ifdef ENABLE_LLDPMED
873 if (lldpmed
== LLDPMED_CLASS_III
)
874 lchassis
->c_cap_available
|= LLDP_CAP_TELEPHONE
;
875 lchassis
->c_med_type
= lldpmed
;
876 lchassis
->c_med_cap_available
= LLDPMED_CAP_CAP
|
877 LLDPMED_CAP_IV
| LLDPMED_CAP_LOCATION
;
878 cfg
->g_noinventory
= noinventory
;
880 cfg
->g_noinventory
= 1;
884 lchassis
->c_ttl
= LLDPD_TTL
;
886 cfg
->g_protocols
= protos
;
887 for (i
=0; protos
[i
].mode
!= 0; i
++)
888 if (protos
[i
].enabled
) {
889 LLOG_INFO("protocol %s enabled", protos
[i
].name
);
891 LLOG_INFO("protocol %s disabled", protos
[i
].name
);
893 TAILQ_INIT(&cfg
->g_hardware
);
894 TAILQ_INIT(&cfg
->g_chassis
);
895 TAILQ_INSERT_TAIL(&cfg
->g_chassis
, lchassis
, c_entries
);
896 lchassis
->c_refcount
++;
898 TAILQ_INIT(&cfg
->g_callbacks
);
903 agent_init(cfg
, debug
);
905 #endif /* USE_SNMP */
908 if ((cfg
->g_ctl
= priv_ctl_create()) == -1)
909 fatalx("unable to create control socket " LLDPD_CTL_SOCKET
);
910 if (lldpd_callback_add(cfg
, cfg
->g_ctl
, ctl_accept
, NULL
) != 0)
911 fatalx("unable to add callback for control socket");
914 if (atexit(lldpd_exit
) != 0) {
917 fatal("unable to set exit function");
920 /* Signal handling */
921 signal(SIGHUP
, lldpd_shutdown
);
922 signal(SIGINT
, lldpd_shutdown
);
923 signal(SIGTERM
, lldpd_shutdown
);