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>
51 int lldpd_iface_init(struct lldpd
*, struct lldpd_hardware
*);
52 int lldpd_iface_init_vlan(struct lldpd
*, struct lldpd_vif
*);
53 void lldpd_iface_init_mtu(struct lldpd
*, struct lldpd_hardware
*);
54 int lldpd_iface_close(struct lldpd
*, struct lldpd_hardware
*);
55 void lldpd_iface_multicast(struct lldpd
*, const char *, int);
57 /* "ether proto 0x88cc and ether dst 01:80:c2:00:00:0e" */
58 #define LLDPD_FILTER_LLDP_F \
59 { 0x28, 0, 0, 0x0000000c }, \
60 { 0x15, 0, 5, 0x000088cc }, \
61 { 0x20, 0, 0, 0x00000002 }, \
62 { 0x15, 0, 3, 0xc200000e }, \
63 { 0x28, 0, 0, 0x00000000 }, \
64 { 0x15, 0, 1, 0x00000180 }, \
65 { 0x6, 0, 0, 0x0000ffff }, \
66 { 0x6, 0, 0, 0x00000000 },
67 struct sock_filter lldpd_filter_lldp_f
[] = { LLDPD_FILTER_LLDP_F
};
69 /* "ether dst 01:e0:52:cc:cc:cc" */
70 #define LLDPD_FILTER_FDP_F \
71 { 0x20, 0, 0, 0x00000002 }, \
72 { 0x15, 0, 3, 0x52cccccc }, \
73 { 0x28, 0, 0, 0x00000000 }, \
74 { 0x15, 0, 1, 0x000001e0 }, \
75 { 0x6, 0, 0, 0x0000ffff }, \
76 { 0x6, 0, 0, 0x00000000 },
77 struct sock_filter lldpd_filter_fdp_f
[] = { LLDPD_FILTER_FDP_F
};
78 #endif /* ENABLE_FDP */
80 /* "ether dst 01:00:0c:cc:cc:cc" */
81 #define LLDPD_FILTER_CDP_F \
82 { 0x20, 0, 0, 0x00000002 }, \
83 { 0x15, 0, 3, 0x0ccccccc }, \
84 { 0x28, 0, 0, 0x00000000 }, \
85 { 0x15, 0, 1, 0x00000100 }, \
86 { 0x6, 0, 0, 0x0000ffff }, \
87 { 0x6, 0, 0, 0x00000000 },
88 struct sock_filter lldpd_filter_cdp_f
[] = { LLDPD_FILTER_CDP_F
};
89 #endif /* ENABLE_CDP */
91 /* "ether dst 01:00:81:00:01:00" */
92 #define LLDPD_FILTER_SONMP_F \
93 { 0x20, 0, 0, 0x00000002 }, \
94 { 0x15, 0, 3, 0x81000100 }, \
95 { 0x28, 0, 0, 0x00000000 }, \
96 { 0x15, 0, 1, 0x00000100 }, \
97 { 0x6, 0, 0, 0x0000ffff }, \
98 { 0x6, 0, 0, 0x00000000 },
99 struct sock_filter lldpd_filter_sonmp_f
[] = { LLDPD_FILTER_SONMP_F
};
100 #endif /* ENABLE_SONMP */
102 /* "ether dst 00:e0:2b:00:00:00" */
103 #define LLDPD_FILTER_EDP_F \
104 { 0x20, 0, 0, 0x00000002 }, \
105 { 0x15, 0, 3, 0x2b000000 }, \
106 { 0x28, 0, 0, 0x00000000 }, \
107 { 0x15, 0, 1, 0x000000e0 }, \
108 { 0x6, 0, 0, 0x0000ffff }, \
109 { 0x6, 0, 0, 0x00000000 },
110 #endif /* ENABLE_EDP */
111 struct sock_filter lldpd_filter_edp_f
[] = { LLDPD_FILTER_EDP_F
};
112 #define LLDPD_FILTER_ANY_F \
113 { 0x28, 0, 0, 0x0000000c }, \
114 { 0x15, 0, 4, 0x000088cc }, \
115 { 0x20, 0, 0, 0x00000002 }, \
116 { 0x15, 0, 2, 0xc200000e }, \
117 { 0x28, 0, 0, 0x00000000 }, \
118 { 0x15, 11, 12, 0x00000180 }, \
119 { 0x20, 0, 0, 0x00000002 }, \
120 { 0x15, 0, 2, 0x2b000000 }, \
121 { 0x28, 0, 0, 0x00000000 }, \
122 { 0x15, 7, 8, 0x000000e0 }, \
123 { 0x15, 1, 0, 0x0ccccccc }, \
124 { 0x15, 0, 2, 0x81000100 }, \
125 { 0x28, 0, 0, 0x00000000 }, \
126 { 0x15, 3, 4, 0x00000100 }, \
127 { 0x15, 0, 3, 0x52cccccc }, \
128 { 0x28, 0, 0, 0x00000000 }, \
129 { 0x15, 0, 1, 0x000001e0 }, \
130 { 0x6, 0, 0, 0x0000ffff }, \
131 { 0x6, 0, 0, 0x00000000 },
132 struct sock_filter lldpd_filter_any_f
[] = { LLDPD_FILTER_ANY_F
};
134 struct protocol protos
[] =
136 { LLDPD_MODE_LLDP
, 1, "LLDP", ' ', lldp_send
, lldp_decode
, NULL
,
137 LLDP_MULTICAST_ADDR
, lldpd_filter_lldp_f
, sizeof(lldpd_filter_lldp_f
) },
139 { LLDPD_MODE_CDPV1
, 0, "CDPv1", 'c', cdpv1_send
, cdp_decode
, cdpv1_guess
,
140 CDP_MULTICAST_ADDR
, lldpd_filter_cdp_f
, sizeof(lldpd_filter_cdp_f
) },
141 { LLDPD_MODE_CDPV2
, 0, "CDPv2", 'c', cdpv2_send
, cdp_decode
, cdpv2_guess
,
142 CDP_MULTICAST_ADDR
, lldpd_filter_cdp_f
, sizeof(lldpd_filter_cdp_f
) },
145 { LLDPD_MODE_SONMP
, 0, "SONMP", 's', sonmp_send
, sonmp_decode
, NULL
,
146 SONMP_MULTICAST_ADDR
, lldpd_filter_sonmp_f
, sizeof(lldpd_filter_sonmp_f
) },
149 { LLDPD_MODE_EDP
, 0, "EDP", 'e', edp_send
, edp_decode
, NULL
,
150 EDP_MULTICAST_ADDR
, lldpd_filter_edp_f
, sizeof(lldpd_filter_edp_f
) },
153 { LLDPD_MODE_FDP
, 0, "FDP", 'f', fdp_send
, cdp_decode
, NULL
,
154 FDP_MULTICAST_ADDR
, lldpd_filter_fdp_f
, sizeof(lldpd_filter_fdp_f
) },
156 { 0, 0, "any", ' ', NULL
, NULL
, NULL
,
157 {0,0,0,0,0,0}, lldpd_filter_any_f
, sizeof(lldpd_filter_any_f
) }
160 int lldpd_iface_switchto(struct lldpd
*, short int,
161 struct lldpd_hardware
*);
162 struct lldpd_hardware
*lldpd_port_add(struct lldpd
*, struct ifaddrs
*);
163 void lldpd_loop(struct lldpd
*);
164 void lldpd_shutdown(int);
166 void lldpd_send_all(struct lldpd
*);
167 void lldpd_recv_all(struct lldpd
*);
168 int lldpd_guess_type(struct lldpd
*, char *, int);
169 void lldpd_decode(struct lldpd
*, char *, int,
170 struct lldpd_hardware
*, int);
171 #ifdef ENABLE_LLDPMED
172 void lldpd_med(struct lldpd_chassis
*);
180 extern const char *__progname
;
181 fprintf(stderr
, "usage: %s [options]\n", __progname
);
182 fprintf(stderr
, "see manual page lldpd(8) for more information\n");
187 lldpd_iface_init_mtu(struct lldpd
*global
, struct lldpd_hardware
*hardware
)
192 memset(&ifr
, 0, sizeof(ifr
));
193 strlcpy(ifr
.ifr_name
, hardware
->h_ifname
, sizeof(ifr
.ifr_name
));
194 if (ioctl(global
->g_sock
, SIOCGIFMTU
, (char*)&ifr
) == -1) {
195 LLOG_WARN("unable to get MTU of %s, using 1500", hardware
->h_ifname
);
196 hardware
->h_mtu
= 1500;
198 hardware
->h_mtu
= ifr
.ifr_mtu
;
202 lldpd_iface_init_vlan(struct lldpd
*global
, struct lldpd_vif
*vif
)
207 lldpd_iface_init_mtu(global
, (struct lldpd_hardware
*)vif
);
208 status
= priv_iface_init((struct lldpd_hardware
*)vif
, -1);
213 filter
= LLDPD_MODE_ANY
;
215 filter
= LLDPD_MODE_LLDP
;
217 if (lldpd_iface_switchto(global
, filter
,
218 (struct lldpd_hardware
*)vif
) == -1) {
219 LLOG_WARNX("unable to apply filter");
223 lldpd_iface_multicast(global
, vif
->vif_ifname
, 0);
225 LLOG_DEBUG("vlan interface %s initialized (fd=%d)", vif
->vif_ifname
,
231 lldpd_iface_init(struct lldpd
*global
, struct lldpd_hardware
*hardware
)
233 int master
; /* Bond device */
234 char if_bond
[IFNAMSIZ
];
238 lldpd_iface_init_mtu(global
, hardware
);
239 status
= priv_iface_init(hardware
, -1);
243 if ((master
= iface_is_enslaved(global
, hardware
->h_ifname
)) != -1) {
244 /* With bonding device, we need to listen on the bond ! */
245 if (if_indextoname(master
, if_bond
) == NULL
) {
246 LLOG_WARN("unable to get index for interface %d (master of %s)",
247 master
, hardware
->h_ifname
);
250 hardware
->h_raw_real
= hardware
->h_raw
;
251 hardware
->h_master
= master
;
252 hardware
->h_raw
= -1;
253 status
= priv_iface_init(hardware
, master
);
255 close(hardware
->h_raw_real
);
256 if (hardware
->h_raw
!= -1)
257 close(hardware
->h_raw
);
263 filter
= LLDPD_MODE_ANY
;
265 filter
= LLDPD_MODE_LLDP
;
266 if (lldpd_iface_switchto(global
, filter
, hardware
) == -1) {
267 LLOG_WARNX("unable to apply filter");
272 lldpd_iface_multicast(global
, if_bond
, 0);
273 lldpd_iface_multicast(global
, hardware
->h_ifname
, 0);
275 LLOG_DEBUG("interface %s initialized (fd=%d)", hardware
->h_ifname
,
281 lldpd_iface_multicast(struct lldpd
*global
, const char *name
, int remove
)
285 for (i
=0; global
->g_protocols
[i
].mode
!= 0; i
++) {
286 if (!global
->g_protocols
[i
].enabled
) continue;
287 if ((rc
= priv_iface_multicast(name
,
288 global
->g_protocols
[i
].mac
, !remove
)) != 0) {
291 LLOG_INFO("unable to %s %s address to multicast filter for %s",
292 (remove
)?"delete":"add",
293 global
->g_protocols
[i
].name
,
300 lldpd_iface_close(struct lldpd
*global
, struct lldpd_hardware
*hardware
)
302 char listen
[IFNAMSIZ
];
304 close(hardware
->h_raw
);
305 hardware
->h_raw
= -1;
307 if (hardware
->h_raw_real
> 0) {
308 if (if_indextoname(hardware
->h_master
, listen
) == NULL
) {
309 LLOG_WARN("unable to get index for interface %d",
311 strlcpy(listen
, hardware
->h_ifname
, sizeof(listen
));
313 close(hardware
->h_raw_real
);
314 lldpd_iface_multicast(global
, listen
, 1);
316 strlcpy(listen
, hardware
->h_ifname
, sizeof(listen
));
317 lldpd_iface_multicast(global
, listen
, 1);
319 hardware
->h_raw_real
= -1;
324 lldpd_iface_switchto(struct lldpd
*cfg
, short int filter
, struct lldpd_hardware
*hardware
)
326 struct sock_fprog prog
;
329 memset(&prog
, 0, sizeof(prog
));
330 for (i
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
331 if (!cfg
->g_protocols
[i
].enabled
) continue;
332 if (cfg
->g_protocols
[i
].mode
== filter
)
335 prog
.filter
= cfg
->g_protocols
[i
].filter
;
336 prog
.len
= cfg
->g_protocols
[i
].filterlen
/ sizeof(struct sock_filter
);
337 if (setsockopt(hardware
->h_raw
, SOL_SOCKET
, SO_ATTACH_FILTER
,
338 &prog
, sizeof(prog
)) < 0) {
339 LLOG_WARN("unable to change filter for %s", hardware
->h_ifname
);
342 if ((hardware
->h_raw_real
> 0) &&
343 (setsockopt(hardware
->h_raw_real
, SOL_SOCKET
, SO_ATTACH_FILTER
,
344 &prog
, sizeof(prog
)) < 0)) {
345 LLOG_WARN("unable to change filter for real device %s", hardware
->h_ifname
);
353 lldpd_vlan_cleanup(struct lldpd_port
*port
)
355 struct lldpd_vlan
*vlan
, *vlan_next
;
356 for (vlan
= TAILQ_FIRST(&port
->p_vlans
);
360 vlan_next
= TAILQ_NEXT(vlan
, v_entries
);
361 TAILQ_REMOVE(&port
->p_vlans
, vlan
, v_entries
);
368 lldpd_port_cleanup(struct lldpd_port
*port
)
371 lldpd_vlan_cleanup(port
);
379 lldpd_chassis_cleanup(struct lldpd_chassis
*chassis
)
381 #ifdef ENABLE_LLDPMED
383 free(chassis
->c_med_hw
);
384 free(chassis
->c_med_fw
);
385 free(chassis
->c_med_sn
);
386 free(chassis
->c_med_manuf
);
387 free(chassis
->c_med_model
);
388 free(chassis
->c_med_asset
);
389 for (i
=0; i
< LLDPMED_LOCFORMAT_LAST
; i
++)
390 free(chassis
->c_med_location
[i
].data
);
393 free(chassis
->c_name
);
394 free(chassis
->c_descr
);
399 lldpd_remote_cleanup(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
, int reset
)
401 if (hardware
->h_rport
!= NULL
) {
402 lldpd_port_cleanup(hardware
->h_rport
);
403 hardware
->h_rport
= NULL
;
405 if (hardware
->h_rchassis
!= NULL
) {
406 lldpd_chassis_cleanup(hardware
->h_rchassis
);
407 hardware
->h_rchassis
= NULL
;
409 hardware
->h_rlastchange
= hardware
->h_rlastupdate
= 0;
410 free(hardware
->h_rlastframe
);
411 hardware
->h_rlastframe
= NULL
;
412 if (reset
&& cfg
->g_multi
) {
413 hardware
->h_mode
= LLDPD_MODE_ANY
;
414 memset(hardware
->h_proto_macs
, 0, ETH_ALEN
*(cfg
->g_multi
+1));
415 hardware
->h_start_probe
= 0;
416 lldpd_iface_switchto(cfg
, LLDPD_MODE_ANY
, hardware
);
421 lldpd_hardware_cleanup(struct lldpd_hardware
*hardware
)
424 lldpd_vlan_cleanup(&hardware
->h_lport
);
426 free(hardware
->h_proto_macs
);
427 free(hardware
->h_llastframe
);
432 lldpd_cleanup(struct lldpd
*cfg
)
434 struct lldpd_hardware
*hardware
, *hardware_next
;
435 struct lldpd_vif
*vif
, *vif_next
;
437 for (hardware
= TAILQ_FIRST(&cfg
->g_hardware
); hardware
!= NULL
;
438 hardware
= hardware_next
) {
439 hardware_next
= TAILQ_NEXT(hardware
, h_entries
);
440 if (hardware
->h_flags
== 0) {
441 TAILQ_REMOVE(&cfg
->g_hardware
, hardware
, h_entries
);
442 lldpd_iface_close(cfg
, hardware
);
443 lldpd_remote_cleanup(cfg
, hardware
, 1);
444 lldpd_hardware_cleanup(hardware
);
445 } else if (hardware
->h_rchassis
!= NULL
) {
446 if (time(NULL
) - hardware
->h_rlastupdate
>
447 hardware
->h_rchassis
->c_ttl
) {
448 lldpd_remote_cleanup(cfg
, hardware
, 1);
449 hardware
->h_rx_ageout_cnt
++;
453 for (vif
= TAILQ_FIRST(&cfg
->g_vif
); vif
!= NULL
;
455 vif_next
= TAILQ_NEXT(vif
, vif_entries
);
456 if (vif
->vif_flags
== 0) {
457 TAILQ_REMOVE(&cfg
->g_vif
, vif
, vif_entries
);
458 lldpd_iface_close(cfg
, (struct lldpd_hardware
*)vif
);
465 lldpd_port_add_vlan(struct lldpd
*cfg
, struct ifaddrs
*ifa
)
467 struct lldpd_vif
*vif
;
468 struct lldpd_hardware
*hardware
;
469 struct vlan_ioctl_args ifv
;
471 TAILQ_FOREACH(vif
, &cfg
->g_vif
, vif_entries
) {
472 if (strcmp(vif
->vif_ifname
, ifa
->ifa_name
) == 0)
477 if ((vif
= (struct lldpd_vif
*)
478 calloc(1, sizeof(struct lldpd_vif
))) == NULL
)
481 vif
->vif_raw_real
= -1;
483 strlcpy(vif
->vif_ifname
, ifa
->ifa_name
, sizeof(vif
->vif_ifname
));
484 vif
->vif_flags
= ifa
->ifa_flags
;
486 if (vif
->vif_raw
== -1) {
488 if (lldpd_iface_init_vlan(cfg
, vif
) != 0) {
493 /* Find the real interface */
494 vif
->vif_real
= NULL
;
495 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
496 memset(&ifv
, 0, sizeof(ifv
));
497 ifv
.cmd
= GET_VLAN_REALDEV_NAME_CMD
;
498 strlcpy(ifv
.device1
, ifa
->ifa_name
, sizeof(ifv
.device1
));
499 if ((ioctl(cfg
->g_sock
, SIOCGIFVLAN
, &ifv
) >= 0) &&
500 (strncmp(hardware
->h_ifname
,
502 sizeof(ifv
.u
.device2
)) == 0))
503 vif
->vif_real
= hardware
;
505 if (vif
->vif_real
== NULL
) {
506 LLOG_WARNX("unable to find real interface for %s",
512 TAILQ_INSERT_TAIL(&cfg
->g_vif
, vif
, vif_entries
);
518 struct lldpd_hardware
*
519 lldpd_port_add(struct lldpd
*cfg
, struct ifaddrs
*ifa
)
521 #if defined (ENABLE_DOT1) || defined (ENABLE_DOT3)
522 struct ifaddrs
*oifap
, *oifa
;
524 struct lldpd_hardware
*hardware
;
525 struct lldpd_port
*port
;
527 struct lldpd_vlan
*vlan
;
528 struct vlan_ioctl_args ifv
;
531 struct ethtool_cmd ethc
;
535 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
536 if (strcmp(hardware
->h_ifname
, ifa
->ifa_name
) == 0)
540 if (hardware
== NULL
) {
541 if ((hardware
= (struct lldpd_hardware
*)
542 calloc(1, sizeof(struct lldpd_hardware
))) == NULL
)
544 hardware
->h_raw
= -1;
545 hardware
->h_raw_real
= -1;
546 hardware
->h_start_probe
= 0;
547 hardware
->h_proto_macs
= (u_int8_t
*)calloc(cfg
->g_multi
+1, ETH_ALEN
);
549 TAILQ_INIT(&hardware
->h_lport
.p_vlans
);
551 lldpd_vlan_cleanup(&hardware
->h_lport
);
555 port
= &hardware
->h_lport
;
556 hardware
->h_flags
= ifa
->ifa_flags
;
558 strlcpy(hardware
->h_ifname
, ifa
->ifa_name
, sizeof(hardware
->h_ifname
));
559 lladdr
= (u_int8_t
*)(((struct sockaddr_ll
*)ifa
->ifa_addr
)->sll_addr
);
560 memcpy(&hardware
->h_lladdr
, lladdr
, sizeof(hardware
->h_lladdr
));
561 iface_get_permanent_mac(cfg
, hardware
);
562 port
->p_id_subtype
= LLDP_PORTID_SUBTYPE_LLADDR
;
563 if ((port
->p_id
= calloc(1, sizeof(hardware
->h_lladdr
))) == NULL
)
565 memcpy(port
->p_id
, hardware
->h_lladdr
, sizeof(hardware
->h_lladdr
));
566 port
->p_id_len
= sizeof(hardware
->h_lladdr
);
567 port
->p_descr
= hardware
->h_ifname
;
569 if (cfg
->g_lchassis
.c_id
== NULL
) {
570 /* Use the first port's l2 addr as the chassis ID */
571 if ((cfg
->g_lchassis
.c_id
= malloc(sizeof(hardware
->h_lladdr
))) == NULL
)
573 cfg
->g_lchassis
.c_id_subtype
= LLDP_CHASSISID_SUBTYPE_LLADDR
;
574 cfg
->g_lchassis
.c_id_len
= sizeof(hardware
->h_lladdr
);
575 memcpy(cfg
->g_lchassis
.c_id
,
576 hardware
->h_lladdr
, sizeof(hardware
->h_lladdr
));
579 /* Get VLANS and aggregation status */
580 #if defined (ENABLE_DOT3) || defined (ENABLE_DOT1)
581 if (getifaddrs(&oifap
) != 0)
582 fatal("lldpd_port_add: failed to get interface list");
583 for (oifa
= oifap
; oifa
!= NULL
; oifa
= oifa
->ifa_next
) {
585 /* Check if we already have checked this one */
587 TAILQ_FOREACH(vlan
, &port
->p_vlans
, v_entries
) {
588 if (strcmp(vlan
->v_name
, oifa
->ifa_name
) == 0)
594 /* Aggregation check */
596 if (iface_is_bond_slave(cfg
, hardware
->h_ifname
, oifa
->ifa_name
, NULL
))
597 port
->p_aggregid
= if_nametoindex(oifa
->ifa_name
);
602 memset(&ifv
, 0, sizeof(ifv
));
603 ifv
.cmd
= GET_VLAN_REALDEV_NAME_CMD
;
604 strlcpy(ifv
.device1
, oifa
->ifa_name
, sizeof(ifv
.device1
));
605 if ((ioctl(cfg
->g_sock
, SIOCGIFVLAN
, &ifv
) >= 0) &&
606 ((iface_is_bond_slave(cfg
, hardware
->h_ifname
, ifv
.u
.device2
, NULL
)) ||
607 (strncmp(hardware
->h_ifname
, ifv
.u
.device2
, sizeof(ifv
.u
.device2
)) == 0))) {
608 if ((vlan
= (struct lldpd_vlan
*)
609 calloc(1, sizeof(struct lldpd_vlan
))) == NULL
)
611 if ((vlan
->v_name
= strdup(oifa
->ifa_name
)) == NULL
) {
615 memset(&ifv
, 0, sizeof(ifv
));
616 ifv
.cmd
= GET_VLAN_VID_CMD
;
617 strlcpy(ifv
.device1
, oifa
->ifa_name
, sizeof(ifv
.device1
));
618 if (ioctl(cfg
->g_sock
, SIOCGIFVLAN
, &ifv
) < 0) {
619 /* Dunno what happened */
623 vlan
->v_vid
= ifv
.u
.VID
;
624 TAILQ_INSERT_TAIL(&port
->p_vlans
, vlan
, v_entries
);
634 if (priv_ethtool(hardware
->h_ifname
, ðc
) == 0) {
636 int advertised_ethtool_to_rfc3636
[][2] = {
637 {ADVERTISED_10baseT_Half
, LLDP_DOT3_LINK_AUTONEG_10BASE_T
},
638 {ADVERTISED_10baseT_Full
, LLDP_DOT3_LINK_AUTONEG_10BASET_FD
},
639 {ADVERTISED_100baseT_Half
, LLDP_DOT3_LINK_AUTONEG_100BASE_TX
},
640 {ADVERTISED_100baseT_Full
, LLDP_DOT3_LINK_AUTONEG_100BASE_TXFD
},
641 {ADVERTISED_1000baseT_Half
, LLDP_DOT3_LINK_AUTONEG_1000BASE_T
},
642 {ADVERTISED_1000baseT_Full
, LLDP_DOT3_LINK_AUTONEG_1000BASE_TFD
},
643 {ADVERTISED_10000baseT_Full
, LLDP_DOT3_LINK_AUTONEG_OTHER
},
644 {ADVERTISED_Pause
, LLDP_DOT3_LINK_AUTONEG_FDX_PAUSE
},
645 {ADVERTISED_Asym_Pause
, LLDP_DOT3_LINK_AUTONEG_FDX_APAUSE
},
646 {ADVERTISED_2500baseX_Full
, LLDP_DOT3_LINK_AUTONEG_OTHER
},
649 port
->p_autoneg_support
= (ethc
.supported
& SUPPORTED_Autoneg
) ? 1 : 0;
650 port
->p_autoneg_enabled
= (ethc
.autoneg
== AUTONEG_DISABLE
) ? 0 : 1;
651 for (j
=0; advertised_ethtool_to_rfc3636
[j
][0]; j
++) {
652 if (ethc
.advertising
& advertised_ethtool_to_rfc3636
[j
][0])
653 port
->p_autoneg_advertised
|= advertised_ethtool_to_rfc3636
[j
][1];
655 switch (ethc
.speed
) {
657 port
->p_mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
658 LLDP_DOT3_MAU_10BASETFD
: LLDP_DOT3_MAU_10BASETHD
;
659 if (ethc
.port
== PORT_BNC
) port
->p_mau_type
= LLDP_DOT3_MAU_10BASE2
;
660 if (ethc
.port
== PORT_FIBRE
)
661 port
->p_mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
662 LLDP_DOT3_MAU_10BASEFLDF
: LLDP_DOT3_MAU_10BASEFLHD
;
665 port
->p_mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
666 LLDP_DOT3_MAU_100BASETXFD
: LLDP_DOT3_MAU_100BASETXHD
;
667 if (ethc
.port
== PORT_BNC
)
668 port
->p_mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
669 LLDP_DOT3_MAU_100BASET2DF
: LLDP_DOT3_MAU_100BASET2HD
;
670 if (ethc
.port
== PORT_FIBRE
)
671 port
->p_mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
672 LLDP_DOT3_MAU_100BASEFXFD
: LLDP_DOT3_MAU_100BASEFXHD
;
675 port
->p_mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
676 LLDP_DOT3_MAU_1000BASETFD
: LLDP_DOT3_MAU_1000BASETHD
;
677 if (ethc
.port
== PORT_FIBRE
)
678 port
->p_mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
679 LLDP_DOT3_MAU_1000BASEXFD
: LLDP_DOT3_MAU_1000BASEXHD
;
682 port
->p_mau_type
= (ethc
.port
== PORT_FIBRE
) ? \
683 LLDP_DOT3_MAU_10GIGBASEX
: LLDP_DOT3_MAU_10GIGBASER
;
686 if (ethc
.port
== PORT_AUI
) port
->p_mau_type
= LLDP_DOT3_MAU_AUI
;
688 LLOG_DEBUG("unable to get eth info for %s", hardware
->h_ifname
);
691 if (!INTERFACE_OPENED(hardware
)) {
693 if (lldpd_iface_init(cfg
, hardware
) != 0) {
694 LLOG_WARN("unable to initialize %s", hardware
->h_ifname
);
695 lldpd_hardware_cleanup(hardware
);
699 TAILQ_INSERT_TAIL(&cfg
->g_hardware
, hardware
, h_entries
);
706 lldpd_guess_type(struct lldpd
*cfg
, char *frame
, int s
)
711 for (i
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
712 if (!cfg
->g_protocols
[i
].enabled
)
714 if (cfg
->g_protocols
[i
].guess
== NULL
) {
715 if (memcmp(frame
, cfg
->g_protocols
[i
].mac
, ETH_ALEN
) == 0)
716 return cfg
->g_protocols
[i
].mode
;
718 if (cfg
->g_protocols
[i
].guess(frame
, s
))
719 return cfg
->g_protocols
[i
].mode
;
726 lldpd_decode(struct lldpd
*cfg
, char *frame
, int s
,
727 struct lldpd_hardware
*hardware
, int bond
)
729 int result
= 0, i
, j
, candidatetonull
;
730 u_int8_t nullmac
[ETH_ALEN
] = {0,0,0,0,0,0};
731 u_int8_t broadcastmac
[ETH_ALEN
] = {0xff,0xff,0xff,0xff,0xff,0xff};
732 struct lldpd_chassis
*chassis
;
733 struct lldpd_port
*port
;
734 struct lldpd_hardware
*ohardware
, *firstnull
= NULL
, *older
= NULL
;
735 int guess
= LLDPD_MODE_LLDP
;
737 /* Discard VLAN frames */
738 if ((s
>= sizeof(struct ieee8023
)) &&
739 (((struct ieee8023
*)frame
)->size
== htons(ETHERTYPE_VLAN
)))
742 if ((hardware
->h_rlastframe
!= NULL
) &&
743 (hardware
->h_rlastframe
->size
== s
) &&
744 (memcmp(hardware
->h_rlastframe
->frame
, frame
, s
) == 0)) {
745 /* Already received the same frame */
746 hardware
->h_rlastupdate
= time(NULL
);
751 if (hardware
->h_mode
== LLDPD_MODE_ANY
)
752 guess
= lldpd_guess_type(cfg
, frame
, s
);
754 guess
= hardware
->h_mode
;
755 for (i
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
756 if (!cfg
->g_protocols
[i
].enabled
)
758 if (cfg
->g_protocols
[i
].mode
== guess
) {
759 if ((result
= cfg
->g_protocols
[i
].decode(cfg
, frame
,
760 s
, hardware
, &chassis
, &port
)) == -1)
765 if (cfg
->g_protocols
[i
].mode
== 0) {
766 LLOG_INFO("unable to guess frame type");
769 } else if (cfg
->g_protocols
[0].decode(cfg
, frame
, s
, hardware
,
770 &chassis
, &port
) == -1)
771 /* Nothing has been received */
775 /* Eh, wait ! The frame we just received was for a bonding
776 * device. We need to attach it to a real device. What is the
777 * best candidate? Drum rolling... */
778 TAILQ_FOREACH(ohardware
, &cfg
->g_hardware
, h_entries
) {
779 if (ohardware
->h_master
== hardware
->h_master
) {
781 if (ohardware
->h_rchassis
== NULL
) {
784 (ohardware
->h_mode
== LLDPD_MODE_ANY
)) {
786 cfg
->g_protocols
[i
].mode
!= 0;
788 if (!cfg
->g_protocols
[i
].enabled
)
790 if ((cfg
->g_protocols
[i
].mode
== guess
) &&
791 (memcmp(frame
+ ETH_ALEN
,
792 ohardware
->h_proto_macs
+ ETH_ALEN
*j
,
794 hardware
= ohardware
;
801 if (firstnull
!= NULL
) {
803 cfg
->g_protocols
[i
].mode
!= 0;
805 if (!cfg
->g_protocols
[i
].enabled
)
807 if ((cfg
->g_protocols
[i
].mode
== guess
) &&
809 ohardware
->h_proto_macs
+
822 /* Ok, this is the first candidate if we
823 * don't find a matching chassis/port */
824 if (candidatetonull
) firstnull
= ohardware
;
827 if ((older
== NULL
) ||
828 (older
->h_rlastupdate
> ohardware
->h_rlastupdate
))
829 /* If there is no matching chassis/port
830 * and no free hardware, we will use
833 if ((chassis
->c_id_subtype
!=
834 ohardware
->h_rchassis
->c_id_subtype
) ||
835 (chassis
->c_id_len
!= ohardware
->h_rchassis
->c_id_len
) ||
836 (memcmp(chassis
->c_id
, ohardware
->h_rchassis
->c_id
,
837 chassis
->c_id_len
) != 0) ||
838 (port
->p_id_subtype
!= ohardware
->h_rport
->p_id_subtype
) ||
839 (port
->p_id_len
!= ohardware
->h_rport
->p_id_len
) ||
840 (memcmp(port
->p_id
, ohardware
->h_rport
->p_id
,
841 port
->p_id_len
) != 0))
843 /* We got a match! */
844 hardware
= ohardware
; /* We switch hardware */
851 if (firstnull
!= NULL
)
852 hardware
= firstnull
;
853 else hardware
= older
;
858 (hardware
->h_mode
== LLDPD_MODE_ANY
)) {
863 for (i
=j
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
864 if (!cfg
->g_protocols
[i
].enabled
)
866 if (cfg
->g_protocols
[i
].mode
== guess
) {
867 mac
= hardware
->h_proto_macs
+ ETH_ALEN
*j
;
868 modename
= cfg
->g_protocols
[i
].name
;
869 filter
= cfg
->g_protocols
[i
].mode
;
874 if (cfg
->g_protocols
[i
].mode
== 0) {
875 LLOG_WARNX("should not be there");
879 if (hardware
->h_start_probe
== 0)
880 hardware
->h_start_probe
= time(NULL
) - 1;
881 /* Handle switching respecting probe time */
882 if ((memcmp(mac
, frame
+ ETH_ALEN
, ETH_ALEN
) == 0) &&
883 ((time(NULL
) - hardware
->h_start_probe
) > cfg
->g_probe_time
) &&
884 /* Don't switch to this protocol if not LLDP and LLDP is
885 * a valid candidate */
886 ((filter
== LLDPD_MODE_LLDP
) ||
887 (memcmp(hardware
->h_proto_macs
,
888 broadcastmac
, ETH_ALEN
) == 0) ||
889 (memcmp(hardware
->h_proto_macs
,
890 nullmac
, ETH_ALEN
) == 0))) {
891 LLOG_INFO("switching to %s on port %s", modename
,
893 hardware
->h_mode
= guess
;
894 lldpd_iface_switchto(cfg
, filter
, hardware
);
896 /* Wait twice probe time to be able to receive packets of all kind */
897 if ((time(NULL
) - hardware
->h_start_probe
) > cfg
->g_probe_time
* 2) {
898 LLOG_DEBUG("probe expired on %s, retry", hardware
->h_ifname
);
899 hardware
->h_start_probe
= 0;
900 memset(hardware
->h_proto_macs
, 0, ETH_ALEN
*(cfg
->g_multi
+1));
903 if (memcmp(mac
, broadcastmac
, ETH_ALEN
) == 0)
905 LLOG_INFO("received a %s frame on %s but wait for %d sec",
906 modename
, hardware
->h_ifname
, cfg
->g_probe_time
- time(NULL
) +
907 hardware
->h_start_probe
);
908 if (memcmp(mac
, frame
+ ETH_ALEN
, ETH_ALEN
) == 0)
910 if (memcmp(mac
, nullmac
, ETH_ALEN
) == 0) {
911 memcpy(mac
, frame
+ ETH_ALEN
, ETH_ALEN
);
914 LLOG_INFO("several MAC for %s on %s, discarding %s for this interface",
915 modename
, hardware
->h_ifname
, modename
);
916 memcpy(mac
, broadcastmac
, ETH_ALEN
);
922 if ((hardware
->h_rchassis
== NULL
) ||
923 (chassis
->c_id_subtype
!= hardware
->h_rchassis
->c_id_subtype
) ||
924 (chassis
->c_id_len
!= hardware
->h_rchassis
->c_id_len
) ||
925 (memcmp(chassis
->c_id
, hardware
->h_rchassis
->c_id
,
926 chassis
->c_id_len
) != 0))
929 /* We have our new frame */
930 lldpd_remote_cleanup(cfg
, hardware
, 0);
931 hardware
->h_rport
= port
;
932 hardware
->h_rchassis
= chassis
;
933 hardware
->h_rlastchange
= hardware
->h_rlastupdate
= time(NULL
);
935 /* We remember this frame */
936 free(hardware
->h_rlastframe
);
937 if ((hardware
->h_rlastframe
= (struct lldpd_frame
*)malloc(s
+
938 sizeof(int))) != NULL
) {
939 hardware
->h_rlastframe
->size
= s
;
940 memcpy(hardware
->h_rlastframe
->frame
, frame
, s
);
944 /* This is a new remote system */
945 LLOG_DEBUG("we discovered a new remote system on %s",
947 /* Do we already know this remote system? */
948 TAILQ_FOREACH(ohardware
, &cfg
->g_hardware
, h_entries
) {
949 if ((ohardware
->h_ifname
!= hardware
->h_ifname
) &&
950 (ohardware
->h_rchassis
!= NULL
) &&
951 (ohardware
->h_rchassis
->c_id_subtype
==
952 chassis
->c_id_subtype
) &&
953 (ohardware
->h_rchassis
->c_id_len
==
954 chassis
->c_id_len
) &&
955 (memcmp(ohardware
->h_rchassis
->c_id
,
956 chassis
->c_id
, chassis
->c_id_len
) == 0)) {
957 LLOG_DEBUG("but it was already on %s",
958 ohardware
->h_ifname
);
959 hardware
->h_rid
= ohardware
->h_rid
;
963 hardware
->h_rid
= ++cfg
->g_lastrid
;
968 lldpd_chassis_cleanup(chassis
);
969 lldpd_port_cleanup(port
);
974 lldpd_recv_all(struct lldpd
*cfg
)
976 struct lldpd_hardware
*hardware
;
977 struct lldpd_vif
*vif
;
978 struct lldpd_client
*client
, *client_next
;
981 struct sockaddr_ll from
;
986 struct timeval
*tvp
= &tv
;
988 int rc
, nfds
, n
, bond
;
992 tv
.tv_sec
= cfg
->g_delay
- (time(NULL
) - cfg
->g_lastsent
);
994 tv
.tv_sec
= LLDPD_TX_DELAY
;
995 if (tv
.tv_sec
>= cfg
->g_delay
)
996 tv
.tv_sec
= cfg
->g_delay
;
1002 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
1003 /* Ignore if interface is down */
1004 if ((hardware
->h_flags
& IFF_UP
) == 0)
1006 FD_SET(hardware
->h_raw
, &rfds
);
1007 if (nfds
< hardware
->h_raw
)
1008 nfds
= hardware
->h_raw
;
1009 /* Listen to real interface too. In 2.6.27, we can
1010 * receive packets if this is the slave interface. */
1011 if (hardware
->h_raw_real
> 0) {
1012 FD_SET(hardware
->h_raw_real
, &rfds
);
1013 if (nfds
< hardware
->h_raw_real
)
1014 nfds
= hardware
->h_raw_real
;
1017 TAILQ_FOREACH(vif
, &cfg
->g_vif
, vif_entries
) {
1018 if ((vif
->vif_flags
& IFF_UP
) == 0)
1020 FD_SET(vif
->vif_raw
, &rfds
);
1021 if (nfds
< vif
->vif_raw
)
1022 nfds
= vif
->vif_raw
;
1024 TAILQ_FOREACH(client
, &cfg
->g_clients
, next
) {
1025 FD_SET(client
->fd
, &rfds
);
1026 if (nfds
< client
->fd
)
1029 FD_SET(cfg
->g_ctl
, &rfds
);
1030 if (nfds
< cfg
->g_ctl
)
1035 snmp_select_info(&nfds
, &rfds
, tvp
, &fakeblock
);
1036 #endif /* USE_SNMP */
1038 sleep(cfg
->g_delay
);
1042 rc
= select(nfds
+ 1, &rfds
, NULL
, NULL
, &tv
);
1046 LLOG_WARN("failure on select");
1056 #endif /* USE_SNMP */
1057 TAILQ_FOREACH(vif
, &cfg
->g_vif
, vif_entries
) {
1058 if (!FD_ISSET(vif
->vif_raw
, &rfds
))
1060 if ((buffer
= (char *)malloc(
1061 vif
->vif_mtu
)) == NULL
) {
1062 LLOG_WARN("failed to alloc reception buffer");
1065 fromlen
= sizeof(from
);
1066 if ((n
= recvfrom(vif
->vif_raw
,
1069 (struct sockaddr
*)&from
,
1071 LLOG_WARN("error while receiving frame on vlan %s",
1073 vif
->vif_real
->h_rx_discarded_cnt
++;
1077 if (from
.sll_pkttype
== PACKET_OUTGOING
) {
1081 if (!((cfg
->g_multi
) &&
1082 (vif
->vif_real
->h_mode
!= LLDPD_MODE_ANY
) &&
1083 (lldpd_guess_type(cfg
, buffer
, n
) !=
1084 vif
->vif_real
->h_mode
))) {
1085 vif
->vif_real
->h_rx_cnt
++;
1086 lldpd_decode(cfg
, buffer
, n
, vif
->vif_real
, 0);
1091 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
1092 /* We could have received something on _real_
1093 * interface. However, even in this case, this could be
1094 * just an outgoing packet. We will try to handle both
1095 * cases, but maybe not in the same select. */
1096 onreal
= ((hardware
->h_raw_real
> 0) &&
1097 (FD_ISSET(hardware
->h_raw_real
, &rfds
)));
1098 if (onreal
|| (FD_ISSET(hardware
->h_raw
, &rfds
))) {
1099 if ((buffer
= (char *)malloc(
1100 hardware
->h_mtu
)) == NULL
) {
1101 LLOG_WARN("failed to alloc reception buffer");
1104 fromlen
= sizeof(from
);
1106 onreal
?hardware
->h_raw_real
:hardware
->h_raw
,
1109 (struct sockaddr
*)&from
,
1111 LLOG_WARN("error while receiving frame on %s",
1112 hardware
->h_ifname
);
1113 hardware
->h_rx_discarded_cnt
++;
1117 if (from
.sll_pkttype
== PACKET_OUTGOING
) {
1122 /* If received on real interface, we act like if
1123 * this is not a bond! */
1124 if (!onreal
&& (hardware
->h_raw_real
> 0)) {
1125 /* Bonding. Is it for the correct
1126 * physical interface ? */
1127 if (from
.sll_ifindex
== hardware
->h_master
) {
1128 /* It seems that we don't know from
1129 which physical interface it comes
1130 (kernel < 2.6.24 ?) */
1132 } else if (from
.sll_ifindex
!=
1133 if_nametoindex(hardware
->h_ifname
)) {
1138 hardware
->h_rx_cnt
++;
1139 lldpd_decode(cfg
, buffer
, n
, hardware
, bond
);
1144 if (FD_ISSET(cfg
->g_ctl
, &rfds
)) {
1145 if (ctl_accept(cfg
, cfg
->g_ctl
) == -1)
1146 LLOG_WARN("unable to accept new client");
1148 for (client
= TAILQ_FIRST(&cfg
->g_clients
);
1150 client
= client_next
) {
1151 client_next
= TAILQ_NEXT(client
, next
);
1152 if (FD_ISSET(client
->fd
, &rfds
)) {
1154 if ((buffer
= (char *)malloc(MAX_HMSGSIZE
)) ==
1156 LLOG_WARN("failed to alloc reception buffer");
1159 if ((n
= recv(client
->fd
, buffer
,
1160 MAX_HMSGSIZE
, 0)) == -1) {
1161 LLOG_WARN("error while receiving message");
1166 client_handle_client(cfg
, client
, buffer
, n
);
1168 ctl_close(cfg
, client
->fd
); /* Will use TAILQ_REMOVE ! */
1176 netsnmp_check_outstanding_agent_requests();
1178 #endif /* USE_SNMP */
1179 } while ((rc
!= 0) || (time(NULL
) - cfg
->g_lastsent
< cfg
->g_delay
));
1183 lldpd_send_all(struct lldpd
*cfg
)
1185 struct lldpd_hardware
*hardware
;
1186 u_int8_t saved_lladdr
[ETHER_ADDR_LEN
];
1189 cfg
->g_lastsent
= time(NULL
);
1190 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
1191 /* Ignore if interface is down */
1192 if ((hardware
->h_flags
& IFF_UP
) == 0)
1195 /* When sending on inactive slaves, just send using a 0:0:0:0:0:0 address */
1197 if ((hardware
->h_raw_real
> 0) &&
1198 (!iface_is_slave_active(cfg
, hardware
->h_master
,
1199 hardware
->h_ifname
))) {
1201 memcpy(saved_lladdr
, hardware
->h_lladdr
, ETHER_ADDR_LEN
);
1202 memset(hardware
->h_lladdr
, 0, ETHER_ADDR_LEN
);
1205 for (i
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
1206 if (!cfg
->g_protocols
[i
].enabled
)
1208 if ((hardware
->h_mode
== cfg
->g_protocols
[i
].mode
) ||
1209 (cfg
->g_protocols
[i
].mode
== LLDPD_MODE_LLDP
))
1210 cfg
->g_protocols
[i
].send(cfg
, &cfg
->g_lchassis
, hardware
);
1212 /* Restore MAC if needed */
1214 memcpy(hardware
->h_lladdr
, saved_lladdr
, ETHER_ADDR_LEN
);
1218 #ifdef ENABLE_LLDPMED
1220 lldpd_med(struct lldpd_chassis
*chassis
)
1222 free(chassis
->c_med_hw
);
1223 free(chassis
->c_med_fw
);
1224 free(chassis
->c_med_sn
);
1225 free(chassis
->c_med_manuf
);
1226 free(chassis
->c_med_model
);
1227 free(chassis
->c_med_asset
);
1228 chassis
->c_med_hw
= dmi_hw();
1229 chassis
->c_med_fw
= dmi_fw();
1230 chassis
->c_med_sn
= dmi_sn();
1231 chassis
->c_med_manuf
= dmi_manuf();
1232 chassis
->c_med_model
= dmi_model();
1233 chassis
->c_med_asset
= dmi_asset();
1238 lldpd_loop(struct lldpd
*cfg
)
1240 struct ifaddrs
*ifap
, *ifa
;
1241 struct sockaddr_ll
*sdl
;
1242 struct lldpd_hardware
*hardware
;
1243 struct lldpd_vif
*vif
;
1249 /* Set system name and description */
1250 if ((un
= (struct utsname
*)malloc(sizeof(struct utsname
))) == NULL
)
1253 fatal("failed to get system information");
1254 if ((hp
= priv_gethostbyname()) == NULL
)
1255 fatal("failed to get system name");
1256 free(cfg
->g_lchassis
.c_name
);
1257 free(cfg
->g_lchassis
.c_descr
);
1258 if ((cfg
->g_lchassis
.c_name
= strdup(hp
)) == NULL
)
1260 if (asprintf(&cfg
->g_lchassis
.c_descr
, "%s %s %s %s",
1261 un
->sysname
, un
->release
, un
->version
, un
->machine
) == -1)
1262 fatal("failed to set system description");
1264 /* Check forwarding */
1265 cfg
->g_lchassis
.c_cap_enabled
= 0;
1266 if ((f
= priv_open("/proc/sys/net/ipv4/ip_forward")) >= 0) {
1267 if ((read(f
, &status
, 1) == 1) && (status
== '1')) {
1268 cfg
->g_lchassis
.c_cap_enabled
= LLDP_CAP_ROUTER
;
1272 #ifdef ENABLE_LLDPMED
1273 if (cfg
->g_lchassis
.c_cap_available
& LLDP_CAP_TELEPHONE
)
1274 cfg
->g_lchassis
.c_cap_enabled
|= LLDP_CAP_TELEPHONE
;
1275 lldpd_med(&cfg
->g_lchassis
);
1276 free(cfg
->g_lchassis
.c_med_sw
);
1277 cfg
->g_lchassis
.c_med_sw
= strdup(un
->release
);
1281 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
)
1282 hardware
->h_flags
= 0;
1283 TAILQ_FOREACH(vif
, &cfg
->g_vif
, vif_entries
)
1286 if (getifaddrs(&ifap
) != 0)
1287 fatal("lldpd_loop: failed to get interface list");
1289 cfg
->g_lchassis
.c_mgmt
.s_addr
= INADDR_ANY
;
1290 for (ifa
= ifap
; ifa
!= NULL
; ifa
= ifa
->ifa_next
) {
1291 if (cfg
->g_lchassis
.c_mgmt
.s_addr
== INADDR_ANY
)
1292 /* Get management address, if available */
1293 if ((ifa
->ifa_addr
!= NULL
) &&
1294 (ifa
->ifa_addr
->sa_family
== AF_INET
)) {
1295 struct sockaddr_in
*sa
;
1296 sa
= (struct sockaddr_in
*)ifa
->ifa_addr
;
1297 if ((ntohl(*(u_int32_t
*)&sa
->sin_addr
) != INADDR_LOOPBACK
) &&
1298 (cfg
->g_mgmt_pattern
== NULL
)) {
1299 memcpy(&cfg
->g_lchassis
.c_mgmt
,
1301 sizeof(struct in_addr
));
1302 cfg
->g_lchassis
.c_mgmt_if
= if_nametoindex(ifa
->ifa_name
);
1304 else if (cfg
->g_mgmt_pattern
!= NULL
) {
1306 ip
= inet_ntoa(sa
->sin_addr
);
1307 if (fnmatch(cfg
->g_mgmt_pattern
,
1309 memcpy(&cfg
->g_lchassis
.c_mgmt
,
1311 sizeof(struct in_addr
));
1312 cfg
->g_lchassis
.c_mgmt_if
=
1313 if_nametoindex(ifa
->ifa_name
);
1318 if (ifa
->ifa_addr
== NULL
||
1319 ifa
->ifa_addr
->sa_family
!= PF_PACKET
)
1322 sdl
= (struct sockaddr_ll
*)ifa
->ifa_addr
;
1323 if (sdl
->sll_hatype
!= ARPHRD_ETHER
|| !sdl
->sll_halen
)
1326 if (iface_is_bridge(cfg
, ifa
->ifa_name
)) {
1327 cfg
->g_lchassis
.c_cap_enabled
|= LLDP_CAP_BRIDGE
;
1331 if ((iface_is_vlan(cfg
, ifa
->ifa_name
)) ||
1332 (iface_is_bond(cfg
, ifa
->ifa_name
)))
1335 if (!(ifa
->ifa_flags
& IFF_MULTICAST
))
1338 if (iface_is_wireless(cfg
, ifa
->ifa_name
))
1339 cfg
->g_lchassis
.c_cap_enabled
|= LLDP_CAP_WLAN
;
1341 if (lldpd_port_add(cfg
, ifa
) == NULL
)
1342 LLOG_WARNX("failed to allocate port %s, skip it",
1347 if (cfg
->g_listen_vlans
) {
1348 for (ifa
= ifap
; ifa
!= NULL
; ifa
= ifa
->ifa_next
) {
1349 if ((iface_is_vlan(cfg
, ifa
->ifa_name
)) &&
1350 (lldpd_port_add_vlan(cfg
, ifa
) == NULL
)) {
1351 LLOG_WARNX("unable to allocate vlan %s, skip it",
1361 lldpd_send_all(cfg
);
1362 lldpd_recv_all(cfg
);
1365 #ifdef ENABLE_LLDPMED
1367 lldpd_parse_location(struct lldpd_chassis
*chassis
, const char *location
)
1369 char *l
, *e
, *s
, *data
, *n
;
1370 double ll
, altitude
;
1371 u_int32_t intpart
, floatpart
;
1374 if ((l
= strdup(location
)) == NULL
)
1377 if ((e
= index(s
, ':')) == NULL
)
1378 goto invalid_location
;
1382 case LLDPMED_LOCFORMAT_COORD
:
1384 if ((chassis
->c_med_location
[0].data
=
1385 (char *)malloc(16)) == NULL
)
1387 chassis
->c_med_location
[0].data_len
= 16;
1388 chassis
->c_med_location
[0].format
= LLDPMED_LOCFORMAT_COORD
;
1389 data
= chassis
->c_med_location
[0].data
;
1391 /* Latitude and longitude */
1392 for (i
= 0; i
< 2; i
++) {
1394 if ((e
= index(s
, ':')) == NULL
)
1395 goto invalid_location
;
1399 if ((e
= index(s
, ':')) == NULL
)
1400 goto invalid_location
;
1403 floatpart
= (ll
- intpart
) * (1 << 25);
1404 if (((i
== 0) && (*s
== 'S')) ||
1405 ((i
== 1) && (*s
== 'W'))) {
1408 floatpart
= ~floatpart
;
1410 } else if (((i
== 0) && (*s
!= 'N')) ||
1411 ((i
== 1) && (*s
!= 'E')))
1412 goto invalid_location
;
1413 *(u_int8_t
*)data
= (6 << 2) | /* Precision */
1414 ((intpart
& 0x180) >> 7); /* Int part 2 bits */
1416 *(u_int8_t
*)data
= (((intpart
& 0x7f) << 1) | /* Int part 7 bits */
1417 ((floatpart
& 0x1000000) >> 24)); /* Float part 1 bit */
1419 *(u_int8_t
*)data
= (floatpart
& 0xff0000) >> 16; /* 8 bits */
1421 *(u_int8_t
*)data
= (floatpart
& 0xff00) >> 8; /* 8 bits */
1423 *(u_int8_t
*)data
= (floatpart
& 0xff); /* 8 bits */
1429 if ((e
= index(s
, ':')) == NULL
)
1430 goto invalid_location
;
1434 if ((e
= index(s
, ':')) == NULL
)
1435 goto invalid_location
;
1438 intpart
= -(int)altitude
;
1439 floatpart
= (-(altitude
+ intpart
)) * (1 << 8);
1440 intpart
= ~intpart
; intpart
+= 1;
1441 floatpart
= ~floatpart
; floatpart
+= 1;
1443 intpart
= (int)altitude
;
1444 floatpart
= (altitude
- intpart
) * (1 << 8);
1446 if ((*s
!= 'm') && (*s
!= 'f'))
1447 goto invalid_location
;
1448 *(u_int8_t
*)data
= ((((*s
== 'm')?1:2) << 4) | /* Type 4 bits */
1449 0); /* Precision 4 bits */
1451 *(u_int8_t
*)data
= ((6 << 6) | /* Precision 2 bits */
1452 ((intpart
& 0x3f0000) >> 16)); /* Int 6 bits */
1454 *(u_int8_t
*)data
= (intpart
& 0xff00) >> 8; /* Int 8 bits */
1456 *(u_int8_t
*)data
= intpart
& 0xff; /* Int 8 bits */
1458 *(u_int8_t
*)data
= floatpart
& 0xff; /* Float 8 bits */
1463 if (index(s
, ':') != NULL
)
1464 goto invalid_location
;
1465 *(u_int8_t
*)data
= atoi(s
);
1467 case LLDPMED_LOCFORMAT_CIVIC
:
1469 chassis
->c_med_location
[1].data_len
= 4;
1471 if ((s
= index(s
, ':')) == NULL
)
1472 goto invalid_location
;
1475 if ((s
= index(s
, ':')) == NULL
)
1478 /* s is the beginning of the word */
1479 if ((n
= index(s
, ':')) == NULL
)
1481 /* n is the end of the word */
1482 chassis
->c_med_location
[1].data_len
+= (n
- s
) + 2;
1483 if ((s
= index(s
, ':')) == NULL
)
1488 if ((chassis
->c_med_location
[1].data
=
1489 (char *)malloc(chassis
->c_med_location
[1].data_len
)) ==
1492 chassis
->c_med_location
[1].format
= LLDPMED_LOCFORMAT_CIVIC
;
1493 data
= chassis
->c_med_location
[1].data
;
1494 *(u_int8_t
*)data
= chassis
->c_med_location
[1].data_len
- 1;
1496 *(u_int8_t
*)data
= 2; /* Client location */
1498 if ((e
= index(s
, ':')) == NULL
)
1499 goto invalid_location
;
1501 goto invalid_location
;
1502 memcpy(data
, s
, 2); /* Country code */
1504 while (*e
!= '\0') {
1506 if ((e
= index(s
, ':')) == NULL
)
1507 goto invalid_location
;
1509 *(u_int8_t
*)data
= atoi(s
);
1512 if ((e
= index(s
, ':')) == NULL
)
1514 *(u_int8_t
*)data
= e
- s
;
1516 memcpy(data
, s
, e
-s
);
1520 case LLDPMED_LOCFORMAT_ELIN
:
1522 chassis
->c_med_location
[2].data_len
= strlen(s
);
1523 if ((chassis
->c_med_location
[2].data
=
1524 (char *)malloc(strlen(s
))) == NULL
)
1526 chassis
->c_med_location
[2].format
= LLDPMED_LOCFORMAT_ELIN
;
1527 strcpy(chassis
->c_med_location
[2].data
, s
);
1530 goto invalid_location
;
1533 chassis
->c_med_cap_enabled
|= LLDPMED_CAP_LOCATION
;
1536 LLOG_WARNX("the format of the location is invalid (%s)",
1539 free(chassis
->c_med_location
[type
-1].data
);
1540 memset(&chassis
->c_med_location
[type
-1], 0,
1541 sizeof(struct lldpd_med_loc
));
1548 lldpd_shutdown(int sig
)
1550 LLOG_INFO("signal received, exiting");
1554 /* For signal handling */
1555 struct lldpd
*gcfg
= NULL
;
1560 struct lldpd_hardware
*hardware
;
1561 struct lldpd_vif
*vif
;
1564 TAILQ_FOREACH(hardware
, &gcfg
->g_hardware
, h_entries
) {
1565 if (INTERFACE_OPENED(hardware
))
1566 lldpd_iface_close(gcfg
, hardware
);
1568 TAILQ_FOREACH(vif
, &gcfg
->g_vif
, vif_entries
) {
1569 if (vif
->vif_raw
!= -1)
1570 lldpd_iface_close(gcfg
, (struct lldpd_hardware
*)vif
);
1575 #endif /* USE_SNMP */
1579 main(int argc
, char *argv
[])
1587 char *popt
, opts
[] = "vdxm:p:M:iL:P:@ ";
1588 int probe
= 0, i
, found
, vlan
= 0;
1589 #ifdef ENABLE_LLDPMED
1590 int lldpmed
= 0, noinventory
= 0;
1596 * Get and parse command line options
1598 popt
= index(opts
, '@');
1599 for (i
=0; protos
[i
].mode
!= 0; i
++) {
1600 if (protos
[i
].enabled
== 1) continue;
1601 *(popt
++) = protos
[i
].arg
;
1604 while ((ch
= getopt(argc
, argv
, opts
)) != -1) {
1615 #ifdef ENABLE_LLDPMED
1617 lldpmed
= atoi(optarg
);
1618 if ((lldpmed
< 1) || (lldpmed
> 4)) {
1619 fprintf(stderr
, "-M requires an argument between 1 and 4\n");
1635 fprintf(stderr
, "LLDP-MED support is not built-in\n");
1640 probe
= atoi(optarg
);
1646 fprintf(stderr
, "SNMP support is not built-in\n");
1652 for (i
=0; protos
[i
].mode
!= 0; i
++) {
1653 if (protos
[i
].enabled
) continue;
1654 if (ch
== protos
[i
].arg
) {
1655 protos
[i
].enabled
= 1;
1669 if (daemon(0, 0) != 0)
1670 fatal("failed to detach daemon");
1671 if ((pid
= open(LLDPD_PID_FILE
,
1672 O_TRUNC
| O_CREAT
| O_WRONLY
, 0644)) == -1)
1673 fatal("unable to open pid file " LLDPD_PID_FILE
);
1674 if (asprintf(&spid
, "%d\n", getpid()) == -1)
1675 fatal("unable to create pid file " LLDPD_PID_FILE
);
1676 if (write(pid
, spid
, strlen(spid
)) == -1)
1677 fatal("unable to write pid file " LLDPD_PID_FILE
);
1682 priv_init(PRIVSEP_CHROOT
);
1684 if (probe
== 0) probe
= LLDPD_TTL
;
1686 if ((cfg
= (struct lldpd
*)
1687 calloc(1, sizeof(struct lldpd
))) == NULL
)
1690 cfg
->g_mgmt_pattern
= mgmtp
;
1691 cfg
->g_listen_vlans
= vlan
;
1693 /* Get ioctl socket */
1694 if ((cfg
->g_sock
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1)
1695 fatal("failed to get ioctl socket");
1696 cfg
->g_delay
= LLDPD_TX_DELAY
;
1698 /* Set system capabilities */
1699 cfg
->g_lchassis
.c_cap_available
= LLDP_CAP_BRIDGE
| LLDP_CAP_WLAN
|
1701 #ifdef ENABLE_LLDPMED
1703 if (lldpmed
== LLDPMED_CLASS_III
)
1704 cfg
->g_lchassis
.c_cap_available
|= LLDP_CAP_TELEPHONE
;
1705 cfg
->g_lchassis
.c_med_type
= lldpmed
;
1706 cfg
->g_lchassis
.c_med_cap_available
= LLDPMED_CAP_CAP
|
1707 LLDPMED_CAP_IV
| LLDPMED_CAP_LOCATION
;
1708 cfg
->g_lchassis
.c_med_cap_enabled
= LLDPMED_CAP_CAP
;
1710 cfg
->g_lchassis
.c_med_cap_enabled
|= LLDPMED_CAP_IV
;
1712 while ((ch
= getopt(argc
, argv
, opts
)) != -1) {
1715 lldpd_parse_location(&cfg
->g_lchassis
, optarg
);
1725 cfg
->g_lchassis
.c_ttl
= LLDPD_TTL
;
1727 cfg
->g_protocols
= protos
;
1728 cfg
->g_probe_time
= probe
;
1729 for (i
=0; protos
[i
].mode
!= 0; i
++)
1730 if (protos
[i
].enabled
) {
1732 LLOG_INFO("protocol %s enabled", protos
[i
].name
);
1734 LLOG_INFO("protocol %s disabled", protos
[i
].name
);
1737 TAILQ_INIT(&cfg
->g_hardware
);
1738 TAILQ_INIT(&cfg
->g_vif
);
1743 agent_init(cfg
, debug
);
1745 #endif /* USE_SNMP */
1748 if ((cfg
->g_ctl
= priv_ctl_create(cfg
)) == -1)
1749 fatalx("unable to create control socket " LLDPD_CTL_SOCKET
);
1750 TAILQ_INIT(&cfg
->g_clients
);
1753 if (atexit(lldpd_exit
) != 0) {
1756 fatal("unable to set exit function");
1759 /* Signal handling */
1760 signal(SIGHUP
, lldpd_shutdown
);
1761 signal(SIGINT
, lldpd_shutdown
);
1762 signal(SIGTERM
, lldpd_shutdown
);