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();
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
;
93 extern const char *__progname
;
94 fprintf(stderr
, "usage: %s [options]\n", __progname
);
95 fprintf(stderr
, "see manual page lldpd(8) for more information\n");
99 struct lldpd_hardware
*
100 lldpd_get_hardware(struct lldpd
*cfg
, char *name
, int index
, struct lldpd_ops
*ops
)
102 struct lldpd_hardware
*hardware
;
103 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
104 if ((strcmp(hardware
->h_ifname
, name
) == 0) &&
105 (hardware
->h_ifindex
== index
) &&
106 ((!ops
) || (ops
== hardware
->h_ops
)))
112 struct lldpd_hardware
*
113 lldpd_alloc_hardware(struct lldpd
*cfg
, char *name
)
115 struct lldpd_hardware
*hardware
;
117 if ((hardware
= (struct lldpd_hardware
*)
118 calloc(1, sizeof(struct lldpd_hardware
))) == NULL
)
121 strlcpy(hardware
->h_ifname
, name
, sizeof(hardware
->h_ifname
));
122 hardware
->h_lport
.p_chassis
= LOCAL_CHASSIS(cfg
);
123 TAILQ_INIT(&hardware
->h_rports
);
125 #ifdef ENABLE_LLDPMED
126 if (LOCAL_CHASSIS(cfg
)->c_med_cap_available
) {
127 hardware
->h_lport
.p_med_cap_enabled
= LLDPMED_CAP_CAP
;
128 if (!cfg
->g_noinventory
)
129 hardware
->h_lport
.p_med_cap_enabled
|= LLDPMED_CAP_IV
;
133 TAILQ_INIT(&hardware
->h_lport
.p_vlans
);
140 lldpd_vlan_cleanup(struct lldpd_port
*port
)
142 struct lldpd_vlan
*vlan
, *vlan_next
;
143 for (vlan
= TAILQ_FIRST(&port
->p_vlans
);
147 vlan_next
= TAILQ_NEXT(vlan
, v_entries
);
148 TAILQ_REMOVE(&port
->p_vlans
, vlan
, v_entries
);
154 /* If `all' is true, clear all information, including information that
155 are not refreshed periodically. Port should be freed manually. */
157 lldpd_port_cleanup(struct lldpd_port
*port
, int all
)
159 #ifdef ENABLE_LLDPMED
162 for (i
=0; i
< LLDPMED_LOCFORMAT_LAST
; i
++)
163 free(port
->p_med_location
[i
].data
);
166 lldpd_vlan_cleanup(port
);
171 free(port
->p_lastframe
);
172 if (port
->p_chassis
) /* chassis may not have been attributed, yet */
173 port
->p_chassis
->c_refcount
--;
178 lldpd_chassis_cleanup(struct lldpd_chassis
*chassis
, int all
)
180 #ifdef ENABLE_LLDPMED
181 free(chassis
->c_med_hw
);
182 free(chassis
->c_med_sw
);
183 free(chassis
->c_med_fw
);
184 free(chassis
->c_med_sn
);
185 free(chassis
->c_med_manuf
);
186 free(chassis
->c_med_model
);
187 free(chassis
->c_med_asset
);
190 free(chassis
->c_name
);
191 free(chassis
->c_descr
);
197 lldpd_remote_cleanup(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
, int all
)
199 struct lldpd_port
*port
, *port_next
;
201 for (port
= TAILQ_FIRST(&hardware
->h_rports
);
204 port_next
= TAILQ_NEXT(port
, p_entries
);
207 (time(NULL
) - port
->p_lastupdate
> port
->p_chassis
->c_ttl
)) {
208 hardware
->h_rx_ageout_cnt
++;
212 TAILQ_REMOVE(&hardware
->h_rports
, port
, p_entries
);
213 lldpd_port_cleanup(port
, 1);
220 lldpd_hardware_cleanup(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
)
223 lldpd_port_cleanup(&hardware
->h_lport
, 1);
224 /* If we have a dedicated cleanup function, use it. Otherwise,
225 we just free the hardware-dependent data and close all FD
226 in h_recvfds and h_sendfd. */
227 if (hardware
->h_ops
->cleanup
)
228 hardware
->h_ops
->cleanup(cfg
, hardware
);
230 free(hardware
->h_data
);
231 for (i
=0; i
< FD_SETSIZE
; i
++)
232 if (FD_ISSET(i
, &hardware
->h_recvfds
))
234 if (hardware
->h_sendfd
) close(hardware
->h_sendfd
);
240 lldpd_cleanup(struct lldpd
*cfg
)
242 struct lldpd_hardware
*hardware
, *hardware_next
;
244 for (hardware
= TAILQ_FIRST(&cfg
->g_hardware
); hardware
!= NULL
;
245 hardware
= hardware_next
) {
246 hardware_next
= TAILQ_NEXT(hardware
, h_entries
);
247 if (!hardware
->h_flags
) {
248 TAILQ_REMOVE(&cfg
->g_hardware
, hardware
, h_entries
);
249 lldpd_remote_cleanup(cfg
, hardware
, 1);
250 lldpd_hardware_cleanup(cfg
, hardware
);
252 lldpd_remote_cleanup(cfg
, hardware
, 0);
257 lldpd_guess_type(struct lldpd
*cfg
, char *frame
, int s
)
262 for (i
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
263 if (!cfg
->g_protocols
[i
].enabled
)
265 if (cfg
->g_protocols
[i
].guess
== NULL
) {
266 if (memcmp(frame
, cfg
->g_protocols
[i
].mac
, ETH_ALEN
) == 0)
267 return cfg
->g_protocols
[i
].mode
;
269 if (cfg
->g_protocols
[i
].guess(frame
, s
))
270 return cfg
->g_protocols
[i
].mode
;
277 lldpd_decode(struct lldpd
*cfg
, char *frame
, int s
,
278 struct lldpd_hardware
*hardware
)
281 struct lldpd_chassis
*chassis
, *ochassis
= NULL
;
282 struct lldpd_port
*port
, *oport
= NULL
;
283 int guess
= LLDPD_MODE_LLDP
;
285 /* Discard VLAN frames */
286 if ((s
>= sizeof(struct ethhdr
)) &&
287 (((struct ethhdr
*)frame
)->h_proto
== htons(ETHERTYPE_VLAN
)))
290 TAILQ_FOREACH(oport
, &hardware
->h_rports
, p_entries
) {
291 if ((oport
->p_lastframe
!= NULL
) &&
292 (oport
->p_lastframe
->size
== s
) &&
293 (memcmp(oport
->p_lastframe
->frame
, frame
, s
) == 0)) {
294 /* Already received the same frame */
295 oport
->p_lastupdate
= time(NULL
);
300 guess
= lldpd_guess_type(cfg
, frame
, s
);
301 for (i
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
302 if (!cfg
->g_protocols
[i
].enabled
)
304 if (cfg
->g_protocols
[i
].mode
== guess
) {
305 if ((result
= cfg
->g_protocols
[i
].decode(cfg
, frame
,
306 s
, hardware
, &chassis
, &port
)) == -1)
308 chassis
->c_protocol
= port
->p_protocol
=
309 cfg
->g_protocols
[i
].mode
;
313 if (cfg
->g_protocols
[i
].mode
== 0) {
314 LLOG_INFO("unable to guess frame type");
318 /* Do we already have the same MSAP somewhere? */
319 TAILQ_FOREACH(oport
, &hardware
->h_rports
, p_entries
) {
320 if ((port
->p_protocol
== oport
->p_protocol
) &&
321 (port
->p_id_subtype
== oport
->p_id_subtype
) &&
322 (port
->p_id_len
== oport
->p_id_len
) &&
323 (memcmp(port
->p_id
, oport
->p_id
, port
->p_id_len
) == 0) &&
324 (chassis
->c_id_subtype
== oport
->p_chassis
->c_id_subtype
) &&
325 (chassis
->c_id_len
== oport
->p_chassis
->c_id_len
) &&
326 (memcmp(chassis
->c_id
, oport
->p_chassis
->c_id
,
327 chassis
->c_id_len
) == 0)) {
328 ochassis
= oport
->p_chassis
;
332 /* No, but do we already know the system? */
334 TAILQ_FOREACH(ochassis
, &cfg
->g_chassis
, c_entries
) {
335 if ((chassis
->c_protocol
== ochassis
->c_protocol
) &&
336 (chassis
->c_id_subtype
== ochassis
->c_id_subtype
) &&
337 (chassis
->c_id_len
== ochassis
->c_id_len
) &&
338 (memcmp(chassis
->c_id
, ochassis
->c_id
,
339 chassis
->c_id_len
) == 0))
345 /* The port is known, remove it before adding it back */
346 TAILQ_REMOVE(&hardware
->h_rports
, oport
, p_entries
);
347 lldpd_port_cleanup(oport
, 1);
351 lldpd_update_chassis(ochassis
, chassis
);
355 /* Chassis not known, add it */
356 chassis
->c_index
= ++cfg
->g_lastrid
;
357 port
->p_chassis
= chassis
;
358 chassis
->c_refcount
= 0;
359 TAILQ_INSERT_TAIL(&cfg
->g_chassis
, chassis
, c_entries
);
360 i
= 0; TAILQ_FOREACH(ochassis
, &cfg
->g_chassis
, c_entries
) i
++;
361 LLOG_DEBUG("Currently, we know %d different systems", i
);
364 port
->p_lastchange
= port
->p_lastupdate
= time(NULL
);
365 if ((port
->p_lastframe
= (struct lldpd_frame
*)malloc(s
+
366 sizeof(int))) != NULL
) {
367 port
->p_lastframe
->size
= s
;
368 memcpy(port
->p_lastframe
->frame
, frame
, s
);
370 TAILQ_INSERT_TAIL(&hardware
->h_rports
, port
, p_entries
);
371 port
->p_chassis
= chassis
;
372 port
->p_chassis
->c_refcount
++;
373 i
= 0; TAILQ_FOREACH(oport
, &hardware
->h_rports
, p_entries
) i
++;
374 LLOG_DEBUG("Currently, %s known %d neighbors",
375 hardware
->h_ifname
, i
);
379 /* Update chassis `ochassis' with values from `chassis'. */
381 lldpd_update_chassis(struct lldpd_chassis
*ochassis
,
382 const struct lldpd_chassis
*chassis
) {
383 TAILQ_ENTRY(lldpd_chassis
) entries
;
384 /* We want to keep refcount, index and list stuff from the current
386 int refcount
= ochassis
->c_refcount
;
387 int index
= ochassis
->c_index
;
388 memcpy(&entries
, &ochassis
->c_entries
,
391 lldpd_chassis_cleanup(ochassis
, 0);
392 memcpy(ochassis
, chassis
, sizeof(struct lldpd_chassis
));
393 /* Restore saved values */
394 ochassis
->c_refcount
= refcount
;
395 ochassis
->c_index
= index
;
396 memcpy(&ochassis
->c_entries
, &entries
, sizeof(entries
));
400 lldpd_callback_add(struct lldpd
*cfg
, int fd
, void(*fn
)(CALLBACK_SIG
), void *data
)
402 struct lldpd_callback
*callback
;
403 if ((callback
= (struct lldpd_callback
*)
404 malloc(sizeof(struct lldpd_callback
))) == NULL
)
407 callback
->function
= fn
;
408 callback
->data
= data
;
409 TAILQ_INSERT_TAIL(&cfg
->g_callbacks
, callback
, next
);
414 lldpd_callback_del(struct lldpd
*cfg
, int fd
, void(*fn
)(CALLBACK_SIG
))
416 struct lldpd_callback
*callback
, *callback_next
;
417 for (callback
= TAILQ_FIRST(&cfg
->g_callbacks
);
419 callback
= callback_next
) {
420 callback_next
= TAILQ_NEXT(callback
, next
);
421 if ((callback
->fd
== fd
) &&
422 (callback
->function
= fn
)) {
423 free(callback
->data
);
424 TAILQ_REMOVE(&cfg
->g_callbacks
, callback
, next
);
431 lldpd_recv_all(struct lldpd
*cfg
)
433 struct lldpd_hardware
*hardware
;
434 struct lldpd_callback
*callback
, *callback_next
;
439 struct timeval
*tvp
= &tv
;
445 tv
.tv_sec
= cfg
->g_delay
- (time(NULL
) - cfg
->g_lastsent
);
447 tv
.tv_sec
= LLDPD_TX_DELAY
;
448 if (tv
.tv_sec
>= cfg
->g_delay
)
449 tv
.tv_sec
= cfg
->g_delay
;
455 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
456 /* Ignore if interface is down */
457 if ((hardware
->h_flags
& IFF_RUNNING
) == 0)
459 /* This is quite expensive but we don't rely on internal
460 * structure of fd_set. */
461 for (n
= 0; n
< FD_SETSIZE
; n
++)
462 if (FD_ISSET(n
, &hardware
->h_recvfds
)) {
468 TAILQ_FOREACH(callback
, &cfg
->g_callbacks
, next
) {
469 FD_SET(callback
->fd
, &rfds
);
470 if (nfds
< callback
->fd
)
476 snmp_select_info(&nfds
, &rfds
, tvp
, &fakeblock
);
477 #endif /* USE_SNMP */
483 rc
= select(nfds
+ 1, &rfds
, NULL
, NULL
, &tv
);
487 LLOG_WARN("failure on select");
497 #endif /* USE_SNMP */
498 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
499 for (n
= 0; n
< FD_SETSIZE
; n
++)
500 if ((FD_ISSET(n
, &hardware
->h_recvfds
)) &&
501 (FD_ISSET(n
, &rfds
))) break;
502 if (n
== FD_SETSIZE
) continue;
503 if ((buffer
= (char *)malloc(
504 hardware
->h_mtu
)) == NULL
) {
505 LLOG_WARN("failed to alloc reception buffer");
508 if ((n
= hardware
->h_ops
->recv(cfg
, hardware
,
509 n
, buffer
, hardware
->h_mtu
)) == -1) {
513 hardware
->h_rx_cnt
++;
514 lldpd_decode(cfg
, buffer
, n
, hardware
);
518 for (callback
= TAILQ_FIRST(&cfg
->g_callbacks
);
520 callback
= callback_next
) {
521 /* Callback function can use TAILQ_REMOVE */
522 callback_next
= TAILQ_NEXT(callback
, next
);
523 if (FD_ISSET(callback
->fd
, &rfds
))
524 callback
->function(cfg
, callback
);
530 netsnmp_check_outstanding_agent_requests();
532 #endif /* USE_SNMP */
533 } while ((rc
!= 0) || (time(NULL
) - cfg
->g_lastsent
< cfg
->g_delay
));
537 lldpd_send_all(struct lldpd
*cfg
)
539 struct lldpd_hardware
*hardware
;
540 struct lldpd_port
*port
;
543 cfg
->g_lastsent
= time(NULL
);
544 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
545 /* Ignore if interface is down */
546 if ((hardware
->h_flags
& IFF_RUNNING
) == 0)
549 for (i
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
550 if (!cfg
->g_protocols
[i
].enabled
)
552 /* We send only if we have at least one remote system
553 * speaking this protocol */
554 TAILQ_FOREACH(port
, &hardware
->h_rports
, p_entries
) {
555 if (port
->p_protocol
==
556 cfg
->g_protocols
[i
].mode
) {
557 cfg
->g_protocols
[i
].send(cfg
,
566 /* Nothing was sent for this port, let's speak LLDP */
567 cfg
->g_protocols
[0].send(cfg
,
572 #ifdef ENABLE_LLDPMED
574 lldpd_med(struct lldpd_chassis
*chassis
)
576 free(chassis
->c_med_hw
);
577 free(chassis
->c_med_fw
);
578 free(chassis
->c_med_sn
);
579 free(chassis
->c_med_manuf
);
580 free(chassis
->c_med_model
);
581 free(chassis
->c_med_asset
);
582 chassis
->c_med_hw
= dmi_hw();
583 chassis
->c_med_fw
= dmi_fw();
584 chassis
->c_med_sn
= dmi_sn();
585 chassis
->c_med_manuf
= dmi_manuf();
586 chassis
->c_med_model
= dmi_model();
587 chassis
->c_med_asset
= dmi_asset();
592 lldpd_update_localchassis(struct lldpd
*cfg
)
598 struct lldpd_hardware
*hardware
;
600 /* Set system name and description */
602 fatal("failed to get system information");
603 if ((hp
= priv_gethostbyname()) == NULL
)
604 fatal("failed to get system name");
605 free(LOCAL_CHASSIS(cfg
)->c_name
);
606 free(LOCAL_CHASSIS(cfg
)->c_descr
);
607 if ((LOCAL_CHASSIS(cfg
)->c_name
= strdup(hp
)) == NULL
)
609 if (asprintf(&LOCAL_CHASSIS(cfg
)->c_descr
, "%s %s %s %s",
610 un
.sysname
, un
.release
, un
.version
, un
.machine
) == -1)
611 fatal("failed to set system description");
613 /* Check forwarding */
614 if ((f
= priv_open("/proc/sys/net/ipv4/ip_forward")) >= 0) {
615 if ((read(f
, &status
, 1) == 1) && (status
== '1')) {
616 LOCAL_CHASSIS(cfg
)->c_cap_enabled
= LLDP_CAP_ROUTER
;
620 #ifdef ENABLE_LLDPMED
621 if (LOCAL_CHASSIS(cfg
)->c_cap_available
& LLDP_CAP_TELEPHONE
)
622 LOCAL_CHASSIS(cfg
)->c_cap_enabled
|= LLDP_CAP_TELEPHONE
;
623 lldpd_med(LOCAL_CHASSIS(cfg
));
624 free(LOCAL_CHASSIS(cfg
)->c_med_sw
);
625 LOCAL_CHASSIS(cfg
)->c_med_sw
= strdup(un
.release
);
628 /* Set chassis ID if needed */
629 if ((LOCAL_CHASSIS(cfg
)->c_id
== NULL
) &&
630 (hardware
= TAILQ_FIRST(&cfg
->g_hardware
))) {
631 if ((LOCAL_CHASSIS(cfg
)->c_id
=
632 malloc(sizeof(hardware
->h_lladdr
))) == NULL
)
634 LOCAL_CHASSIS(cfg
)->c_id_subtype
= LLDP_CHASSISID_SUBTYPE_LLADDR
;
635 LOCAL_CHASSIS(cfg
)->c_id_len
= sizeof(hardware
->h_lladdr
);
636 memcpy(LOCAL_CHASSIS(cfg
)->c_id
,
637 hardware
->h_lladdr
, sizeof(hardware
->h_lladdr
));
642 lldpd_update_localports(struct lldpd
*cfg
)
644 struct ifaddrs
*ifap
;
645 struct lldpd_hardware
*hardware
;
646 lldpd_ifhandlers ifhs
[] = {
647 lldpd_ifh_bond
, /* Handle bond */
648 lldpd_ifh_eth
, /* Handle classic ethernet interfaces */
650 lldpd_ifh_vlan
, /* Handle VLAN */
652 lldpd_ifh_mgmt
, /* Handle management address (if not already handled) */
655 lldpd_ifhandlers
*ifh
;
657 /* h_flags is set to 0 for each port. If the port is updated, h_flags
658 * will be set to a non-zero value. This will allow us to clean up any
659 * non up-to-date port */
660 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
)
661 hardware
->h_flags
= 0;
663 LOCAL_CHASSIS(cfg
)->c_mgmt
.s_addr
= INADDR_ANY
;
664 if (getifaddrs(&ifap
) != 0)
665 fatal("lldpd_update_localports: failed to get interface list");
667 /* We will run the list of interfaces through a list of interface
668 * handlers. Each handler will create or update some hardware port (and
669 * will set h_flags to a non zero value. The handler can use the list of
670 * interfaces but this is not mandatory. If the interface handler
671 * handles an interface from the list, it should set ifa_flags to 0 to
672 * let know the other handlers that it took care of this interface. This
673 * means that more specific handlers should be before less specific
675 for (ifh
= ifhs
; *ifh
!= NULL
; ifh
++)
681 lldpd_loop(struct lldpd
*cfg
)
685 1. Update local ports information
686 2. Clean unwanted (removed) local ports
687 3. Update local chassis information
691 LOCAL_CHASSIS(cfg
)->c_cap_enabled
= 0;
692 lldpd_update_localports(cfg
);
694 lldpd_update_localchassis(cfg
);
700 lldpd_shutdown(int sig
)
702 LLOG_INFO("signal received, exiting");
706 /* For signal handling */
707 static struct lldpd
*gcfg
= NULL
;
712 struct lldpd_hardware
*hardware
, *hardware_next
;
715 for (hardware
= TAILQ_FIRST(&gcfg
->g_hardware
); hardware
!= NULL
;
716 hardware
= hardware_next
) {
717 hardware_next
= TAILQ_NEXT(hardware
, h_entries
);
718 lldpd_hardware_cleanup(gcfg
, hardware
);
723 #endif /* USE_SNMP */
727 main(int argc
, char *argv
[])
730 struct lldpd_chassis
*lchassis
;
737 #ifdef ENABLE_LISTENVLAN
742 #ifdef ENABLE_LISTENVLAN
745 #ifdef ENABLE_LLDPMED
746 int lldpmed
= 0, noinventory
= 0;
752 * Get and parse command line options
754 popt
= index(opts
, '@');
755 for (i
=0; protos
[i
].mode
!= 0; i
++) {
756 if (protos
[i
].enabled
== 1) continue;
757 *(popt
++) = protos
[i
].arg
;
760 while ((ch
= getopt(argc
, argv
, opts
)) != -1) {
762 #ifdef ENABLE_LISTENVLAN
773 #ifdef ENABLE_LLDPMED
775 lldpmed
= atoi(optarg
);
776 if ((lldpmed
< 1) || (lldpmed
> 4)) {
777 fprintf(stderr
, "-M requires an argument between 1 and 4\n");
788 fprintf(stderr
, "LLDP-MED support is not built-in\n");
796 fprintf(stderr
, "SNMP support is not built-in\n");
802 for (i
=0; protos
[i
].mode
!= 0; i
++) {
803 if (protos
[i
].enabled
) continue;
804 if (ch
== protos
[i
].arg
) {
805 protos
[i
].enabled
= 1;
819 if (daemon(0, 0) != 0)
820 fatal("failed to detach daemon");
821 if ((pid
= open(LLDPD_PID_FILE
,
822 O_TRUNC
| O_CREAT
| O_WRONLY
, 0644)) == -1)
823 fatal("unable to open pid file " LLDPD_PID_FILE
);
824 if (asprintf(&spid
, "%d\n", getpid()) == -1)
825 fatal("unable to create pid file " LLDPD_PID_FILE
);
826 if (write(pid
, spid
, strlen(spid
)) == -1)
827 fatal("unable to write pid file " LLDPD_PID_FILE
);
832 priv_init(PRIVSEP_CHROOT
);
834 if ((cfg
= (struct lldpd
*)
835 calloc(1, sizeof(struct lldpd
))) == NULL
)
838 cfg
->g_mgmt_pattern
= mgmtp
;
839 #ifdef ENABLE_LISTENVLAN
840 cfg
->g_listen_vlans
= vlan
;
843 /* Get ioctl socket */
844 if ((cfg
->g_sock
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1)
845 fatal("failed to get ioctl socket");
846 cfg
->g_delay
= LLDPD_TX_DELAY
;
848 /* Set system capabilities */
849 if ((lchassis
= (struct lldpd_chassis
*)
850 calloc(1, sizeof(struct lldpd_chassis
))) == NULL
)
852 lchassis
->c_cap_available
= LLDP_CAP_BRIDGE
| LLDP_CAP_WLAN
|
854 #ifdef ENABLE_LLDPMED
856 if (lldpmed
== LLDPMED_CLASS_III
)
857 lchassis
->c_cap_available
|= LLDP_CAP_TELEPHONE
;
858 lchassis
->c_med_type
= lldpmed
;
859 lchassis
->c_med_cap_available
= LLDPMED_CAP_CAP
|
860 LLDPMED_CAP_IV
| LLDPMED_CAP_LOCATION
;
861 cfg
->g_noinventory
= noinventory
;
863 cfg
->g_noinventory
= 1;
867 lchassis
->c_ttl
= LLDPD_TTL
;
869 cfg
->g_protocols
= protos
;
870 for (i
=0; protos
[i
].mode
!= 0; i
++)
871 if (protos
[i
].enabled
) {
872 LLOG_INFO("protocol %s enabled", protos
[i
].name
);
874 LLOG_INFO("protocol %s disabled", protos
[i
].name
);
876 TAILQ_INIT(&cfg
->g_hardware
);
877 TAILQ_INIT(&cfg
->g_chassis
);
878 TAILQ_INSERT_TAIL(&cfg
->g_chassis
, lchassis
, c_entries
);
879 lchassis
->c_refcount
++;
881 TAILQ_INIT(&cfg
->g_callbacks
);
886 agent_init(cfg
, debug
);
888 #endif /* USE_SNMP */
891 if ((cfg
->g_ctl
= priv_ctl_create(cfg
)) == -1)
892 fatalx("unable to create control socket " LLDPD_CTL_SOCKET
);
893 if (lldpd_callback_add(cfg
, cfg
->g_ctl
, ctl_accept
, NULL
) != 0)
894 fatalx("unable to add callback for control socket");
897 if (atexit(lldpd_exit
) != 0) {
900 fatal("unable to set exit function");
903 /* Signal handling */
904 signal(SIGHUP
, lldpd_shutdown
);
905 signal(SIGINT
, lldpd_shutdown
);
906 signal(SIGTERM
, lldpd_shutdown
);