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 static void lldpd_update_chassis(struct lldpd_chassis
*,
120 const struct lldpd_chassis
*);
121 #ifdef ENABLE_LLDPMED
122 static void lldpd_med(struct lldpd_chassis
*);
125 static char **saved_argv
;
130 extern const char *__progname
;
131 fprintf(stderr
, "usage: %s [options]\n", __progname
);
132 fprintf(stderr
, "see manual page lldpd(8) for more information\n");
137 lldpd_iface_init_mtu(struct lldpd
*global
, struct lldpd_hardware
*hardware
)
142 memset(&ifr
, 0, sizeof(ifr
));
143 strlcpy(ifr
.ifr_name
, hardware
->h_ifname
, sizeof(ifr
.ifr_name
));
144 if (ioctl(global
->g_sock
, SIOCGIFMTU
, (char*)&ifr
) == -1) {
145 LLOG_WARN("unable to get MTU of %s, using 1500", hardware
->h_ifname
);
146 hardware
->h_mtu
= 1500;
148 hardware
->h_mtu
= hardware
->h_lport
.p_mfs
= ifr
.ifr_mtu
;
152 lldpd_iface_init(struct lldpd
*global
, struct lldpd_hardware
*hardware
)
155 struct sock_fprog prog
;
157 lldpd_iface_init_mtu(global
, hardware
);
158 status
= priv_iface_init(hardware
, -1);
163 prog
.filter
= lldpd_filter_f
;
164 prog
.len
= sizeof(lldpd_filter_f
) / sizeof(struct sock_filter
);
165 if (setsockopt(hardware
->h_raw
, SOL_SOCKET
, SO_ATTACH_FILTER
,
166 &prog
, sizeof(prog
)) < 0) {
167 LLOG_WARN("unable to change filter for %s", hardware
->h_ifname
);
171 lldpd_iface_multicast(global
, hardware
->h_ifname
, 0);
173 LLOG_DEBUG("interface %s initialized (fd=%d)", hardware
->h_ifname
,
179 lldpd_iface_multicast(struct lldpd
*global
, const char *name
, int remove
)
183 for (i
=0; global
->g_protocols
[i
].mode
!= 0; i
++) {
184 if (!global
->g_protocols
[i
].enabled
) continue;
185 if ((rc
= priv_iface_multicast(name
,
186 global
->g_protocols
[i
].mac
, !remove
)) != 0) {
189 LLOG_INFO("unable to %s %s address to multicast filter for %s",
190 (remove
)?"delete":"add",
191 global
->g_protocols
[i
].name
,
198 lldpd_iface_close(struct lldpd
*global
, struct lldpd_hardware
*hardware
)
200 char listen
[IFNAMSIZ
];
202 close(hardware
->h_raw
);
203 hardware
->h_raw
= -1;
205 memcpy(listen
, hardware
->h_ifname
, IFNAMSIZ
);
206 lldpd_iface_multicast(global
, listen
, 1);
213 lldpd_vlan_cleanup(struct lldpd_port
*port
)
215 struct lldpd_vlan
*vlan
, *vlan_next
;
216 for (vlan
= TAILQ_FIRST(&port
->p_vlans
);
220 vlan_next
= TAILQ_NEXT(vlan
, v_entries
);
221 TAILQ_REMOVE(&port
->p_vlans
, vlan
, v_entries
);
227 /* If `all' is true, clear all information, including information that
228 are not refreshed periodically. If `all' is true, also free the
231 lldpd_port_cleanup(struct lldpd_port
*port
, int all
)
233 #ifdef ENABLE_LLDPMED
236 for (i
=0; i
< LLDPMED_LOCFORMAT_LAST
; i
++)
237 free(port
->p_med_location
[i
].data
);
240 lldpd_vlan_cleanup(port
);
245 free(port
->p_lastframe
);
246 if (port
->p_chassis
) /* chassis may not have been attributed, yet */
247 port
->p_chassis
->c_refcount
--;
253 lldpd_chassis_cleanup(struct lldpd_chassis
*chassis
, int all
)
255 #ifdef ENABLE_LLDPMED
256 free(chassis
->c_med_hw
);
257 free(chassis
->c_med_sw
);
258 free(chassis
->c_med_fw
);
259 free(chassis
->c_med_sn
);
260 free(chassis
->c_med_manuf
);
261 free(chassis
->c_med_model
);
262 free(chassis
->c_med_asset
);
265 free(chassis
->c_name
);
266 free(chassis
->c_descr
);
272 lldpd_remote_cleanup(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
, int all
)
274 struct lldpd_port
*port
, *port_next
;
276 for (port
= TAILQ_FIRST(&hardware
->h_rports
);
279 port_next
= TAILQ_NEXT(port
, p_entries
);
282 (time(NULL
) - port
->p_lastupdate
> port
->p_chassis
->c_ttl
)) {
283 hardware
->h_rx_ageout_cnt
++;
287 TAILQ_REMOVE(&hardware
->h_rports
, port
, p_entries
);
288 lldpd_port_cleanup(port
, 1);
294 lldpd_hardware_cleanup(struct lldpd_hardware
*hardware
)
296 lldpd_port_cleanup(&hardware
->h_lport
, 1);
301 lldpd_cleanup(struct lldpd
*cfg
)
303 struct lldpd_hardware
*hardware
, *hardware_next
;
305 for (hardware
= TAILQ_FIRST(&cfg
->g_hardware
); hardware
!= NULL
;
306 hardware
= hardware_next
) {
307 hardware_next
= TAILQ_NEXT(hardware
, h_entries
);
308 if (hardware
->h_flags
== 0) {
309 TAILQ_REMOVE(&cfg
->g_hardware
, hardware
, h_entries
);
310 lldpd_iface_close(cfg
, hardware
);
311 lldpd_remote_cleanup(cfg
, hardware
, 1);
312 lldpd_hardware_cleanup(hardware
);
314 lldpd_remote_cleanup(cfg
, hardware
, 0);
318 static struct lldpd_hardware
*
319 lldpd_hardware_add(struct lldpd
*cfg
, struct ifaddrs
*ifa
)
321 #if defined (ENABLE_DOT1) || defined (ENABLE_DOT3)
322 struct ifaddrs
*oifap
, *oifa
;
324 struct lldpd_hardware
*hardware
;
325 struct lldpd_port
*port
;
327 struct lldpd_vlan
*vlan
;
328 struct vlan_ioctl_args ifv
;
331 struct ethtool_cmd ethc
;
335 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
336 if (strcmp(hardware
->h_ifname
, ifa
->ifa_name
) == 0)
340 if (hardware
== NULL
) {
341 if ((hardware
= (struct lldpd_hardware
*)
342 calloc(1, sizeof(struct lldpd_hardware
))) == NULL
)
344 hardware
->h_raw
= -1;
345 hardware
->h_lport
.p_chassis
= LOCAL_CHASSIS(cfg
);
346 TAILQ_INIT(&hardware
->h_rports
);
347 #ifdef ENABLE_LLDPMED
348 if (LOCAL_CHASSIS(cfg
)->c_med_cap_available
) {
349 hardware
->h_lport
.p_med_cap_enabled
= LLDPMED_CAP_CAP
;
350 if (!cfg
->g_noinventory
)
351 hardware
->h_lport
.p_med_cap_enabled
|= LLDPMED_CAP_IV
;
355 TAILQ_INIT(&hardware
->h_lport
.p_vlans
);
357 lldpd_port_cleanup(&hardware
->h_lport
, 0);
361 port
= &hardware
->h_lport
;
362 hardware
->h_flags
= ifa
->ifa_flags
;
364 strlcpy(hardware
->h_ifname
, ifa
->ifa_name
, sizeof(hardware
->h_ifname
));
365 lladdr
= (u_int8_t
*)(((struct sockaddr_ll
*)ifa
->ifa_addr
)->sll_addr
);
366 memcpy(&hardware
->h_lladdr
, lladdr
, sizeof(hardware
->h_lladdr
));
367 iface_get_permanent_mac(cfg
, hardware
);
368 port
->p_id_subtype
= LLDP_PORTID_SUBTYPE_LLADDR
;
369 if ((port
->p_id
= calloc(1, sizeof(hardware
->h_lladdr
))) == NULL
)
371 memcpy(port
->p_id
, hardware
->h_lladdr
, sizeof(hardware
->h_lladdr
));
372 port
->p_id_len
= sizeof(hardware
->h_lladdr
);
373 port
->p_descr
= strdup(hardware
->h_ifname
);
375 if (LOCAL_CHASSIS(cfg
)->c_id
== NULL
) {
376 /* Use the first port's l2 addr as the chassis ID */
377 if ((LOCAL_CHASSIS(cfg
)->c_id
=
378 malloc(sizeof(hardware
->h_lladdr
))) == NULL
)
380 LOCAL_CHASSIS(cfg
)->c_id_subtype
= LLDP_CHASSISID_SUBTYPE_LLADDR
;
381 LOCAL_CHASSIS(cfg
)->c_id_len
= sizeof(hardware
->h_lladdr
);
382 memcpy(LOCAL_CHASSIS(cfg
)->c_id
,
383 hardware
->h_lladdr
, sizeof(hardware
->h_lladdr
));
386 /* Get VLANS and aggregation status */
387 #if defined (ENABLE_DOT3) || defined (ENABLE_DOT1)
388 if (getifaddrs(&oifap
) != 0)
389 fatal("lldpd_hardware_add: failed to get interface list");
390 for (oifa
= oifap
; oifa
!= NULL
; oifa
= oifa
->ifa_next
) {
392 /* Check if we already have checked this one */
394 TAILQ_FOREACH(vlan
, &port
->p_vlans
, v_entries
) {
395 if (strcmp(vlan
->v_name
, oifa
->ifa_name
) == 0) {
403 /* Aggregation check */
405 if (iface_is_bond_slave(cfg
, hardware
->h_ifname
, oifa
->ifa_name
, NULL
))
406 port
->p_aggregid
= if_nametoindex(oifa
->ifa_name
);
411 memset(&ifv
, 0, sizeof(ifv
));
412 ifv
.cmd
= GET_VLAN_REALDEV_NAME_CMD
;
413 strlcpy(ifv
.device1
, oifa
->ifa_name
, sizeof(ifv
.device1
));
414 if ((ioctl(cfg
->g_sock
, SIOCGIFVLAN
, &ifv
) >= 0) &&
415 ((iface_is_bond_slave(cfg
, hardware
->h_ifname
, ifv
.u
.device2
, NULL
)) ||
416 (iface_is_bridged_to(cfg
, hardware
->h_ifname
, ifv
.u
.device2
)) ||
417 (strncmp(hardware
->h_ifname
, ifv
.u
.device2
, sizeof(ifv
.u
.device2
)) == 0))) {
418 if ((vlan
= (struct lldpd_vlan
*)
419 calloc(1, sizeof(struct lldpd_vlan
))) == NULL
)
421 if ((vlan
->v_name
= strdup(oifa
->ifa_name
)) == NULL
) {
425 memset(&ifv
, 0, sizeof(ifv
));
426 ifv
.cmd
= GET_VLAN_VID_CMD
;
427 strlcpy(ifv
.device1
, oifa
->ifa_name
, sizeof(ifv
.device1
));
428 if (ioctl(cfg
->g_sock
, SIOCGIFVLAN
, &ifv
) < 0) {
429 /* Dunno what happened */
433 vlan
->v_vid
= ifv
.u
.VID
;
434 TAILQ_INSERT_TAIL(&port
->p_vlans
, vlan
, v_entries
);
444 if (priv_ethtool(hardware
->h_ifname
, ðc
) == 0) {
446 int advertised_ethtool_to_rfc3636
[][2] = {
447 {ADVERTISED_10baseT_Half
, LLDP_DOT3_LINK_AUTONEG_10BASE_T
},
448 {ADVERTISED_10baseT_Full
, LLDP_DOT3_LINK_AUTONEG_10BASET_FD
},
449 {ADVERTISED_100baseT_Half
, LLDP_DOT3_LINK_AUTONEG_100BASE_TX
},
450 {ADVERTISED_100baseT_Full
, LLDP_DOT3_LINK_AUTONEG_100BASE_TXFD
},
451 {ADVERTISED_1000baseT_Half
, LLDP_DOT3_LINK_AUTONEG_1000BASE_T
},
452 {ADVERTISED_1000baseT_Full
, LLDP_DOT3_LINK_AUTONEG_1000BASE_TFD
},
453 {ADVERTISED_10000baseT_Full
, LLDP_DOT3_LINK_AUTONEG_OTHER
},
454 {ADVERTISED_Pause
, LLDP_DOT3_LINK_AUTONEG_FDX_PAUSE
},
455 {ADVERTISED_Asym_Pause
, LLDP_DOT3_LINK_AUTONEG_FDX_APAUSE
},
456 {ADVERTISED_2500baseX_Full
, LLDP_DOT3_LINK_AUTONEG_OTHER
},
459 port
->p_autoneg_support
= (ethc
.supported
& SUPPORTED_Autoneg
) ? 1 : 0;
460 port
->p_autoneg_enabled
= (ethc
.autoneg
== AUTONEG_DISABLE
) ? 0 : 1;
461 for (j
=0; advertised_ethtool_to_rfc3636
[j
][0]; j
++) {
462 if (ethc
.advertising
& advertised_ethtool_to_rfc3636
[j
][0])
463 port
->p_autoneg_advertised
|= advertised_ethtool_to_rfc3636
[j
][1];
465 switch (ethc
.speed
) {
467 port
->p_mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
468 LLDP_DOT3_MAU_10BASETFD
: LLDP_DOT3_MAU_10BASETHD
;
469 if (ethc
.port
== PORT_BNC
) port
->p_mau_type
= LLDP_DOT3_MAU_10BASE2
;
470 if (ethc
.port
== PORT_FIBRE
)
471 port
->p_mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
472 LLDP_DOT3_MAU_10BASEFLDF
: LLDP_DOT3_MAU_10BASEFLHD
;
475 port
->p_mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
476 LLDP_DOT3_MAU_100BASETXFD
: LLDP_DOT3_MAU_100BASETXHD
;
477 if (ethc
.port
== PORT_BNC
)
478 port
->p_mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
479 LLDP_DOT3_MAU_100BASET2DF
: LLDP_DOT3_MAU_100BASET2HD
;
480 if (ethc
.port
== PORT_FIBRE
)
481 port
->p_mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
482 LLDP_DOT3_MAU_100BASEFXFD
: LLDP_DOT3_MAU_100BASEFXHD
;
485 port
->p_mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
486 LLDP_DOT3_MAU_1000BASETFD
: LLDP_DOT3_MAU_1000BASETHD
;
487 if (ethc
.port
== PORT_FIBRE
)
488 port
->p_mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
489 LLDP_DOT3_MAU_1000BASEXFD
: LLDP_DOT3_MAU_1000BASEXHD
;
492 port
->p_mau_type
= (ethc
.port
== PORT_FIBRE
) ? \
493 LLDP_DOT3_MAU_10GIGBASEX
: LLDP_DOT3_MAU_10GIGBASER
;
496 if (ethc
.port
== PORT_AUI
) port
->p_mau_type
= LLDP_DOT3_MAU_AUI
;
498 LLOG_DEBUG("unable to get eth info for %s", hardware
->h_ifname
);
501 if (!INTERFACE_OPENED(hardware
)) {
503 if (lldpd_iface_init(cfg
, hardware
) != 0) {
504 LLOG_WARN("unable to initialize %s", hardware
->h_ifname
);
505 lldpd_hardware_cleanup(hardware
);
509 TAILQ_INSERT_TAIL(&cfg
->g_hardware
, hardware
, h_entries
);
516 lldpd_guess_type(struct lldpd
*cfg
, char *frame
, int s
)
521 for (i
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
522 if (!cfg
->g_protocols
[i
].enabled
)
524 if (cfg
->g_protocols
[i
].guess
== NULL
) {
525 if (memcmp(frame
, cfg
->g_protocols
[i
].mac
, ETH_ALEN
) == 0)
526 return cfg
->g_protocols
[i
].mode
;
528 if (cfg
->g_protocols
[i
].guess(frame
, s
))
529 return cfg
->g_protocols
[i
].mode
;
536 lldpd_decode(struct lldpd
*cfg
, char *frame
, int s
,
537 struct lldpd_hardware
*hardware
)
540 struct lldpd_chassis
*chassis
, *ochassis
= NULL
;
541 struct lldpd_port
*port
, *oport
= NULL
;
542 int guess
= LLDPD_MODE_LLDP
;
544 /* Discard VLAN frames */
545 if ((s
>= sizeof(struct ethhdr
)) &&
546 (((struct ethhdr
*)frame
)->h_proto
== htons(ETHERTYPE_VLAN
)))
549 TAILQ_FOREACH(oport
, &hardware
->h_rports
, p_entries
) {
550 if ((oport
->p_lastframe
!= NULL
) &&
551 (oport
->p_lastframe
->size
== s
) &&
552 (memcmp(oport
->p_lastframe
->frame
, frame
, s
) == 0)) {
553 /* Already received the same frame */
554 oport
->p_lastupdate
= time(NULL
);
559 guess
= lldpd_guess_type(cfg
, frame
, s
);
560 for (i
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
561 if (!cfg
->g_protocols
[i
].enabled
)
563 if (cfg
->g_protocols
[i
].mode
== guess
) {
564 if ((result
= cfg
->g_protocols
[i
].decode(cfg
, frame
,
565 s
, hardware
, &chassis
, &port
)) == -1)
567 chassis
->c_protocol
= port
->p_protocol
=
568 cfg
->g_protocols
[i
].mode
;
572 if (cfg
->g_protocols
[i
].mode
== 0) {
573 LLOG_INFO("unable to guess frame type");
577 /* Do we already have the same MSAP somewhere? */
578 TAILQ_FOREACH(oport
, &hardware
->h_rports
, p_entries
) {
579 if ((port
->p_protocol
== oport
->p_protocol
) &&
580 (port
->p_id_subtype
== oport
->p_id_subtype
) &&
581 (port
->p_id_len
== oport
->p_id_len
) &&
582 (memcmp(port
->p_id
, oport
->p_id
, port
->p_id_len
) == 0) &&
583 (chassis
->c_id_subtype
== oport
->p_chassis
->c_id_subtype
) &&
584 (chassis
->c_id_len
== oport
->p_chassis
->c_id_len
) &&
585 (memcmp(chassis
->c_id
, oport
->p_chassis
->c_id
,
586 chassis
->c_id_len
) == 0)) {
587 ochassis
= oport
->p_chassis
;
591 /* No, but do we already know the system? */
593 TAILQ_FOREACH(ochassis
, &cfg
->g_chassis
, c_entries
) {
594 if ((chassis
->c_protocol
== ochassis
->c_protocol
) &&
595 (chassis
->c_id_subtype
== ochassis
->c_id_subtype
) &&
596 (chassis
->c_id_len
== ochassis
->c_id_len
) &&
597 (memcmp(chassis
->c_id
, ochassis
->c_id
,
598 chassis
->c_id_len
) == 0))
604 /* The port is known, remove it before adding it back */
605 TAILQ_REMOVE(&hardware
->h_rports
, oport
, p_entries
);
606 lldpd_port_cleanup(oport
, 1);
609 lldpd_update_chassis(ochassis
, chassis
);
613 /* Chassis not known, add it */
614 chassis
->c_index
= ++cfg
->g_lastrid
;
615 port
->p_chassis
= chassis
;
616 chassis
->c_refcount
= 0;
617 TAILQ_INSERT_TAIL(&cfg
->g_chassis
, chassis
, c_entries
);
618 i
= 0; TAILQ_FOREACH(ochassis
, &cfg
->g_chassis
, c_entries
) i
++;
619 LLOG_DEBUG("Currently, we know %d different systems", i
);
622 port
->p_lastchange
= port
->p_lastupdate
= time(NULL
);
623 if ((port
->p_lastframe
= (struct lldpd_frame
*)malloc(s
+
624 sizeof(int))) != NULL
) {
625 port
->p_lastframe
->size
= s
;
626 memcpy(port
->p_lastframe
->frame
, frame
, s
);
628 TAILQ_INSERT_TAIL(&hardware
->h_rports
, port
, p_entries
);
629 port
->p_chassis
= chassis
;
630 port
->p_chassis
->c_refcount
++;
631 i
= 0; TAILQ_FOREACH(oport
, &hardware
->h_rports
, p_entries
) i
++;
632 LLOG_DEBUG("Currently, %s known %d neighbors",
633 hardware
->h_ifname
, i
);
637 /* Update chassis `ochassis' with values from `chassis'. */
639 lldpd_update_chassis(struct lldpd_chassis
*ochassis
,
640 const struct lldpd_chassis
*chassis
) {
641 TAILQ_ENTRY(lldpd_chassis
) entries
;
642 /* We want to keep refcount, index and list stuff from the current
644 int refcount
= ochassis
->c_refcount
;
645 int index
= ochassis
->c_index
;
646 memcpy(&entries
, &ochassis
->c_entries
,
649 lldpd_chassis_cleanup(ochassis
, 0);
650 memcpy(ochassis
, chassis
, sizeof(struct lldpd_chassis
));
651 /* Restore saved values */
652 ochassis
->c_refcount
= refcount
;
653 ochassis
->c_index
= index
;
654 memcpy(&ochassis
->c_entries
, &entries
, sizeof(entries
));
659 lldpd_recv_all(struct lldpd
*cfg
)
661 struct lldpd_hardware
*hardware
;
662 struct lldpd_client
*client
, *client_next
;
665 struct sockaddr_ll from
;
669 struct timeval
*tvp
= &tv
;
675 tv
.tv_sec
= cfg
->g_delay
- (time(NULL
) - cfg
->g_lastsent
);
677 tv
.tv_sec
= LLDPD_TX_DELAY
;
678 if (tv
.tv_sec
>= cfg
->g_delay
)
679 tv
.tv_sec
= cfg
->g_delay
;
685 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
686 /* Ignore if interface is down */
687 if (((hardware
->h_flags
& IFF_UP
) == 0) ||
688 ((hardware
->h_flags
& IFF_RUNNING
) == 0))
690 FD_SET(hardware
->h_raw
, &rfds
);
691 if (nfds
< hardware
->h_raw
)
692 nfds
= hardware
->h_raw
;
694 TAILQ_FOREACH(client
, &cfg
->g_clients
, next
) {
695 FD_SET(client
->fd
, &rfds
);
696 if (nfds
< client
->fd
)
699 FD_SET(cfg
->g_ctl
, &rfds
);
700 if (nfds
< cfg
->g_ctl
)
705 snmp_select_info(&nfds
, &rfds
, tvp
, &fakeblock
);
706 #endif /* USE_SNMP */
712 rc
= select(nfds
+ 1, &rfds
, NULL
, NULL
, &tv
);
716 LLOG_WARN("failure on select");
726 #endif /* USE_SNMP */
727 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
728 /* We could have received something on _real_
729 * interface. However, even in this case, this could be
730 * just an outgoing packet. We will try to handle both
731 * cases, but maybe not in the same select. */
732 if (FD_ISSET(hardware
->h_raw
, &rfds
)) {
733 if ((buffer
= (char *)malloc(
734 hardware
->h_mtu
)) == NULL
) {
735 LLOG_WARN("failed to alloc reception buffer");
738 fromlen
= sizeof(from
);
743 (struct sockaddr
*)&from
,
745 LLOG_WARN("error while receiving frame on %s",
747 hardware
->h_rx_discarded_cnt
++;
751 if (from
.sll_pkttype
== PACKET_OUTGOING
) {
755 hardware
->h_rx_cnt
++;
756 lldpd_decode(cfg
, buffer
, n
, hardware
);
761 if (FD_ISSET(cfg
->g_ctl
, &rfds
)) {
762 if (ctl_accept(cfg
, cfg
->g_ctl
) == -1)
763 LLOG_WARN("unable to accept new client");
765 for (client
= TAILQ_FIRST(&cfg
->g_clients
);
767 client
= client_next
) {
768 client_next
= TAILQ_NEXT(client
, next
);
769 if (FD_ISSET(client
->fd
, &rfds
)) {
771 if ((buffer
= (char *)malloc(MAX_HMSGSIZE
)) ==
773 LLOG_WARN("failed to alloc reception buffer");
776 if ((n
= recv(client
->fd
, buffer
,
777 MAX_HMSGSIZE
, 0)) == -1) {
778 LLOG_WARN("error while receiving message");
783 client_handle_client(cfg
, client
, buffer
, n
);
785 ctl_close(cfg
, client
->fd
); /* Will use TAILQ_REMOVE ! */
793 netsnmp_check_outstanding_agent_requests();
795 #endif /* USE_SNMP */
796 } while ((rc
!= 0) || (time(NULL
) - cfg
->g_lastsent
< cfg
->g_delay
));
800 lldpd_send_all(struct lldpd
*cfg
)
802 struct lldpd_hardware
*hardware
;
803 struct lldpd_port
*port
;
806 cfg
->g_lastsent
= time(NULL
);
807 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
808 /* Ignore if interface is down */
809 if (((hardware
->h_flags
& IFF_UP
) == 0) ||
810 ((hardware
->h_flags
& IFF_RUNNING
) == 0))
813 for (i
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
814 if (!cfg
->g_protocols
[i
].enabled
)
816 /* We send only if we have at least one remote system
817 * speaking this protocol */
818 TAILQ_FOREACH(port
, &hardware
->h_rports
, p_entries
) {
819 if (port
->p_protocol
==
820 cfg
->g_protocols
[i
].mode
) {
821 cfg
->g_protocols
[i
].send(cfg
,
830 /* Nothing was sent for this port, let's speak LLDP */
831 cfg
->g_protocols
[0].send(cfg
,
836 #ifdef ENABLE_LLDPMED
838 lldpd_med(struct lldpd_chassis
*chassis
)
840 free(chassis
->c_med_hw
);
841 free(chassis
->c_med_fw
);
842 free(chassis
->c_med_sn
);
843 free(chassis
->c_med_manuf
);
844 free(chassis
->c_med_model
);
845 free(chassis
->c_med_asset
);
846 chassis
->c_med_hw
= dmi_hw();
847 chassis
->c_med_fw
= dmi_fw();
848 chassis
->c_med_sn
= dmi_sn();
849 chassis
->c_med_manuf
= dmi_manuf();
850 chassis
->c_med_model
= dmi_model();
851 chassis
->c_med_asset
= dmi_asset();
856 lldpd_loop(struct lldpd
*cfg
)
858 struct ifaddrs
*ifap
, *ifa
;
859 struct sockaddr_ll
*sdl
;
860 struct lldpd_hardware
*hardware
;
866 /* Set system name and description */
867 if ((un
= (struct utsname
*)malloc(sizeof(struct utsname
))) == NULL
)
870 fatal("failed to get system information");
871 if ((hp
= priv_gethostbyname()) == NULL
)
872 fatal("failed to get system name");
873 free(LOCAL_CHASSIS(cfg
)->c_name
);
874 free(LOCAL_CHASSIS(cfg
)->c_descr
);
875 if ((LOCAL_CHASSIS(cfg
)->c_name
= strdup(hp
)) == NULL
)
877 if (asprintf(&LOCAL_CHASSIS(cfg
)->c_descr
, "%s %s %s %s",
878 un
->sysname
, un
->release
, un
->version
, un
->machine
) == -1)
879 fatal("failed to set system description");
881 /* Check forwarding */
882 LOCAL_CHASSIS(cfg
)->c_cap_enabled
= 0;
883 if ((f
= priv_open("/proc/sys/net/ipv4/ip_forward")) >= 0) {
884 if ((read(f
, &status
, 1) == 1) && (status
== '1')) {
885 LOCAL_CHASSIS(cfg
)->c_cap_enabled
= LLDP_CAP_ROUTER
;
889 #ifdef ENABLE_LLDPMED
890 if (LOCAL_CHASSIS(cfg
)->c_cap_available
& LLDP_CAP_TELEPHONE
)
891 LOCAL_CHASSIS(cfg
)->c_cap_enabled
|= LLDP_CAP_TELEPHONE
;
892 lldpd_med(LOCAL_CHASSIS(cfg
));
893 free(LOCAL_CHASSIS(cfg
)->c_med_sw
);
894 LOCAL_CHASSIS(cfg
)->c_med_sw
= strdup(un
->release
);
898 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
)
899 hardware
->h_flags
= 0;
901 if (getifaddrs(&ifap
) != 0)
902 fatal("lldpd_loop: failed to get interface list");
904 LOCAL_CHASSIS(cfg
)->c_mgmt
.s_addr
= INADDR_ANY
;
905 for (ifa
= ifap
; ifa
!= NULL
; ifa
= ifa
->ifa_next
) {
906 if (LOCAL_CHASSIS(cfg
)->c_mgmt
.s_addr
== INADDR_ANY
)
907 /* Get management address, if available */
908 if ((ifa
->ifa_addr
!= NULL
) &&
909 (ifa
->ifa_addr
->sa_family
== AF_INET
)) {
910 struct sockaddr_in
*sa
;
911 sa
= (struct sockaddr_in
*)ifa
->ifa_addr
;
912 if ((ntohl(*(u_int32_t
*)&sa
->sin_addr
) != INADDR_LOOPBACK
) &&
913 (cfg
->g_mgmt_pattern
== NULL
)) {
914 memcpy(&LOCAL_CHASSIS(cfg
)->c_mgmt
,
916 sizeof(struct in_addr
));
917 LOCAL_CHASSIS(cfg
)->c_mgmt_if
= if_nametoindex(ifa
->ifa_name
);
919 else if (cfg
->g_mgmt_pattern
!= NULL
) {
921 ip
= inet_ntoa(sa
->sin_addr
);
922 if (fnmatch(cfg
->g_mgmt_pattern
,
924 memcpy(&LOCAL_CHASSIS(cfg
)->c_mgmt
,
926 sizeof(struct in_addr
));
927 LOCAL_CHASSIS(cfg
)->c_mgmt_if
=
928 if_nametoindex(ifa
->ifa_name
);
933 if (ifa
->ifa_addr
== NULL
||
934 ifa
->ifa_addr
->sa_family
!= PF_PACKET
)
937 sdl
= (struct sockaddr_ll
*)ifa
->ifa_addr
;
938 if (sdl
->sll_hatype
!= ARPHRD_ETHER
|| !sdl
->sll_halen
)
941 if (iface_is_bridge(cfg
, ifa
->ifa_name
)) {
942 LOCAL_CHASSIS(cfg
)->c_cap_enabled
|= LLDP_CAP_BRIDGE
;
946 if ((iface_is_vlan(cfg
, ifa
->ifa_name
)) ||
947 (iface_is_bond(cfg
, ifa
->ifa_name
)))
950 if (!(ifa
->ifa_flags
& (IFF_MULTICAST
|IFF_BROADCAST
)))
953 if (iface_is_wireless(cfg
, ifa
->ifa_name
))
954 LOCAL_CHASSIS(cfg
)->c_cap_enabled
|= LLDP_CAP_WLAN
;
956 if (lldpd_hardware_add(cfg
, ifa
) == NULL
)
957 LLOG_WARNX("failed to allocate port %s, skip it",
970 lldpd_shutdown(int sig
)
972 LLOG_INFO("signal received, exiting");
976 /* For signal handling */
977 static struct lldpd
*gcfg
= NULL
;
982 struct lldpd_hardware
*hardware
;
985 TAILQ_FOREACH(hardware
, &gcfg
->g_hardware
, h_entries
) {
986 if (INTERFACE_OPENED(hardware
))
987 lldpd_iface_close(gcfg
, hardware
);
992 #endif /* USE_SNMP */
996 main(int argc
, char *argv
[])
999 struct lldpd_chassis
*lchassis
;
1005 char *popt
, opts
[] = "dxm:p:M:i@ ";
1007 #ifdef ENABLE_LLDPMED
1008 int lldpmed
= 0, noinventory
= 0;
1014 * Get and parse command line options
1016 popt
= index(opts
, '@');
1017 for (i
=0; protos
[i
].mode
!= 0; i
++) {
1018 if (protos
[i
].enabled
== 1) continue;
1019 *(popt
++) = protos
[i
].arg
;
1022 while ((ch
= getopt(argc
, argv
, opts
)) != -1) {
1030 #ifdef ENABLE_LLDPMED
1032 lldpmed
= atoi(optarg
);
1033 if ((lldpmed
< 1) || (lldpmed
> 4)) {
1034 fprintf(stderr
, "-M requires an argument between 1 and 4\n");
1045 fprintf(stderr
, "LLDP-MED support is not built-in\n");
1053 fprintf(stderr
, "SNMP support is not built-in\n");
1059 for (i
=0; protos
[i
].mode
!= 0; i
++) {
1060 if (protos
[i
].enabled
) continue;
1061 if (ch
== protos
[i
].arg
) {
1062 protos
[i
].enabled
= 1;
1076 if (daemon(0, 0) != 0)
1077 fatal("failed to detach daemon");
1078 if ((pid
= open(LLDPD_PID_FILE
,
1079 O_TRUNC
| O_CREAT
| O_WRONLY
, 0644)) == -1)
1080 fatal("unable to open pid file " LLDPD_PID_FILE
);
1081 if (asprintf(&spid
, "%d\n", getpid()) == -1)
1082 fatal("unable to create pid file " LLDPD_PID_FILE
);
1083 if (write(pid
, spid
, strlen(spid
)) == -1)
1084 fatal("unable to write pid file " LLDPD_PID_FILE
);
1089 priv_init(PRIVSEP_CHROOT
);
1091 if ((cfg
= (struct lldpd
*)
1092 calloc(1, sizeof(struct lldpd
))) == NULL
)
1095 cfg
->g_mgmt_pattern
= mgmtp
;
1097 /* Get ioctl socket */
1098 if ((cfg
->g_sock
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1)
1099 fatal("failed to get ioctl socket");
1100 cfg
->g_delay
= LLDPD_TX_DELAY
;
1102 /* Set system capabilities */
1103 if ((lchassis
= (struct lldpd_chassis
*)
1104 calloc(1, sizeof(struct lldpd_chassis
))) == NULL
)
1106 lchassis
->c_cap_available
= LLDP_CAP_BRIDGE
| LLDP_CAP_WLAN
|
1108 #ifdef ENABLE_LLDPMED
1110 if (lldpmed
== LLDPMED_CLASS_III
)
1111 lchassis
->c_cap_available
|= LLDP_CAP_TELEPHONE
;
1112 lchassis
->c_med_type
= lldpmed
;
1113 lchassis
->c_med_cap_available
= LLDPMED_CAP_CAP
|
1114 LLDPMED_CAP_IV
| LLDPMED_CAP_LOCATION
;
1115 cfg
->g_noinventory
= noinventory
;
1117 cfg
->g_noinventory
= 1;
1121 lchassis
->c_ttl
= LLDPD_TTL
;
1123 cfg
->g_protocols
= protos
;
1124 for (i
=0; protos
[i
].mode
!= 0; i
++)
1125 if (protos
[i
].enabled
) {
1126 LLOG_INFO("protocol %s enabled", protos
[i
].name
);
1128 LLOG_INFO("protocol %s disabled", protos
[i
].name
);
1130 TAILQ_INIT(&cfg
->g_hardware
);
1131 TAILQ_INIT(&cfg
->g_chassis
);
1132 TAILQ_INSERT_TAIL(&cfg
->g_chassis
, lchassis
, c_entries
);
1133 lchassis
->c_refcount
++;
1138 agent_init(cfg
, debug
);
1140 #endif /* USE_SNMP */
1143 if ((cfg
->g_ctl
= priv_ctl_create(cfg
)) == -1)
1144 fatalx("unable to create control socket " LLDPD_CTL_SOCKET
);
1145 TAILQ_INIT(&cfg
->g_clients
);
1148 if (atexit(lldpd_exit
) != 0) {
1151 fatal("unable to set exit function");
1154 /* Signal handling */
1155 signal(SIGHUP
, lldpd_shutdown
);
1156 signal(SIGINT
, lldpd_shutdown
);
1157 signal(SIGTERM
, lldpd_shutdown
);