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.
28 #include <sys/utsname.h>
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <sys/select.h>
33 #include <sys/ioctl.h>
34 #include <arpa/inet.h>
36 #include <net/if_arp.h>
37 #include <linux/filter.h>
38 #include <linux/if_vlan.h>
39 #include <linux/if_packet.h>
40 #include <linux/sockios.h>
43 #include <net-snmp/net-snmp-config.h>
44 #include <net-snmp/net-snmp-includes.h>
45 #include <net-snmp/agent/net-snmp-agent-includes.h>
46 #include <net-snmp/agent/snmp_vars.h>
49 static void usage(void);
51 static int lldpd_iface_init(struct lldpd
*, struct lldpd_hardware
*);
52 static void lldpd_iface_init_mtu(struct lldpd
*, struct lldpd_hardware
*);
53 static int lldpd_iface_close(struct lldpd
*, struct lldpd_hardware
*);
54 static void lldpd_iface_multicast(struct lldpd
*, const char *, int);
56 /* LLDP: "ether proto 0x88cc and ether dst 01:80:c2:00:00:0e" */
57 /* FDP: "ether dst 01:e0:52:cc:cc:cc" */
58 /* CDP: "ether dst 01:00:0c:cc:cc:cc" */
59 /* SONMP: "ether dst 01:00:81:00:01:00" */
60 /* EDP: "ether dst 00:e0:2b:00:00:00" */
61 #define LLDPD_FILTER_F \
62 { 0x28, 0, 0, 0x0000000c }, \
63 { 0x15, 0, 4, 0x000088cc }, \
64 { 0x20, 0, 0, 0x00000002 }, \
65 { 0x15, 0, 2, 0xc200000e }, \
66 { 0x28, 0, 0, 0x00000000 }, \
67 { 0x15, 11, 12, 0x00000180 }, \
68 { 0x20, 0, 0, 0x00000002 }, \
69 { 0x15, 0, 2, 0x2b000000 }, \
70 { 0x28, 0, 0, 0x00000000 }, \
71 { 0x15, 7, 8, 0x000000e0 }, \
72 { 0x15, 1, 0, 0x0ccccccc }, \
73 { 0x15, 0, 2, 0x81000100 }, \
74 { 0x28, 0, 0, 0x00000000 }, \
75 { 0x15, 3, 4, 0x00000100 }, \
76 { 0x15, 0, 3, 0x52cccccc }, \
77 { 0x28, 0, 0, 0x00000000 }, \
78 { 0x15, 0, 1, 0x000001e0 }, \
79 { 0x6, 0, 0, 0x0000ffff }, \
80 { 0x6, 0, 0, 0x00000000 },
81 static struct sock_filter lldpd_filter_f
[] = { LLDPD_FILTER_F
};
83 static struct protocol protos
[] =
85 { LLDPD_MODE_LLDP
, 1, "LLDP", ' ', lldp_send
, lldp_decode
, NULL
,
86 LLDP_MULTICAST_ADDR
},
88 { LLDPD_MODE_CDPV1
, 0, "CDPv1", 'c', cdpv1_send
, cdp_decode
, cdpv1_guess
,
90 { LLDPD_MODE_CDPV2
, 0, "CDPv2", 'c', cdpv2_send
, cdp_decode
, cdpv2_guess
,
94 { LLDPD_MODE_SONMP
, 0, "SONMP", 's', sonmp_send
, sonmp_decode
, NULL
,
95 SONMP_MULTICAST_ADDR
},
98 { LLDPD_MODE_EDP
, 0, "EDP", 'e', edp_send
, edp_decode
, NULL
,
102 { LLDPD_MODE_FDP
, 0, "FDP", 'f', fdp_send
, cdp_decode
, NULL
,
103 FDP_MULTICAST_ADDR
},
105 { 0, 0, "any", ' ', NULL
, NULL
, NULL
,
110 struct lldpd_hardware
*lldpd_hardware_add(struct lldpd
*, struct ifaddrs
*);
111 static void lldpd_loop(struct lldpd
*);
112 static void lldpd_shutdown(int);
113 static void lldpd_exit();
114 static void lldpd_send_all(struct lldpd
*);
115 static void lldpd_recv_all(struct lldpd
*);
116 static int lldpd_guess_type(struct lldpd
*, char *, int);
117 static void lldpd_decode(struct lldpd
*, char *, int,
118 struct lldpd_hardware
*);
119 #ifdef ENABLE_LLDPMED
120 static void lldpd_med(struct lldpd_chassis
*);
123 static char **saved_argv
;
128 extern const char *__progname
;
129 fprintf(stderr
, "usage: %s [options]\n", __progname
);
130 fprintf(stderr
, "see manual page lldpd(8) for more information\n");
135 lldpd_iface_init_mtu(struct lldpd
*global
, struct lldpd_hardware
*hardware
)
140 memset(&ifr
, 0, sizeof(ifr
));
141 strlcpy(ifr
.ifr_name
, hardware
->h_ifname
, sizeof(ifr
.ifr_name
));
142 if (ioctl(global
->g_sock
, SIOCGIFMTU
, (char*)&ifr
) == -1) {
143 LLOG_WARN("unable to get MTU of %s, using 1500", hardware
->h_ifname
);
144 hardware
->h_mtu
= 1500;
146 hardware
->h_mtu
= hardware
->h_lport
.p_mfs
= ifr
.ifr_mtu
;
150 lldpd_iface_init(struct lldpd
*global
, struct lldpd_hardware
*hardware
)
153 struct sock_fprog prog
;
155 lldpd_iface_init_mtu(global
, hardware
);
156 status
= priv_iface_init(hardware
, -1);
161 prog
.filter
= lldpd_filter_f
;
162 prog
.len
= sizeof(lldpd_filter_f
) / sizeof(struct sock_filter
);
163 if (setsockopt(hardware
->h_raw
, SOL_SOCKET
, SO_ATTACH_FILTER
,
164 &prog
, sizeof(prog
)) < 0) {
165 LLOG_WARN("unable to change filter for %s", hardware
->h_ifname
);
169 lldpd_iface_multicast(global
, hardware
->h_ifname
, 0);
171 LLOG_DEBUG("interface %s initialized (fd=%d)", hardware
->h_ifname
,
177 lldpd_iface_multicast(struct lldpd
*global
, const char *name
, int remove
)
181 for (i
=0; global
->g_protocols
[i
].mode
!= 0; i
++) {
182 if (!global
->g_protocols
[i
].enabled
) continue;
183 if ((rc
= priv_iface_multicast(name
,
184 global
->g_protocols
[i
].mac
, !remove
)) != 0) {
187 LLOG_INFO("unable to %s %s address to multicast filter for %s",
188 (remove
)?"delete":"add",
189 global
->g_protocols
[i
].name
,
196 lldpd_iface_close(struct lldpd
*global
, struct lldpd_hardware
*hardware
)
198 char listen
[IFNAMSIZ
];
200 close(hardware
->h_raw
);
201 hardware
->h_raw
= -1;
203 memcpy(listen
, hardware
->h_ifname
, IFNAMSIZ
);
204 lldpd_iface_multicast(global
, listen
, 1);
211 lldpd_vlan_cleanup(struct lldpd_port
*port
)
213 struct lldpd_vlan
*vlan
, *vlan_next
;
214 for (vlan
= TAILQ_FIRST(&port
->p_vlans
);
218 vlan_next
= TAILQ_NEXT(vlan
, v_entries
);
219 TAILQ_REMOVE(&port
->p_vlans
, vlan
, v_entries
);
225 /* If `all' is true, clear all information, including information that
226 are not refreshed periodically. If `all' is true, also free the
229 lldpd_port_cleanup(struct lldpd_port
*port
, int all
)
231 #ifdef ENABLE_LLDPMED
234 for (i
=0; i
< LLDPMED_LOCFORMAT_LAST
; i
++)
235 free(port
->p_med_location
[i
].data
);
238 lldpd_vlan_cleanup(port
);
243 free(port
->p_lastframe
);
244 if (port
->p_chassis
) /* chassis may not have been attributed, yet */
245 port
->p_chassis
->c_refcount
--;
251 lldpd_chassis_cleanup(struct lldpd_chassis
*chassis
, int all
)
253 #ifdef ENABLE_LLDPMED
254 free(chassis
->c_med_hw
);
255 free(chassis
->c_med_sw
);
256 free(chassis
->c_med_fw
);
257 free(chassis
->c_med_sn
);
258 free(chassis
->c_med_manuf
);
259 free(chassis
->c_med_model
);
260 free(chassis
->c_med_asset
);
263 free(chassis
->c_name
);
264 free(chassis
->c_descr
);
270 lldpd_remote_cleanup(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
, int all
)
272 struct lldpd_port
*port
, *port_next
;
274 for (port
= TAILQ_FIRST(&hardware
->h_rports
);
277 port_next
= TAILQ_NEXT(port
, p_entries
);
280 (time(NULL
) - port
->p_lastupdate
> port
->p_chassis
->c_ttl
)) {
281 hardware
->h_rx_ageout_cnt
++;
285 TAILQ_REMOVE(&hardware
->h_rports
, port
, p_entries
);
286 lldpd_port_cleanup(port
, 1);
292 lldpd_hardware_cleanup(struct lldpd_hardware
*hardware
)
294 lldpd_port_cleanup(&hardware
->h_lport
, 1);
299 lldpd_cleanup(struct lldpd
*cfg
)
301 struct lldpd_hardware
*hardware
, *hardware_next
;
303 for (hardware
= TAILQ_FIRST(&cfg
->g_hardware
); hardware
!= NULL
;
304 hardware
= hardware_next
) {
305 hardware_next
= TAILQ_NEXT(hardware
, h_entries
);
306 if (hardware
->h_flags
== 0) {
307 TAILQ_REMOVE(&cfg
->g_hardware
, hardware
, h_entries
);
308 lldpd_iface_close(cfg
, hardware
);
309 lldpd_remote_cleanup(cfg
, hardware
, 1);
310 lldpd_hardware_cleanup(hardware
);
312 lldpd_remote_cleanup(cfg
, hardware
, 0);
316 static struct lldpd_hardware
*
317 lldpd_hardware_add(struct lldpd
*cfg
, struct ifaddrs
*ifa
)
319 #if defined (ENABLE_DOT1) || defined (ENABLE_DOT3)
320 struct ifaddrs
*oifap
, *oifa
;
322 struct lldpd_hardware
*hardware
;
323 struct lldpd_port
*port
;
325 struct lldpd_vlan
*vlan
;
326 struct vlan_ioctl_args ifv
;
329 struct ethtool_cmd ethc
;
333 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
334 if (strcmp(hardware
->h_ifname
, ifa
->ifa_name
) == 0)
338 if (hardware
== NULL
) {
339 if ((hardware
= (struct lldpd_hardware
*)
340 calloc(1, sizeof(struct lldpd_hardware
))) == NULL
)
342 hardware
->h_raw
= -1;
343 hardware
->h_lport
.p_chassis
= LOCAL_CHASSIS(cfg
);
344 TAILQ_INIT(&hardware
->h_rports
);
345 #ifdef ENABLE_LLDPMED
346 if (LOCAL_CHASSIS(cfg
)->c_med_cap_available
) {
347 hardware
->h_lport
.p_med_cap_enabled
= LLDPMED_CAP_CAP
;
348 if (!cfg
->g_noinventory
)
349 hardware
->h_lport
.p_med_cap_enabled
|= LLDPMED_CAP_IV
;
353 TAILQ_INIT(&hardware
->h_lport
.p_vlans
);
355 lldpd_port_cleanup(&hardware
->h_lport
, 0);
359 port
= &hardware
->h_lport
;
360 hardware
->h_flags
= ifa
->ifa_flags
;
362 strlcpy(hardware
->h_ifname
, ifa
->ifa_name
, sizeof(hardware
->h_ifname
));
363 lladdr
= (u_int8_t
*)(((struct sockaddr_ll
*)ifa
->ifa_addr
)->sll_addr
);
364 memcpy(&hardware
->h_lladdr
, lladdr
, sizeof(hardware
->h_lladdr
));
365 iface_get_permanent_mac(cfg
, hardware
);
366 port
->p_id_subtype
= LLDP_PORTID_SUBTYPE_LLADDR
;
367 if ((port
->p_id
= calloc(1, sizeof(hardware
->h_lladdr
))) == NULL
)
369 memcpy(port
->p_id
, hardware
->h_lladdr
, sizeof(hardware
->h_lladdr
));
370 port
->p_id_len
= sizeof(hardware
->h_lladdr
);
371 port
->p_descr
= strdup(hardware
->h_ifname
);
373 if (LOCAL_CHASSIS(cfg
)->c_id
== NULL
) {
374 /* Use the first port's l2 addr as the chassis ID */
375 if ((LOCAL_CHASSIS(cfg
)->c_id
=
376 malloc(sizeof(hardware
->h_lladdr
))) == NULL
)
378 LOCAL_CHASSIS(cfg
)->c_id_subtype
= LLDP_CHASSISID_SUBTYPE_LLADDR
;
379 LOCAL_CHASSIS(cfg
)->c_id_len
= sizeof(hardware
->h_lladdr
);
380 memcpy(LOCAL_CHASSIS(cfg
)->c_id
,
381 hardware
->h_lladdr
, sizeof(hardware
->h_lladdr
));
384 /* Get VLANS and aggregation status */
385 #if defined (ENABLE_DOT3) || defined (ENABLE_DOT1)
386 if (getifaddrs(&oifap
) != 0)
387 fatal("lldpd_hardware_add: failed to get interface list");
388 for (oifa
= oifap
; oifa
!= NULL
; oifa
= oifa
->ifa_next
) {
390 /* Check if we already have checked this one */
392 TAILQ_FOREACH(vlan
, &port
->p_vlans
, v_entries
) {
393 if (strcmp(vlan
->v_name
, oifa
->ifa_name
) == 0) {
401 /* Aggregation check */
403 if (iface_is_bond_slave(cfg
, hardware
->h_ifname
, oifa
->ifa_name
, NULL
))
404 port
->p_aggregid
= if_nametoindex(oifa
->ifa_name
);
409 memset(&ifv
, 0, sizeof(ifv
));
410 ifv
.cmd
= GET_VLAN_REALDEV_NAME_CMD
;
411 strlcpy(ifv
.device1
, oifa
->ifa_name
, sizeof(ifv
.device1
));
412 if ((ioctl(cfg
->g_sock
, SIOCGIFVLAN
, &ifv
) >= 0) &&
413 ((iface_is_bond_slave(cfg
, hardware
->h_ifname
, ifv
.u
.device2
, NULL
)) ||
414 (iface_is_bridged_to(cfg
, hardware
->h_ifname
, ifv
.u
.device2
)) ||
415 (strncmp(hardware
->h_ifname
, ifv
.u
.device2
, sizeof(ifv
.u
.device2
)) == 0))) {
416 if ((vlan
= (struct lldpd_vlan
*)
417 calloc(1, sizeof(struct lldpd_vlan
))) == NULL
)
419 if ((vlan
->v_name
= strdup(oifa
->ifa_name
)) == NULL
) {
423 memset(&ifv
, 0, sizeof(ifv
));
424 ifv
.cmd
= GET_VLAN_VID_CMD
;
425 strlcpy(ifv
.device1
, oifa
->ifa_name
, sizeof(ifv
.device1
));
426 if (ioctl(cfg
->g_sock
, SIOCGIFVLAN
, &ifv
) < 0) {
427 /* Dunno what happened */
431 vlan
->v_vid
= ifv
.u
.VID
;
432 TAILQ_INSERT_TAIL(&port
->p_vlans
, vlan
, v_entries
);
442 if (priv_ethtool(hardware
->h_ifname
, ðc
) == 0) {
444 int advertised_ethtool_to_rfc3636
[][2] = {
445 {ADVERTISED_10baseT_Half
, LLDP_DOT3_LINK_AUTONEG_10BASE_T
},
446 {ADVERTISED_10baseT_Full
, LLDP_DOT3_LINK_AUTONEG_10BASET_FD
},
447 {ADVERTISED_100baseT_Half
, LLDP_DOT3_LINK_AUTONEG_100BASE_TX
},
448 {ADVERTISED_100baseT_Full
, LLDP_DOT3_LINK_AUTONEG_100BASE_TXFD
},
449 {ADVERTISED_1000baseT_Half
, LLDP_DOT3_LINK_AUTONEG_1000BASE_T
},
450 {ADVERTISED_1000baseT_Full
, LLDP_DOT3_LINK_AUTONEG_1000BASE_TFD
},
451 {ADVERTISED_10000baseT_Full
, LLDP_DOT3_LINK_AUTONEG_OTHER
},
452 {ADVERTISED_Pause
, LLDP_DOT3_LINK_AUTONEG_FDX_PAUSE
},
453 {ADVERTISED_Asym_Pause
, LLDP_DOT3_LINK_AUTONEG_FDX_APAUSE
},
454 {ADVERTISED_2500baseX_Full
, LLDP_DOT3_LINK_AUTONEG_OTHER
},
457 port
->p_autoneg_support
= (ethc
.supported
& SUPPORTED_Autoneg
) ? 1 : 0;
458 port
->p_autoneg_enabled
= (ethc
.autoneg
== AUTONEG_DISABLE
) ? 0 : 1;
459 for (j
=0; advertised_ethtool_to_rfc3636
[j
][0]; j
++) {
460 if (ethc
.advertising
& advertised_ethtool_to_rfc3636
[j
][0])
461 port
->p_autoneg_advertised
|= advertised_ethtool_to_rfc3636
[j
][1];
463 switch (ethc
.speed
) {
465 port
->p_mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
466 LLDP_DOT3_MAU_10BASETFD
: LLDP_DOT3_MAU_10BASETHD
;
467 if (ethc
.port
== PORT_BNC
) port
->p_mau_type
= LLDP_DOT3_MAU_10BASE2
;
468 if (ethc
.port
== PORT_FIBRE
)
469 port
->p_mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
470 LLDP_DOT3_MAU_10BASEFLDF
: LLDP_DOT3_MAU_10BASEFLHD
;
473 port
->p_mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
474 LLDP_DOT3_MAU_100BASETXFD
: LLDP_DOT3_MAU_100BASETXHD
;
475 if (ethc
.port
== PORT_BNC
)
476 port
->p_mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
477 LLDP_DOT3_MAU_100BASET2DF
: LLDP_DOT3_MAU_100BASET2HD
;
478 if (ethc
.port
== PORT_FIBRE
)
479 port
->p_mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
480 LLDP_DOT3_MAU_100BASEFXFD
: LLDP_DOT3_MAU_100BASEFXHD
;
483 port
->p_mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
484 LLDP_DOT3_MAU_1000BASETFD
: LLDP_DOT3_MAU_1000BASETHD
;
485 if (ethc
.port
== PORT_FIBRE
)
486 port
->p_mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
487 LLDP_DOT3_MAU_1000BASEXFD
: LLDP_DOT3_MAU_1000BASEXHD
;
490 port
->p_mau_type
= (ethc
.port
== PORT_FIBRE
) ? \
491 LLDP_DOT3_MAU_10GIGBASEX
: LLDP_DOT3_MAU_10GIGBASER
;
494 if (ethc
.port
== PORT_AUI
) port
->p_mau_type
= LLDP_DOT3_MAU_AUI
;
496 LLOG_DEBUG("unable to get eth info for %s", hardware
->h_ifname
);
499 if (!INTERFACE_OPENED(hardware
)) {
501 if (lldpd_iface_init(cfg
, hardware
) != 0) {
502 LLOG_WARN("unable to initialize %s", hardware
->h_ifname
);
503 lldpd_hardware_cleanup(hardware
);
507 TAILQ_INSERT_TAIL(&cfg
->g_hardware
, hardware
, h_entries
);
514 lldpd_guess_type(struct lldpd
*cfg
, char *frame
, int s
)
519 for (i
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
520 if (!cfg
->g_protocols
[i
].enabled
)
522 if (cfg
->g_protocols
[i
].guess
== NULL
) {
523 if (memcmp(frame
, cfg
->g_protocols
[i
].mac
, ETH_ALEN
) == 0)
524 return cfg
->g_protocols
[i
].mode
;
526 if (cfg
->g_protocols
[i
].guess(frame
, s
))
527 return cfg
->g_protocols
[i
].mode
;
534 lldpd_decode(struct lldpd
*cfg
, char *frame
, int s
,
535 struct lldpd_hardware
*hardware
)
538 struct lldpd_chassis
*chassis
, *ochassis
= NULL
;
539 struct lldpd_port
*port
, *oport
= NULL
;
540 int guess
= LLDPD_MODE_LLDP
;
542 /* Discard VLAN frames */
543 if ((s
>= sizeof(struct ethhdr
)) &&
544 (((struct ethhdr
*)frame
)->h_proto
== htons(ETHERTYPE_VLAN
)))
547 TAILQ_FOREACH(oport
, &hardware
->h_rports
, p_entries
) {
548 if ((oport
->p_lastframe
!= NULL
) &&
549 (oport
->p_lastframe
->size
== s
) &&
550 (memcmp(oport
->p_lastframe
->frame
, frame
, s
) == 0)) {
551 /* Already received the same frame */
552 oport
->p_lastupdate
= time(NULL
);
557 guess
= lldpd_guess_type(cfg
, frame
, s
);
558 for (i
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
559 if (!cfg
->g_protocols
[i
].enabled
)
561 if (cfg
->g_protocols
[i
].mode
== guess
) {
562 if ((result
= cfg
->g_protocols
[i
].decode(cfg
, frame
,
563 s
, hardware
, &chassis
, &port
)) == -1)
565 chassis
->c_protocol
= port
->p_protocol
=
566 cfg
->g_protocols
[i
].mode
;
570 if (cfg
->g_protocols
[i
].mode
== 0) {
571 LLOG_INFO("unable to guess frame type");
575 /* Do we already have the same MSAP somewhere? */
576 TAILQ_FOREACH(oport
, &hardware
->h_rports
, p_entries
) {
577 if ((port
->p_protocol
== oport
->p_protocol
) &&
578 (port
->p_id_subtype
== oport
->p_id_subtype
) &&
579 (port
->p_id_len
== oport
->p_id_len
) &&
580 (memcmp(port
->p_id
, oport
->p_id
, port
->p_id_len
) == 0) &&
581 (chassis
->c_id_subtype
== oport
->p_chassis
->c_id_subtype
) &&
582 (chassis
->c_id_len
== oport
->p_chassis
->c_id_len
) &&
583 (memcmp(chassis
->c_id
, oport
->p_chassis
->c_id
,
584 chassis
->c_id_len
) == 0)) {
585 ochassis
= oport
->p_chassis
;
589 /* No, but do we already know the system? */
591 TAILQ_FOREACH(ochassis
, &cfg
->g_chassis
, c_entries
) {
592 if ((chassis
->c_protocol
== ochassis
->c_protocol
) &&
593 (chassis
->c_id_subtype
== ochassis
->c_id_subtype
) &&
594 (chassis
->c_id_len
== ochassis
->c_id_len
) &&
595 (memcmp(chassis
->c_id
, ochassis
->c_id
,
596 chassis
->c_id_len
) == 0))
602 /* The port is known, remove it before adding it back */
603 TAILQ_REMOVE(&hardware
->h_rports
, oport
, p_entries
);
604 lldpd_port_cleanup(oport
, 1);
607 /* Chassis is known, replace values. Hackish */
608 chassis
->c_refcount
= ochassis
->c_refcount
;
609 chassis
->c_index
= ochassis
->c_index
;
610 memcpy(&chassis
->c_entries
, &ochassis
->c_entries
,
611 sizeof(chassis
->c_entries
));
612 lldpd_chassis_cleanup(ochassis
, 0);
613 memcpy(ochassis
, chassis
, sizeof(struct lldpd_chassis
));
617 /* Chassis not known, add it */
618 chassis
->c_index
= ++cfg
->g_lastrid
;
619 port
->p_chassis
= chassis
;
620 chassis
->c_refcount
= 0;
621 TAILQ_INSERT_TAIL(&cfg
->g_chassis
, chassis
, c_entries
);
622 i
= 0; TAILQ_FOREACH(ochassis
, &cfg
->g_chassis
, c_entries
) i
++;
623 LLOG_DEBUG("Currently, we know %d different systems", i
);
626 port
->p_lastchange
= port
->p_lastupdate
= time(NULL
);
627 if ((port
->p_lastframe
= (struct lldpd_frame
*)malloc(s
+
628 sizeof(int))) != NULL
) {
629 port
->p_lastframe
->size
= s
;
630 memcpy(port
->p_lastframe
->frame
, frame
, s
);
632 TAILQ_INSERT_TAIL(&hardware
->h_rports
, port
, p_entries
);
633 port
->p_chassis
= chassis
;
634 port
->p_chassis
->c_refcount
++;
635 i
= 0; TAILQ_FOREACH(oport
, &hardware
->h_rports
, p_entries
) i
++;
636 LLOG_DEBUG("Currently, %s known %d neighbors",
637 hardware
->h_ifname
, i
);
642 lldpd_recv_all(struct lldpd
*cfg
)
644 struct lldpd_hardware
*hardware
;
645 struct lldpd_client
*client
, *client_next
;
648 struct sockaddr_ll from
;
652 struct timeval
*tvp
= &tv
;
658 tv
.tv_sec
= cfg
->g_delay
- (time(NULL
) - cfg
->g_lastsent
);
660 tv
.tv_sec
= LLDPD_TX_DELAY
;
661 if (tv
.tv_sec
>= cfg
->g_delay
)
662 tv
.tv_sec
= cfg
->g_delay
;
668 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
669 /* Ignore if interface is down */
670 if (((hardware
->h_flags
& IFF_UP
) == 0) ||
671 ((hardware
->h_flags
& IFF_RUNNING
) == 0))
673 FD_SET(hardware
->h_raw
, &rfds
);
674 if (nfds
< hardware
->h_raw
)
675 nfds
= hardware
->h_raw
;
677 TAILQ_FOREACH(client
, &cfg
->g_clients
, next
) {
678 FD_SET(client
->fd
, &rfds
);
679 if (nfds
< client
->fd
)
682 FD_SET(cfg
->g_ctl
, &rfds
);
683 if (nfds
< cfg
->g_ctl
)
688 snmp_select_info(&nfds
, &rfds
, tvp
, &fakeblock
);
689 #endif /* USE_SNMP */
695 rc
= select(nfds
+ 1, &rfds
, NULL
, NULL
, &tv
);
699 LLOG_WARN("failure on select");
709 #endif /* USE_SNMP */
710 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
711 /* We could have received something on _real_
712 * interface. However, even in this case, this could be
713 * just an outgoing packet. We will try to handle both
714 * cases, but maybe not in the same select. */
715 if (FD_ISSET(hardware
->h_raw
, &rfds
)) {
716 if ((buffer
= (char *)malloc(
717 hardware
->h_mtu
)) == NULL
) {
718 LLOG_WARN("failed to alloc reception buffer");
721 fromlen
= sizeof(from
);
726 (struct sockaddr
*)&from
,
728 LLOG_WARN("error while receiving frame on %s",
730 hardware
->h_rx_discarded_cnt
++;
734 if (from
.sll_pkttype
== PACKET_OUTGOING
) {
738 hardware
->h_rx_cnt
++;
739 lldpd_decode(cfg
, buffer
, n
, hardware
);
744 if (FD_ISSET(cfg
->g_ctl
, &rfds
)) {
745 if (ctl_accept(cfg
, cfg
->g_ctl
) == -1)
746 LLOG_WARN("unable to accept new client");
748 for (client
= TAILQ_FIRST(&cfg
->g_clients
);
750 client
= client_next
) {
751 client_next
= TAILQ_NEXT(client
, next
);
752 if (FD_ISSET(client
->fd
, &rfds
)) {
754 if ((buffer
= (char *)malloc(MAX_HMSGSIZE
)) ==
756 LLOG_WARN("failed to alloc reception buffer");
759 if ((n
= recv(client
->fd
, buffer
,
760 MAX_HMSGSIZE
, 0)) == -1) {
761 LLOG_WARN("error while receiving message");
766 client_handle_client(cfg
, client
, buffer
, n
);
768 ctl_close(cfg
, client
->fd
); /* Will use TAILQ_REMOVE ! */
776 netsnmp_check_outstanding_agent_requests();
778 #endif /* USE_SNMP */
779 } while ((rc
!= 0) || (time(NULL
) - cfg
->g_lastsent
< cfg
->g_delay
));
783 lldpd_send_all(struct lldpd
*cfg
)
785 struct lldpd_hardware
*hardware
;
786 struct lldpd_port
*port
;
789 cfg
->g_lastsent
= time(NULL
);
790 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
791 /* Ignore if interface is down */
792 if (((hardware
->h_flags
& IFF_UP
) == 0) ||
793 ((hardware
->h_flags
& IFF_RUNNING
) == 0))
796 for (i
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
797 if (!cfg
->g_protocols
[i
].enabled
)
799 /* We send only if we have at least one remote system
800 * speaking this protocol */
801 TAILQ_FOREACH(port
, &hardware
->h_rports
, p_entries
) {
802 if (port
->p_protocol
==
803 cfg
->g_protocols
[i
].mode
) {
804 cfg
->g_protocols
[i
].send(cfg
,
813 /* Nothing was sent for this port, let's speak LLDP */
814 cfg
->g_protocols
[0].send(cfg
,
819 #ifdef ENABLE_LLDPMED
821 lldpd_med(struct lldpd_chassis
*chassis
)
823 free(chassis
->c_med_hw
);
824 free(chassis
->c_med_fw
);
825 free(chassis
->c_med_sn
);
826 free(chassis
->c_med_manuf
);
827 free(chassis
->c_med_model
);
828 free(chassis
->c_med_asset
);
829 chassis
->c_med_hw
= dmi_hw();
830 chassis
->c_med_fw
= dmi_fw();
831 chassis
->c_med_sn
= dmi_sn();
832 chassis
->c_med_manuf
= dmi_manuf();
833 chassis
->c_med_model
= dmi_model();
834 chassis
->c_med_asset
= dmi_asset();
839 lldpd_loop(struct lldpd
*cfg
)
841 struct ifaddrs
*ifap
, *ifa
;
842 struct sockaddr_ll
*sdl
;
843 struct lldpd_hardware
*hardware
;
849 /* Set system name and description */
850 if ((un
= (struct utsname
*)malloc(sizeof(struct utsname
))) == NULL
)
853 fatal("failed to get system information");
854 if ((hp
= priv_gethostbyname()) == NULL
)
855 fatal("failed to get system name");
856 free(LOCAL_CHASSIS(cfg
)->c_name
);
857 free(LOCAL_CHASSIS(cfg
)->c_descr
);
858 if ((LOCAL_CHASSIS(cfg
)->c_name
= strdup(hp
)) == NULL
)
860 if (asprintf(&LOCAL_CHASSIS(cfg
)->c_descr
, "%s %s %s %s",
861 un
->sysname
, un
->release
, un
->version
, un
->machine
) == -1)
862 fatal("failed to set system description");
864 /* Check forwarding */
865 LOCAL_CHASSIS(cfg
)->c_cap_enabled
= 0;
866 if ((f
= priv_open("/proc/sys/net/ipv4/ip_forward")) >= 0) {
867 if ((read(f
, &status
, 1) == 1) && (status
== '1')) {
868 LOCAL_CHASSIS(cfg
)->c_cap_enabled
= LLDP_CAP_ROUTER
;
872 #ifdef ENABLE_LLDPMED
873 if (LOCAL_CHASSIS(cfg
)->c_cap_available
& LLDP_CAP_TELEPHONE
)
874 LOCAL_CHASSIS(cfg
)->c_cap_enabled
|= LLDP_CAP_TELEPHONE
;
875 lldpd_med(LOCAL_CHASSIS(cfg
));
876 free(LOCAL_CHASSIS(cfg
)->c_med_sw
);
877 LOCAL_CHASSIS(cfg
)->c_med_sw
= strdup(un
->release
);
881 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
)
882 hardware
->h_flags
= 0;
884 if (getifaddrs(&ifap
) != 0)
885 fatal("lldpd_loop: failed to get interface list");
887 LOCAL_CHASSIS(cfg
)->c_mgmt
.s_addr
= INADDR_ANY
;
888 for (ifa
= ifap
; ifa
!= NULL
; ifa
= ifa
->ifa_next
) {
889 if (LOCAL_CHASSIS(cfg
)->c_mgmt
.s_addr
== INADDR_ANY
)
890 /* Get management address, if available */
891 if ((ifa
->ifa_addr
!= NULL
) &&
892 (ifa
->ifa_addr
->sa_family
== AF_INET
)) {
893 struct sockaddr_in
*sa
;
894 sa
= (struct sockaddr_in
*)ifa
->ifa_addr
;
895 if ((ntohl(*(u_int32_t
*)&sa
->sin_addr
) != INADDR_LOOPBACK
) &&
896 (cfg
->g_mgmt_pattern
== NULL
)) {
897 memcpy(&LOCAL_CHASSIS(cfg
)->c_mgmt
,
899 sizeof(struct in_addr
));
900 LOCAL_CHASSIS(cfg
)->c_mgmt_if
= if_nametoindex(ifa
->ifa_name
);
902 else if (cfg
->g_mgmt_pattern
!= NULL
) {
904 ip
= inet_ntoa(sa
->sin_addr
);
905 if (fnmatch(cfg
->g_mgmt_pattern
,
907 memcpy(&LOCAL_CHASSIS(cfg
)->c_mgmt
,
909 sizeof(struct in_addr
));
910 LOCAL_CHASSIS(cfg
)->c_mgmt_if
=
911 if_nametoindex(ifa
->ifa_name
);
916 if (ifa
->ifa_addr
== NULL
||
917 ifa
->ifa_addr
->sa_family
!= PF_PACKET
)
920 sdl
= (struct sockaddr_ll
*)ifa
->ifa_addr
;
921 if (sdl
->sll_hatype
!= ARPHRD_ETHER
|| !sdl
->sll_halen
)
924 if (iface_is_bridge(cfg
, ifa
->ifa_name
)) {
925 LOCAL_CHASSIS(cfg
)->c_cap_enabled
|= LLDP_CAP_BRIDGE
;
929 if ((iface_is_vlan(cfg
, ifa
->ifa_name
)) ||
930 (iface_is_bond(cfg
, ifa
->ifa_name
)))
933 if (!(ifa
->ifa_flags
& (IFF_MULTICAST
|IFF_BROADCAST
)))
936 if (iface_is_wireless(cfg
, ifa
->ifa_name
))
937 LOCAL_CHASSIS(cfg
)->c_cap_enabled
|= LLDP_CAP_WLAN
;
939 if (lldpd_hardware_add(cfg
, ifa
) == NULL
)
940 LLOG_WARNX("failed to allocate port %s, skip it",
953 lldpd_shutdown(int sig
)
955 LLOG_INFO("signal received, exiting");
959 /* For signal handling */
960 static struct lldpd
*gcfg
= NULL
;
965 struct lldpd_hardware
*hardware
;
968 TAILQ_FOREACH(hardware
, &gcfg
->g_hardware
, h_entries
) {
969 if (INTERFACE_OPENED(hardware
))
970 lldpd_iface_close(gcfg
, hardware
);
975 #endif /* USE_SNMP */
979 main(int argc
, char *argv
[])
982 struct lldpd_chassis
*lchassis
;
988 char *popt
, opts
[] = "dxm:p:M:i@ ";
990 #ifdef ENABLE_LLDPMED
991 int lldpmed
= 0, noinventory
= 0;
997 * Get and parse command line options
999 popt
= index(opts
, '@');
1000 for (i
=0; protos
[i
].mode
!= 0; i
++) {
1001 if (protos
[i
].enabled
== 1) continue;
1002 *(popt
++) = protos
[i
].arg
;
1005 while ((ch
= getopt(argc
, argv
, opts
)) != -1) {
1013 #ifdef ENABLE_LLDPMED
1015 lldpmed
= atoi(optarg
);
1016 if ((lldpmed
< 1) || (lldpmed
> 4)) {
1017 fprintf(stderr
, "-M requires an argument between 1 and 4\n");
1028 fprintf(stderr
, "LLDP-MED support is not built-in\n");
1036 fprintf(stderr
, "SNMP support is not built-in\n");
1042 for (i
=0; protos
[i
].mode
!= 0; i
++) {
1043 if (protos
[i
].enabled
) continue;
1044 if (ch
== protos
[i
].arg
) {
1045 protos
[i
].enabled
= 1;
1059 if (daemon(0, 0) != 0)
1060 fatal("failed to detach daemon");
1061 if ((pid
= open(LLDPD_PID_FILE
,
1062 O_TRUNC
| O_CREAT
| O_WRONLY
, 0644)) == -1)
1063 fatal("unable to open pid file " LLDPD_PID_FILE
);
1064 if (asprintf(&spid
, "%d\n", getpid()) == -1)
1065 fatal("unable to create pid file " LLDPD_PID_FILE
);
1066 if (write(pid
, spid
, strlen(spid
)) == -1)
1067 fatal("unable to write pid file " LLDPD_PID_FILE
);
1072 priv_init(PRIVSEP_CHROOT
);
1074 if ((cfg
= (struct lldpd
*)
1075 calloc(1, sizeof(struct lldpd
))) == NULL
)
1078 cfg
->g_mgmt_pattern
= mgmtp
;
1080 /* Get ioctl socket */
1081 if ((cfg
->g_sock
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1)
1082 fatal("failed to get ioctl socket");
1083 cfg
->g_delay
= LLDPD_TX_DELAY
;
1085 /* Set system capabilities */
1086 if ((lchassis
= (struct lldpd_chassis
*)
1087 calloc(1, sizeof(struct lldpd_chassis
))) == NULL
)
1089 lchassis
->c_cap_available
= LLDP_CAP_BRIDGE
| LLDP_CAP_WLAN
|
1091 #ifdef ENABLE_LLDPMED
1093 if (lldpmed
== LLDPMED_CLASS_III
)
1094 lchassis
->c_cap_available
|= LLDP_CAP_TELEPHONE
;
1095 lchassis
->c_med_type
= lldpmed
;
1096 lchassis
->c_med_cap_available
= LLDPMED_CAP_CAP
|
1097 LLDPMED_CAP_IV
| LLDPMED_CAP_LOCATION
;
1098 cfg
->g_noinventory
= noinventory
;
1100 cfg
->g_noinventory
= 1;
1104 lchassis
->c_ttl
= LLDPD_TTL
;
1106 cfg
->g_protocols
= protos
;
1107 for (i
=0; protos
[i
].mode
!= 0; i
++)
1108 if (protos
[i
].enabled
) {
1109 LLOG_INFO("protocol %s enabled", protos
[i
].name
);
1111 LLOG_INFO("protocol %s disabled", protos
[i
].name
);
1113 TAILQ_INIT(&cfg
->g_hardware
);
1114 TAILQ_INIT(&cfg
->g_chassis
);
1115 TAILQ_INSERT_TAIL(&cfg
->g_chassis
, lchassis
, c_entries
);
1116 lchassis
->c_refcount
++;
1121 agent_init(cfg
, debug
);
1123 #endif /* USE_SNMP */
1126 if ((cfg
->g_ctl
= priv_ctl_create(cfg
)) == -1)
1127 fatalx("unable to create control socket " LLDPD_CTL_SOCKET
);
1128 TAILQ_INIT(&cfg
->g_clients
);
1131 if (atexit(lldpd_exit
) != 0) {
1134 fatal("unable to set exit function");
1137 /* Signal handling */
1138 signal(SIGHUP
, lldpd_shutdown
);
1139 signal(SIGINT
, lldpd_shutdown
);
1140 signal(SIGTERM
, lldpd_shutdown
);