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
, 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 ((!ops
) || (ops
== hardware
->h_ops
)))
111 struct lldpd_hardware
*
112 lldpd_alloc_hardware(struct lldpd
*cfg
, char *name
)
114 struct lldpd_hardware
*hardware
;
116 if ((hardware
= (struct lldpd_hardware
*)
117 calloc(1, sizeof(struct lldpd_hardware
))) == NULL
)
120 strlcpy(hardware
->h_ifname
, name
, sizeof(hardware
->h_ifname
));
121 hardware
->h_lport
.p_chassis
= LOCAL_CHASSIS(cfg
);
122 TAILQ_INIT(&hardware
->h_rports
);
124 #ifdef ENABLE_LLDPMED
125 if (LOCAL_CHASSIS(cfg
)->c_med_cap_available
) {
126 hardware
->h_lport
.p_med_cap_enabled
= LLDPMED_CAP_CAP
;
127 if (!cfg
->g_noinventory
)
128 hardware
->h_lport
.p_med_cap_enabled
|= LLDPMED_CAP_IV
;
132 TAILQ_INIT(&hardware
->h_lport
.p_vlans
);
139 lldpd_vlan_cleanup(struct lldpd_port
*port
)
141 struct lldpd_vlan
*vlan
, *vlan_next
;
142 for (vlan
= TAILQ_FIRST(&port
->p_vlans
);
146 vlan_next
= TAILQ_NEXT(vlan
, v_entries
);
147 TAILQ_REMOVE(&port
->p_vlans
, vlan
, v_entries
);
153 /* If `all' is true, clear all information, including information that
154 are not refreshed periodically. Port should be freed manually. */
156 lldpd_port_cleanup(struct lldpd_port
*port
, int all
)
158 #ifdef ENABLE_LLDPMED
161 for (i
=0; i
< LLDPMED_LOCFORMAT_LAST
; i
++)
162 free(port
->p_med_location
[i
].data
);
165 lldpd_vlan_cleanup(port
);
170 free(port
->p_lastframe
);
171 if (port
->p_chassis
) /* chassis may not have been attributed, yet */
172 port
->p_chassis
->c_refcount
--;
177 lldpd_chassis_cleanup(struct lldpd_chassis
*chassis
, int all
)
179 #ifdef ENABLE_LLDPMED
180 free(chassis
->c_med_hw
);
181 free(chassis
->c_med_sw
);
182 free(chassis
->c_med_fw
);
183 free(chassis
->c_med_sn
);
184 free(chassis
->c_med_manuf
);
185 free(chassis
->c_med_model
);
186 free(chassis
->c_med_asset
);
189 free(chassis
->c_name
);
190 free(chassis
->c_descr
);
196 lldpd_remote_cleanup(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
, int all
)
198 struct lldpd_port
*port
, *port_next
;
200 for (port
= TAILQ_FIRST(&hardware
->h_rports
);
203 port_next
= TAILQ_NEXT(port
, p_entries
);
206 (time(NULL
) - port
->p_lastupdate
> port
->p_chassis
->c_ttl
)) {
207 hardware
->h_rx_ageout_cnt
++;
211 TAILQ_REMOVE(&hardware
->h_rports
, port
, p_entries
);
212 lldpd_port_cleanup(port
, 1);
219 lldpd_hardware_cleanup(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
)
222 lldpd_port_cleanup(&hardware
->h_lport
, 1);
223 /* If we have a dedicated cleanup function, use it. Otherwise,
224 we just free the hardware-dependent data and close all FD
225 in h_recvfds and h_sendfd. */
226 if (hardware
->h_ops
->cleanup
)
227 hardware
->h_ops
->cleanup(cfg
, hardware
);
229 free(hardware
->h_data
);
230 for (i
=0; i
< FD_SETSIZE
; i
++)
231 if (FD_ISSET(i
, &hardware
->h_recvfds
))
233 if (hardware
->h_sendfd
) close(hardware
->h_sendfd
);
239 lldpd_cleanup(struct lldpd
*cfg
)
241 struct lldpd_hardware
*hardware
, *hardware_next
;
243 for (hardware
= TAILQ_FIRST(&cfg
->g_hardware
); hardware
!= NULL
;
244 hardware
= hardware_next
) {
245 hardware_next
= TAILQ_NEXT(hardware
, h_entries
);
246 if (!hardware
->h_flags
) {
247 TAILQ_REMOVE(&cfg
->g_hardware
, hardware
, h_entries
);
248 lldpd_remote_cleanup(cfg
, hardware
, 1);
249 lldpd_hardware_cleanup(cfg
, hardware
);
251 lldpd_remote_cleanup(cfg
, hardware
, 0);
256 lldpd_guess_type(struct lldpd
*cfg
, char *frame
, int s
)
261 for (i
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
262 if (!cfg
->g_protocols
[i
].enabled
)
264 if (cfg
->g_protocols
[i
].guess
== NULL
) {
265 if (memcmp(frame
, cfg
->g_protocols
[i
].mac
, ETH_ALEN
) == 0)
266 return cfg
->g_protocols
[i
].mode
;
268 if (cfg
->g_protocols
[i
].guess(frame
, s
))
269 return cfg
->g_protocols
[i
].mode
;
276 lldpd_decode(struct lldpd
*cfg
, char *frame
, int s
,
277 struct lldpd_hardware
*hardware
)
280 struct lldpd_chassis
*chassis
, *ochassis
= NULL
;
281 struct lldpd_port
*port
, *oport
= NULL
;
282 int guess
= LLDPD_MODE_LLDP
;
284 /* Discard VLAN frames */
285 if ((s
>= sizeof(struct ethhdr
)) &&
286 (((struct ethhdr
*)frame
)->h_proto
== htons(ETHERTYPE_VLAN
)))
289 TAILQ_FOREACH(oport
, &hardware
->h_rports
, p_entries
) {
290 if ((oport
->p_lastframe
!= NULL
) &&
291 (oport
->p_lastframe
->size
== s
) &&
292 (memcmp(oport
->p_lastframe
->frame
, frame
, s
) == 0)) {
293 /* Already received the same frame */
294 oport
->p_lastupdate
= time(NULL
);
299 guess
= lldpd_guess_type(cfg
, frame
, s
);
300 for (i
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
301 if (!cfg
->g_protocols
[i
].enabled
)
303 if (cfg
->g_protocols
[i
].mode
== guess
) {
304 if ((result
= cfg
->g_protocols
[i
].decode(cfg
, frame
,
305 s
, hardware
, &chassis
, &port
)) == -1)
307 chassis
->c_protocol
= port
->p_protocol
=
308 cfg
->g_protocols
[i
].mode
;
312 if (cfg
->g_protocols
[i
].mode
== 0) {
313 LLOG_INFO("unable to guess frame type");
317 /* Do we already have the same MSAP somewhere? */
318 TAILQ_FOREACH(oport
, &hardware
->h_rports
, p_entries
) {
319 if ((port
->p_protocol
== oport
->p_protocol
) &&
320 (port
->p_id_subtype
== oport
->p_id_subtype
) &&
321 (port
->p_id_len
== oport
->p_id_len
) &&
322 (memcmp(port
->p_id
, oport
->p_id
, port
->p_id_len
) == 0) &&
323 (chassis
->c_id_subtype
== oport
->p_chassis
->c_id_subtype
) &&
324 (chassis
->c_id_len
== oport
->p_chassis
->c_id_len
) &&
325 (memcmp(chassis
->c_id
, oport
->p_chassis
->c_id
,
326 chassis
->c_id_len
) == 0)) {
327 ochassis
= oport
->p_chassis
;
331 /* No, but do we already know the system? */
333 TAILQ_FOREACH(ochassis
, &cfg
->g_chassis
, c_entries
) {
334 if ((chassis
->c_protocol
== ochassis
->c_protocol
) &&
335 (chassis
->c_id_subtype
== ochassis
->c_id_subtype
) &&
336 (chassis
->c_id_len
== ochassis
->c_id_len
) &&
337 (memcmp(chassis
->c_id
, ochassis
->c_id
,
338 chassis
->c_id_len
) == 0))
344 /* The port is known, remove it before adding it back */
345 TAILQ_REMOVE(&hardware
->h_rports
, oport
, p_entries
);
346 lldpd_port_cleanup(oport
, 1);
350 lldpd_update_chassis(ochassis
, chassis
);
354 /* Chassis not known, add it */
355 chassis
->c_index
= ++cfg
->g_lastrid
;
356 port
->p_chassis
= chassis
;
357 chassis
->c_refcount
= 0;
358 TAILQ_INSERT_TAIL(&cfg
->g_chassis
, chassis
, c_entries
);
359 i
= 0; TAILQ_FOREACH(ochassis
, &cfg
->g_chassis
, c_entries
) i
++;
360 LLOG_DEBUG("Currently, we know %d different systems", i
);
363 port
->p_lastchange
= port
->p_lastupdate
= time(NULL
);
364 if ((port
->p_lastframe
= (struct lldpd_frame
*)malloc(s
+
365 sizeof(int))) != NULL
) {
366 port
->p_lastframe
->size
= s
;
367 memcpy(port
->p_lastframe
->frame
, frame
, s
);
369 TAILQ_INSERT_TAIL(&hardware
->h_rports
, port
, p_entries
);
370 port
->p_chassis
= chassis
;
371 port
->p_chassis
->c_refcount
++;
372 i
= 0; TAILQ_FOREACH(oport
, &hardware
->h_rports
, p_entries
) i
++;
373 LLOG_DEBUG("Currently, %s known %d neighbors",
374 hardware
->h_ifname
, i
);
378 /* Update chassis `ochassis' with values from `chassis'. */
380 lldpd_update_chassis(struct lldpd_chassis
*ochassis
,
381 const struct lldpd_chassis
*chassis
) {
382 TAILQ_ENTRY(lldpd_chassis
) entries
;
383 /* We want to keep refcount, index and list stuff from the current
385 int refcount
= ochassis
->c_refcount
;
386 int index
= ochassis
->c_index
;
387 memcpy(&entries
, &ochassis
->c_entries
,
390 lldpd_chassis_cleanup(ochassis
, 0);
391 memcpy(ochassis
, chassis
, sizeof(struct lldpd_chassis
));
392 /* Restore saved values */
393 ochassis
->c_refcount
= refcount
;
394 ochassis
->c_index
= index
;
395 memcpy(&ochassis
->c_entries
, &entries
, sizeof(entries
));
400 lldpd_recv_all(struct lldpd
*cfg
)
402 struct lldpd_hardware
*hardware
;
403 struct lldpd_client
*client
, *client_next
;
408 struct timeval
*tvp
= &tv
;
414 tv
.tv_sec
= cfg
->g_delay
- (time(NULL
) - cfg
->g_lastsent
);
416 tv
.tv_sec
= LLDPD_TX_DELAY
;
417 if (tv
.tv_sec
>= cfg
->g_delay
)
418 tv
.tv_sec
= cfg
->g_delay
;
424 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
425 /* Ignore if interface is down */
426 if ((hardware
->h_flags
& IFF_RUNNING
) == 0)
428 /* This is quite expensive but we don't rely on internal
429 * structure of fd_set. */
430 for (n
= 0; n
< FD_SETSIZE
; n
++)
431 if (FD_ISSET(n
, &hardware
->h_recvfds
)) {
437 TAILQ_FOREACH(client
, &cfg
->g_clients
, next
) {
438 FD_SET(client
->fd
, &rfds
);
439 if (nfds
< client
->fd
)
442 FD_SET(cfg
->g_ctl
, &rfds
);
443 if (nfds
< cfg
->g_ctl
)
448 snmp_select_info(&nfds
, &rfds
, tvp
, &fakeblock
);
449 #endif /* USE_SNMP */
455 rc
= select(nfds
+ 1, &rfds
, NULL
, NULL
, &tv
);
459 LLOG_WARN("failure on select");
469 #endif /* USE_SNMP */
470 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
471 for (n
= 0; n
< FD_SETSIZE
; n
++)
472 if ((FD_ISSET(n
, &hardware
->h_recvfds
)) &&
473 (FD_ISSET(n
, &rfds
))) break;
474 if (n
== FD_SETSIZE
) continue;
475 if ((buffer
= (char *)malloc(
476 hardware
->h_mtu
)) == NULL
) {
477 LLOG_WARN("failed to alloc reception buffer");
480 if ((n
= hardware
->h_ops
->recv(cfg
, hardware
,
481 n
, buffer
, hardware
->h_mtu
)) == -1) {
485 hardware
->h_rx_cnt
++;
486 lldpd_decode(cfg
, buffer
, n
, hardware
);
490 if (FD_ISSET(cfg
->g_ctl
, &rfds
)) {
491 if (ctl_accept(cfg
, cfg
->g_ctl
) == -1)
492 LLOG_WARN("unable to accept new client");
494 for (client
= TAILQ_FIRST(&cfg
->g_clients
);
496 client
= client_next
) {
497 client_next
= TAILQ_NEXT(client
, next
);
498 if (FD_ISSET(client
->fd
, &rfds
)) {
500 if ((buffer
= (char *)malloc(MAX_HMSGSIZE
)) ==
502 LLOG_WARN("failed to alloc reception buffer");
505 if ((n
= recv(client
->fd
, buffer
,
506 MAX_HMSGSIZE
, 0)) == -1) {
507 LLOG_WARN("error while receiving message");
512 client_handle_client(cfg
, client
, buffer
, n
);
514 ctl_close(cfg
, client
->fd
); /* Will use TAILQ_REMOVE ! */
522 netsnmp_check_outstanding_agent_requests();
524 #endif /* USE_SNMP */
525 } while ((rc
!= 0) || (time(NULL
) - cfg
->g_lastsent
< cfg
->g_delay
));
529 lldpd_send_all(struct lldpd
*cfg
)
531 struct lldpd_hardware
*hardware
;
532 struct lldpd_port
*port
;
535 cfg
->g_lastsent
= time(NULL
);
536 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
537 /* Ignore if interface is down */
538 if ((hardware
->h_flags
& IFF_RUNNING
) == 0)
541 for (i
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
542 if (!cfg
->g_protocols
[i
].enabled
)
544 /* We send only if we have at least one remote system
545 * speaking this protocol */
546 TAILQ_FOREACH(port
, &hardware
->h_rports
, p_entries
) {
547 if (port
->p_protocol
==
548 cfg
->g_protocols
[i
].mode
) {
549 cfg
->g_protocols
[i
].send(cfg
,
558 /* Nothing was sent for this port, let's speak LLDP */
559 cfg
->g_protocols
[0].send(cfg
,
564 #ifdef ENABLE_LLDPMED
566 lldpd_med(struct lldpd_chassis
*chassis
)
568 free(chassis
->c_med_hw
);
569 free(chassis
->c_med_fw
);
570 free(chassis
->c_med_sn
);
571 free(chassis
->c_med_manuf
);
572 free(chassis
->c_med_model
);
573 free(chassis
->c_med_asset
);
574 chassis
->c_med_hw
= dmi_hw();
575 chassis
->c_med_fw
= dmi_fw();
576 chassis
->c_med_sn
= dmi_sn();
577 chassis
->c_med_manuf
= dmi_manuf();
578 chassis
->c_med_model
= dmi_model();
579 chassis
->c_med_asset
= dmi_asset();
584 lldpd_update_localchassis(struct lldpd
*cfg
)
590 struct lldpd_hardware
*hardware
;
592 /* Set system name and description */
594 fatal("failed to get system information");
595 if ((hp
= priv_gethostbyname()) == NULL
)
596 fatal("failed to get system name");
597 free(LOCAL_CHASSIS(cfg
)->c_name
);
598 free(LOCAL_CHASSIS(cfg
)->c_descr
);
599 if ((LOCAL_CHASSIS(cfg
)->c_name
= strdup(hp
)) == NULL
)
601 if (asprintf(&LOCAL_CHASSIS(cfg
)->c_descr
, "%s %s %s %s",
602 un
.sysname
, un
.release
, un
.version
, un
.machine
) == -1)
603 fatal("failed to set system description");
605 /* Check forwarding */
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_bond
, /* Handle bond */
640 lldpd_ifh_eth
, /* Handle classic ethernet interfaces */
641 lldpd_ifh_vlan
, /* Handle VLAN */
642 lldpd_ifh_mgmt
, /* Handle management address (if not already handled) */
645 lldpd_ifhandlers
*ifh
;
647 /* h_flags is set to 0 for each port. If the port is updated, h_flags
648 * will be set to a non-zero value. This will allow us to clean up any
649 * non up-to-date port */
650 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
)
651 hardware
->h_flags
= 0;
653 LOCAL_CHASSIS(cfg
)->c_mgmt
.s_addr
= INADDR_ANY
;
654 if (getifaddrs(&ifap
) != 0)
655 fatal("lldpd_update_localports: failed to get interface list");
657 /* We will run the list of interfaces through a list of interface
658 * handlers. Each handler will create or update some hardware port (and
659 * will set h_flags to a non zero value. The handler can use the list of
660 * interfaces but this is not mandatory. If the interface handler
661 * handles an interface from the list, it should set ifa_flags to 0 to
662 * let know the other handlers that it took care of this interface. This
663 * means that more specific handlers should be before less specific
665 for (ifh
= ifhs
; *ifh
!= NULL
; ifh
++)
671 lldpd_loop(struct lldpd
*cfg
)
675 1. Update local ports information
676 2. Clean unwanted (removed) local ports
677 3. Update local chassis information
681 LOCAL_CHASSIS(cfg
)->c_cap_enabled
= 0;
682 lldpd_update_localports(cfg
);
684 lldpd_update_localchassis(cfg
);
690 lldpd_shutdown(int sig
)
692 LLOG_INFO("signal received, exiting");
696 /* For signal handling */
697 static struct lldpd
*gcfg
= NULL
;
702 struct lldpd_hardware
*hardware
, *hardware_next
;
705 for (hardware
= TAILQ_FIRST(&gcfg
->g_hardware
); hardware
!= NULL
;
706 hardware
= hardware_next
) {
707 hardware_next
= TAILQ_NEXT(hardware
, h_entries
);
708 lldpd_hardware_cleanup(gcfg
, hardware
);
713 #endif /* USE_SNMP */
717 main(int argc
, char *argv
[])
720 struct lldpd_chassis
*lchassis
;
726 char *popt
, opts
[] = "dxm:p:M:i@ ";
728 #ifdef ENABLE_LLDPMED
729 int lldpmed
= 0, noinventory
= 0;
735 * Get and parse command line options
737 popt
= index(opts
, '@');
738 for (i
=0; protos
[i
].mode
!= 0; i
++) {
739 if (protos
[i
].enabled
== 1) continue;
740 *(popt
++) = protos
[i
].arg
;
743 while ((ch
= getopt(argc
, argv
, opts
)) != -1) {
751 #ifdef ENABLE_LLDPMED
753 lldpmed
= atoi(optarg
);
754 if ((lldpmed
< 1) || (lldpmed
> 4)) {
755 fprintf(stderr
, "-M requires an argument between 1 and 4\n");
766 fprintf(stderr
, "LLDP-MED support is not built-in\n");
774 fprintf(stderr
, "SNMP support is not built-in\n");
780 for (i
=0; protos
[i
].mode
!= 0; i
++) {
781 if (protos
[i
].enabled
) continue;
782 if (ch
== protos
[i
].arg
) {
783 protos
[i
].enabled
= 1;
797 if (daemon(0, 0) != 0)
798 fatal("failed to detach daemon");
799 if ((pid
= open(LLDPD_PID_FILE
,
800 O_TRUNC
| O_CREAT
| O_WRONLY
, 0644)) == -1)
801 fatal("unable to open pid file " LLDPD_PID_FILE
);
802 if (asprintf(&spid
, "%d\n", getpid()) == -1)
803 fatal("unable to create pid file " LLDPD_PID_FILE
);
804 if (write(pid
, spid
, strlen(spid
)) == -1)
805 fatal("unable to write pid file " LLDPD_PID_FILE
);
810 priv_init(PRIVSEP_CHROOT
);
812 if ((cfg
= (struct lldpd
*)
813 calloc(1, sizeof(struct lldpd
))) == NULL
)
816 cfg
->g_mgmt_pattern
= mgmtp
;
818 /* Get ioctl socket */
819 if ((cfg
->g_sock
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1)
820 fatal("failed to get ioctl socket");
821 cfg
->g_delay
= LLDPD_TX_DELAY
;
823 /* Set system capabilities */
824 if ((lchassis
= (struct lldpd_chassis
*)
825 calloc(1, sizeof(struct lldpd_chassis
))) == NULL
)
827 lchassis
->c_cap_available
= LLDP_CAP_BRIDGE
| LLDP_CAP_WLAN
|
829 #ifdef ENABLE_LLDPMED
831 if (lldpmed
== LLDPMED_CLASS_III
)
832 lchassis
->c_cap_available
|= LLDP_CAP_TELEPHONE
;
833 lchassis
->c_med_type
= lldpmed
;
834 lchassis
->c_med_cap_available
= LLDPMED_CAP_CAP
|
835 LLDPMED_CAP_IV
| LLDPMED_CAP_LOCATION
;
836 cfg
->g_noinventory
= noinventory
;
838 cfg
->g_noinventory
= 1;
842 lchassis
->c_ttl
= LLDPD_TTL
;
844 cfg
->g_protocols
= protos
;
845 for (i
=0; protos
[i
].mode
!= 0; i
++)
846 if (protos
[i
].enabled
) {
847 LLOG_INFO("protocol %s enabled", protos
[i
].name
);
849 LLOG_INFO("protocol %s disabled", protos
[i
].name
);
851 TAILQ_INIT(&cfg
->g_hardware
);
852 TAILQ_INIT(&cfg
->g_chassis
);
853 TAILQ_INSERT_TAIL(&cfg
->g_chassis
, lchassis
, c_entries
);
854 lchassis
->c_refcount
++;
859 agent_init(cfg
, debug
);
861 #endif /* USE_SNMP */
864 if ((cfg
->g_ctl
= priv_ctl_create(cfg
)) == -1)
865 fatalx("unable to create control socket " LLDPD_CTL_SOCKET
);
866 TAILQ_INIT(&cfg
->g_clients
);
869 if (atexit(lldpd_exit
) != 0) {
872 fatal("unable to set exit function");
875 /* Signal handling */
876 signal(SIGHUP
, lldpd_shutdown
);
877 signal(SIGINT
, lldpd_shutdown
);
878 signal(SIGTERM
, lldpd_shutdown
);