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
)
102 struct lldpd_hardware
*hardware
;
103 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
104 if (strcmp(hardware
->h_ifname
, name
) == 0)
110 struct lldpd_hardware
*
111 lldpd_alloc_hardware(struct lldpd
*cfg
, char *name
)
113 struct lldpd_hardware
*hardware
;
115 if ((hardware
= (struct lldpd_hardware
*)
116 calloc(1, sizeof(struct lldpd_hardware
))) == NULL
)
119 strlcpy(hardware
->h_ifname
, name
, sizeof(hardware
->h_ifname
));
120 hardware
->h_lport
.p_chassis
= LOCAL_CHASSIS(cfg
);
121 TAILQ_INIT(&hardware
->h_rports
);
123 #ifdef ENABLE_LLDPMED
124 if (LOCAL_CHASSIS(cfg
)->c_med_cap_available
) {
125 hardware
->h_lport
.p_med_cap_enabled
= LLDPMED_CAP_CAP
;
126 if (!cfg
->g_noinventory
)
127 hardware
->h_lport
.p_med_cap_enabled
|= LLDPMED_CAP_IV
;
131 TAILQ_INIT(&hardware
->h_lport
.p_vlans
);
138 lldpd_vlan_cleanup(struct lldpd_port
*port
)
140 struct lldpd_vlan
*vlan
, *vlan_next
;
141 for (vlan
= TAILQ_FIRST(&port
->p_vlans
);
145 vlan_next
= TAILQ_NEXT(vlan
, v_entries
);
146 TAILQ_REMOVE(&port
->p_vlans
, vlan
, v_entries
);
152 /* If `all' is true, clear all information, including information that
153 are not refreshed periodically. Port should be freed manually. */
155 lldpd_port_cleanup(struct lldpd_port
*port
, int all
)
157 #ifdef ENABLE_LLDPMED
160 for (i
=0; i
< LLDPMED_LOCFORMAT_LAST
; i
++)
161 free(port
->p_med_location
[i
].data
);
164 lldpd_vlan_cleanup(port
);
169 free(port
->p_lastframe
);
170 if (port
->p_chassis
) /* chassis may not have been attributed, yet */
171 port
->p_chassis
->c_refcount
--;
176 lldpd_chassis_cleanup(struct lldpd_chassis
*chassis
, int all
)
178 #ifdef ENABLE_LLDPMED
179 free(chassis
->c_med_hw
);
180 free(chassis
->c_med_sw
);
181 free(chassis
->c_med_fw
);
182 free(chassis
->c_med_sn
);
183 free(chassis
->c_med_manuf
);
184 free(chassis
->c_med_model
);
185 free(chassis
->c_med_asset
);
188 free(chassis
->c_name
);
189 free(chassis
->c_descr
);
195 lldpd_remote_cleanup(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
, int all
)
197 struct lldpd_port
*port
, *port_next
;
199 for (port
= TAILQ_FIRST(&hardware
->h_rports
);
202 port_next
= TAILQ_NEXT(port
, p_entries
);
205 (time(NULL
) - port
->p_lastupdate
> port
->p_chassis
->c_ttl
)) {
206 hardware
->h_rx_ageout_cnt
++;
210 TAILQ_REMOVE(&hardware
->h_rports
, port
, p_entries
);
211 lldpd_port_cleanup(port
, 1);
218 lldpd_hardware_cleanup(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
)
221 lldpd_port_cleanup(&hardware
->h_lport
, 1);
222 /* If we have a dedicated cleanup function, use it. Otherwise,
223 we just free the hardware-dependent data and close all FD
224 in h_recvfds and h_sendfd. */
225 if (hardware
->h_ops
->cleanup
)
226 hardware
->h_ops
->cleanup(cfg
, hardware
);
228 free(hardware
->h_data
);
229 for (i
=0; i
< FD_SETSIZE
; i
++)
230 if (FD_ISSET(i
, &hardware
->h_recvfds
))
232 if (hardware
->h_sendfd
) close(hardware
->h_sendfd
);
238 lldpd_cleanup(struct lldpd
*cfg
)
240 struct lldpd_hardware
*hardware
, *hardware_next
;
242 for (hardware
= TAILQ_FIRST(&cfg
->g_hardware
); hardware
!= NULL
;
243 hardware
= hardware_next
) {
244 hardware_next
= TAILQ_NEXT(hardware
, h_entries
);
245 if (!hardware
->h_flags
) {
246 TAILQ_REMOVE(&cfg
->g_hardware
, hardware
, h_entries
);
247 lldpd_remote_cleanup(cfg
, hardware
, 1);
248 lldpd_hardware_cleanup(cfg
, hardware
);
250 lldpd_remote_cleanup(cfg
, hardware
, 0);
255 lldpd_guess_type(struct lldpd
*cfg
, char *frame
, int s
)
260 for (i
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
261 if (!cfg
->g_protocols
[i
].enabled
)
263 if (cfg
->g_protocols
[i
].guess
== NULL
) {
264 if (memcmp(frame
, cfg
->g_protocols
[i
].mac
, ETH_ALEN
) == 0)
265 return cfg
->g_protocols
[i
].mode
;
267 if (cfg
->g_protocols
[i
].guess(frame
, s
))
268 return cfg
->g_protocols
[i
].mode
;
275 lldpd_decode(struct lldpd
*cfg
, char *frame
, int s
,
276 struct lldpd_hardware
*hardware
)
279 struct lldpd_chassis
*chassis
, *ochassis
= NULL
;
280 struct lldpd_port
*port
, *oport
= NULL
;
281 int guess
= LLDPD_MODE_LLDP
;
283 /* Discard VLAN frames */
284 if ((s
>= sizeof(struct ethhdr
)) &&
285 (((struct ethhdr
*)frame
)->h_proto
== htons(ETHERTYPE_VLAN
)))
288 TAILQ_FOREACH(oport
, &hardware
->h_rports
, p_entries
) {
289 if ((oport
->p_lastframe
!= NULL
) &&
290 (oport
->p_lastframe
->size
== s
) &&
291 (memcmp(oport
->p_lastframe
->frame
, frame
, s
) == 0)) {
292 /* Already received the same frame */
293 oport
->p_lastupdate
= time(NULL
);
298 guess
= lldpd_guess_type(cfg
, frame
, s
);
299 for (i
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
300 if (!cfg
->g_protocols
[i
].enabled
)
302 if (cfg
->g_protocols
[i
].mode
== guess
) {
303 if ((result
= cfg
->g_protocols
[i
].decode(cfg
, frame
,
304 s
, hardware
, &chassis
, &port
)) == -1)
306 chassis
->c_protocol
= port
->p_protocol
=
307 cfg
->g_protocols
[i
].mode
;
311 if (cfg
->g_protocols
[i
].mode
== 0) {
312 LLOG_INFO("unable to guess frame type");
316 /* Do we already have the same MSAP somewhere? */
317 TAILQ_FOREACH(oport
, &hardware
->h_rports
, p_entries
) {
318 if ((port
->p_protocol
== oport
->p_protocol
) &&
319 (port
->p_id_subtype
== oport
->p_id_subtype
) &&
320 (port
->p_id_len
== oport
->p_id_len
) &&
321 (memcmp(port
->p_id
, oport
->p_id
, port
->p_id_len
) == 0) &&
322 (chassis
->c_id_subtype
== oport
->p_chassis
->c_id_subtype
) &&
323 (chassis
->c_id_len
== oport
->p_chassis
->c_id_len
) &&
324 (memcmp(chassis
->c_id
, oport
->p_chassis
->c_id
,
325 chassis
->c_id_len
) == 0)) {
326 ochassis
= oport
->p_chassis
;
330 /* No, but do we already know the system? */
332 TAILQ_FOREACH(ochassis
, &cfg
->g_chassis
, c_entries
) {
333 if ((chassis
->c_protocol
== ochassis
->c_protocol
) &&
334 (chassis
->c_id_subtype
== ochassis
->c_id_subtype
) &&
335 (chassis
->c_id_len
== ochassis
->c_id_len
) &&
336 (memcmp(chassis
->c_id
, ochassis
->c_id
,
337 chassis
->c_id_len
) == 0))
343 /* The port is known, remove it before adding it back */
344 TAILQ_REMOVE(&hardware
->h_rports
, oport
, p_entries
);
345 lldpd_port_cleanup(oport
, 1);
349 lldpd_update_chassis(ochassis
, chassis
);
353 /* Chassis not known, add it */
354 chassis
->c_index
= ++cfg
->g_lastrid
;
355 port
->p_chassis
= chassis
;
356 chassis
->c_refcount
= 0;
357 TAILQ_INSERT_TAIL(&cfg
->g_chassis
, chassis
, c_entries
);
358 i
= 0; TAILQ_FOREACH(ochassis
, &cfg
->g_chassis
, c_entries
) i
++;
359 LLOG_DEBUG("Currently, we know %d different systems", i
);
362 port
->p_lastchange
= port
->p_lastupdate
= time(NULL
);
363 if ((port
->p_lastframe
= (struct lldpd_frame
*)malloc(s
+
364 sizeof(int))) != NULL
) {
365 port
->p_lastframe
->size
= s
;
366 memcpy(port
->p_lastframe
->frame
, frame
, s
);
368 TAILQ_INSERT_TAIL(&hardware
->h_rports
, port
, p_entries
);
369 port
->p_chassis
= chassis
;
370 port
->p_chassis
->c_refcount
++;
371 i
= 0; TAILQ_FOREACH(oport
, &hardware
->h_rports
, p_entries
) i
++;
372 LLOG_DEBUG("Currently, %s known %d neighbors",
373 hardware
->h_ifname
, i
);
377 /* Update chassis `ochassis' with values from `chassis'. */
379 lldpd_update_chassis(struct lldpd_chassis
*ochassis
,
380 const struct lldpd_chassis
*chassis
) {
381 TAILQ_ENTRY(lldpd_chassis
) entries
;
382 /* We want to keep refcount, index and list stuff from the current
384 int refcount
= ochassis
->c_refcount
;
385 int index
= ochassis
->c_index
;
386 memcpy(&entries
, &ochassis
->c_entries
,
389 lldpd_chassis_cleanup(ochassis
, 0);
390 memcpy(ochassis
, chassis
, sizeof(struct lldpd_chassis
));
391 /* Restore saved values */
392 ochassis
->c_refcount
= refcount
;
393 ochassis
->c_index
= index
;
394 memcpy(&ochassis
->c_entries
, &entries
, sizeof(entries
));
399 lldpd_recv_all(struct lldpd
*cfg
)
401 struct lldpd_hardware
*hardware
;
402 struct lldpd_client
*client
, *client_next
;
407 struct timeval
*tvp
= &tv
;
413 tv
.tv_sec
= cfg
->g_delay
- (time(NULL
) - cfg
->g_lastsent
);
415 tv
.tv_sec
= LLDPD_TX_DELAY
;
416 if (tv
.tv_sec
>= cfg
->g_delay
)
417 tv
.tv_sec
= cfg
->g_delay
;
423 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
424 /* Ignore if interface is down */
425 if ((hardware
->h_flags
& IFF_RUNNING
) == 0)
427 /* This is quite expensive but we don't rely on internal
428 * structure of fd_set. */
429 for (n
= 0; n
< FD_SETSIZE
; n
++)
430 if (FD_ISSET(n
, &hardware
->h_recvfds
)) {
436 TAILQ_FOREACH(client
, &cfg
->g_clients
, next
) {
437 FD_SET(client
->fd
, &rfds
);
438 if (nfds
< client
->fd
)
441 FD_SET(cfg
->g_ctl
, &rfds
);
442 if (nfds
< cfg
->g_ctl
)
447 snmp_select_info(&nfds
, &rfds
, tvp
, &fakeblock
);
448 #endif /* USE_SNMP */
454 rc
= select(nfds
+ 1, &rfds
, NULL
, NULL
, &tv
);
458 LLOG_WARN("failure on select");
468 #endif /* USE_SNMP */
469 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
470 for (n
= 0; n
< FD_SETSIZE
; n
++)
471 if ((FD_ISSET(n
, &hardware
->h_recvfds
)) &&
472 (FD_ISSET(n
, &rfds
))) break;
473 if (n
== FD_SETSIZE
) continue;
474 if ((buffer
= (char *)malloc(
475 hardware
->h_mtu
)) == NULL
) {
476 LLOG_WARN("failed to alloc reception buffer");
479 if ((n
= hardware
->h_ops
->recv(cfg
, hardware
,
480 n
, buffer
, hardware
->h_mtu
)) == -1) {
484 hardware
->h_rx_cnt
++;
485 lldpd_decode(cfg
, buffer
, n
, hardware
);
489 if (FD_ISSET(cfg
->g_ctl
, &rfds
)) {
490 if (ctl_accept(cfg
, cfg
->g_ctl
) == -1)
491 LLOG_WARN("unable to accept new client");
493 for (client
= TAILQ_FIRST(&cfg
->g_clients
);
495 client
= client_next
) {
496 client_next
= TAILQ_NEXT(client
, next
);
497 if (FD_ISSET(client
->fd
, &rfds
)) {
499 if ((buffer
= (char *)malloc(MAX_HMSGSIZE
)) ==
501 LLOG_WARN("failed to alloc reception buffer");
504 if ((n
= recv(client
->fd
, buffer
,
505 MAX_HMSGSIZE
, 0)) == -1) {
506 LLOG_WARN("error while receiving message");
511 client_handle_client(cfg
, client
, buffer
, n
);
513 ctl_close(cfg
, client
->fd
); /* Will use TAILQ_REMOVE ! */
521 netsnmp_check_outstanding_agent_requests();
523 #endif /* USE_SNMP */
524 } while ((rc
!= 0) || (time(NULL
) - cfg
->g_lastsent
< cfg
->g_delay
));
528 lldpd_send_all(struct lldpd
*cfg
)
530 struct lldpd_hardware
*hardware
;
531 struct lldpd_port
*port
;
534 cfg
->g_lastsent
= time(NULL
);
535 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
536 /* Ignore if interface is down */
537 if ((hardware
->h_flags
& IFF_RUNNING
) == 0)
540 for (i
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
541 if (!cfg
->g_protocols
[i
].enabled
)
543 /* We send only if we have at least one remote system
544 * speaking this protocol */
545 TAILQ_FOREACH(port
, &hardware
->h_rports
, p_entries
) {
546 if (port
->p_protocol
==
547 cfg
->g_protocols
[i
].mode
) {
548 cfg
->g_protocols
[i
].send(cfg
,
557 /* Nothing was sent for this port, let's speak LLDP */
558 cfg
->g_protocols
[0].send(cfg
,
563 #ifdef ENABLE_LLDPMED
565 lldpd_med(struct lldpd_chassis
*chassis
)
567 free(chassis
->c_med_hw
);
568 free(chassis
->c_med_fw
);
569 free(chassis
->c_med_sn
);
570 free(chassis
->c_med_manuf
);
571 free(chassis
->c_med_model
);
572 free(chassis
->c_med_asset
);
573 chassis
->c_med_hw
= dmi_hw();
574 chassis
->c_med_fw
= dmi_fw();
575 chassis
->c_med_sn
= dmi_sn();
576 chassis
->c_med_manuf
= dmi_manuf();
577 chassis
->c_med_model
= dmi_model();
578 chassis
->c_med_asset
= dmi_asset();
583 lldpd_update_localchassis(struct lldpd
*cfg
)
589 struct lldpd_hardware
*hardware
;
591 /* Set system name and description */
593 fatal("failed to get system information");
594 if ((hp
= priv_gethostbyname()) == NULL
)
595 fatal("failed to get system name");
596 free(LOCAL_CHASSIS(cfg
)->c_name
);
597 free(LOCAL_CHASSIS(cfg
)->c_descr
);
598 if ((LOCAL_CHASSIS(cfg
)->c_name
= strdup(hp
)) == NULL
)
600 if (asprintf(&LOCAL_CHASSIS(cfg
)->c_descr
, "%s %s %s %s",
601 un
.sysname
, un
.release
, un
.version
, un
.machine
) == -1)
602 fatal("failed to set system description");
604 /* Check forwarding */
605 LOCAL_CHASSIS(cfg
)->c_cap_enabled
= 0;
606 if ((f
= priv_open("/proc/sys/net/ipv4/ip_forward")) >= 0) {
607 if ((read(f
, &status
, 1) == 1) && (status
== '1')) {
608 LOCAL_CHASSIS(cfg
)->c_cap_enabled
= LLDP_CAP_ROUTER
;
612 #ifdef ENABLE_LLDPMED
613 if (LOCAL_CHASSIS(cfg
)->c_cap_available
& LLDP_CAP_TELEPHONE
)
614 LOCAL_CHASSIS(cfg
)->c_cap_enabled
|= LLDP_CAP_TELEPHONE
;
615 lldpd_med(LOCAL_CHASSIS(cfg
));
616 free(LOCAL_CHASSIS(cfg
)->c_med_sw
);
617 LOCAL_CHASSIS(cfg
)->c_med_sw
= strdup(un
.release
);
620 /* Set chassis ID if needed */
621 if ((LOCAL_CHASSIS(cfg
)->c_id
== NULL
) &&
622 (hardware
= TAILQ_FIRST(&cfg
->g_hardware
))) {
623 if ((LOCAL_CHASSIS(cfg
)->c_id
=
624 malloc(sizeof(hardware
->h_lladdr
))) == NULL
)
626 LOCAL_CHASSIS(cfg
)->c_id_subtype
= LLDP_CHASSISID_SUBTYPE_LLADDR
;
627 LOCAL_CHASSIS(cfg
)->c_id_len
= sizeof(hardware
->h_lladdr
);
628 memcpy(LOCAL_CHASSIS(cfg
)->c_id
,
629 hardware
->h_lladdr
, sizeof(hardware
->h_lladdr
));
634 lldpd_update_localports(struct lldpd
*cfg
)
636 struct ifaddrs
*ifap
;
637 struct lldpd_hardware
*hardware
;
638 lldpd_ifhandlers ifhs
[] = {
639 lldpd_ifh_eth
, /* Handle classic ethernet interfaces */
640 lldpd_ifh_vlan
, /* Handle VLAN */
641 lldpd_ifh_mgmt
, /* Handle management address (if not already handled) */
644 lldpd_ifhandlers
*ifh
;
646 /* h_flags is set to 0 for each port. If the port is updated, h_flags
647 * will be set to a non-zero value. This will allow us to clean up any
648 * non up-to-date port */
649 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
)
650 hardware
->h_flags
= 0;
652 LOCAL_CHASSIS(cfg
)->c_mgmt
.s_addr
= INADDR_ANY
;
653 if (getifaddrs(&ifap
) != 0)
654 fatal("lldpd_update_localports: failed to get interface list");
656 /* We will run the list of interfaces through a list of interface
657 * handlers. Each handler will create or update some hardware port (and
658 * will set h_flags to a non zero value. The handler can use the list of
659 * interfaces but this is not mandatory. If the interface handler
660 * handles an interface from the list, it should set ifa_flags to 0 to
661 * let know the other handlers that it took care of this interface. This
662 * means that more specific handlers should be before less specific
664 for (ifh
= ifhs
; *ifh
!= NULL
; ifh
++)
670 lldpd_loop(struct lldpd
*cfg
)
674 1. Update local ports information
675 2. Clean unwanted (removed) local ports
676 3. Update local chassis information
680 lldpd_update_localports(cfg
);
682 lldpd_update_localchassis(cfg
);
688 lldpd_shutdown(int sig
)
690 LLOG_INFO("signal received, exiting");
694 /* For signal handling */
695 static struct lldpd
*gcfg
= NULL
;
700 struct lldpd_hardware
*hardware
, *hardware_next
;
703 for (hardware
= TAILQ_FIRST(&gcfg
->g_hardware
); hardware
!= NULL
;
704 hardware
= hardware_next
) {
705 hardware_next
= TAILQ_NEXT(hardware
, h_entries
);
706 lldpd_hardware_cleanup(gcfg
, hardware
);
711 #endif /* USE_SNMP */
715 main(int argc
, char *argv
[])
718 struct lldpd_chassis
*lchassis
;
724 char *popt
, opts
[] = "dxm:p:M:i@ ";
726 #ifdef ENABLE_LLDPMED
727 int lldpmed
= 0, noinventory
= 0;
733 * Get and parse command line options
735 popt
= index(opts
, '@');
736 for (i
=0; protos
[i
].mode
!= 0; i
++) {
737 if (protos
[i
].enabled
== 1) continue;
738 *(popt
++) = protos
[i
].arg
;
741 while ((ch
= getopt(argc
, argv
, opts
)) != -1) {
749 #ifdef ENABLE_LLDPMED
751 lldpmed
= atoi(optarg
);
752 if ((lldpmed
< 1) || (lldpmed
> 4)) {
753 fprintf(stderr
, "-M requires an argument between 1 and 4\n");
764 fprintf(stderr
, "LLDP-MED support is not built-in\n");
772 fprintf(stderr
, "SNMP support is not built-in\n");
778 for (i
=0; protos
[i
].mode
!= 0; i
++) {
779 if (protos
[i
].enabled
) continue;
780 if (ch
== protos
[i
].arg
) {
781 protos
[i
].enabled
= 1;
795 if (daemon(0, 0) != 0)
796 fatal("failed to detach daemon");
797 if ((pid
= open(LLDPD_PID_FILE
,
798 O_TRUNC
| O_CREAT
| O_WRONLY
, 0644)) == -1)
799 fatal("unable to open pid file " LLDPD_PID_FILE
);
800 if (asprintf(&spid
, "%d\n", getpid()) == -1)
801 fatal("unable to create pid file " LLDPD_PID_FILE
);
802 if (write(pid
, spid
, strlen(spid
)) == -1)
803 fatal("unable to write pid file " LLDPD_PID_FILE
);
808 priv_init(PRIVSEP_CHROOT
);
810 if ((cfg
= (struct lldpd
*)
811 calloc(1, sizeof(struct lldpd
))) == NULL
)
814 cfg
->g_mgmt_pattern
= mgmtp
;
816 /* Get ioctl socket */
817 if ((cfg
->g_sock
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1)
818 fatal("failed to get ioctl socket");
819 cfg
->g_delay
= LLDPD_TX_DELAY
;
821 /* Set system capabilities */
822 if ((lchassis
= (struct lldpd_chassis
*)
823 calloc(1, sizeof(struct lldpd_chassis
))) == NULL
)
825 lchassis
->c_cap_available
= LLDP_CAP_BRIDGE
| LLDP_CAP_WLAN
|
827 #ifdef ENABLE_LLDPMED
829 if (lldpmed
== LLDPMED_CLASS_III
)
830 lchassis
->c_cap_available
|= LLDP_CAP_TELEPHONE
;
831 lchassis
->c_med_type
= lldpmed
;
832 lchassis
->c_med_cap_available
= LLDPMED_CAP_CAP
|
833 LLDPMED_CAP_IV
| LLDPMED_CAP_LOCATION
;
834 cfg
->g_noinventory
= noinventory
;
836 cfg
->g_noinventory
= 1;
840 lchassis
->c_ttl
= LLDPD_TTL
;
842 cfg
->g_protocols
= protos
;
843 for (i
=0; protos
[i
].mode
!= 0; i
++)
844 if (protos
[i
].enabled
) {
845 LLOG_INFO("protocol %s enabled", protos
[i
].name
);
847 LLOG_INFO("protocol %s disabled", protos
[i
].name
);
849 TAILQ_INIT(&cfg
->g_hardware
);
850 TAILQ_INIT(&cfg
->g_chassis
);
851 TAILQ_INSERT_TAIL(&cfg
->g_chassis
, lchassis
, c_entries
);
852 lchassis
->c_refcount
++;
857 agent_init(cfg
, debug
);
859 #endif /* USE_SNMP */
862 if ((cfg
->g_ctl
= priv_ctl_create(cfg
)) == -1)
863 fatalx("unable to create control socket " LLDPD_CTL_SOCKET
);
864 TAILQ_INIT(&cfg
->g_clients
);
867 if (atexit(lldpd_exit
) != 0) {
870 fatal("unable to set exit function");
873 /* Signal handling */
874 signal(SIGHUP
, lldpd_shutdown
);
875 signal(SIGINT
, lldpd_shutdown
);
876 signal(SIGTERM
, lldpd_shutdown
);