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>
35 #include <netpacket/packet.h>
37 #include <net/if_arp.h>
38 #include <linux/filter.h>
39 #include <linux/if_vlan.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
};
68 /* "ether dst 01:e0:52:cc:cc:cc" */
69 #define LLDPD_FILTER_FDP_F \
70 { 0x20, 0, 0, 0x00000002 }, \
71 { 0x15, 0, 3, 0x52cccccc }, \
72 { 0x28, 0, 0, 0x00000000 }, \
73 { 0x15, 0, 1, 0x000001e0 }, \
74 { 0x6, 0, 0, 0x0000ffff }, \
75 { 0x6, 0, 0, 0x00000000 },
76 struct sock_filter lldpd_filter_fdp_f
[] = { LLDPD_FILTER_FDP_F
};
77 /* "ether dst 01:00:0c:cc:cc:cc" */
78 #define LLDPD_FILTER_CDP_F \
79 { 0x20, 0, 0, 0x00000002 }, \
80 { 0x15, 0, 3, 0x0ccccccc }, \
81 { 0x28, 0, 0, 0x00000000 }, \
82 { 0x15, 0, 1, 0x00000100 }, \
83 { 0x6, 0, 0, 0x0000ffff }, \
84 { 0x6, 0, 0, 0x00000000 },
85 struct sock_filter lldpd_filter_cdp_f
[] = { LLDPD_FILTER_CDP_F
};
86 /* "ether dst 01:00:81:00:01:00" */
87 #define LLDPD_FILTER_SONMP_F \
88 { 0x20, 0, 0, 0x00000002 }, \
89 { 0x15, 0, 3, 0x81000100 }, \
90 { 0x28, 0, 0, 0x00000000 }, \
91 { 0x15, 0, 1, 0x00000100 }, \
92 { 0x6, 0, 0, 0x0000ffff }, \
93 { 0x6, 0, 0, 0x00000000 },
94 struct sock_filter lldpd_filter_sonmp_f
[] = { LLDPD_FILTER_SONMP_F
};
95 /* "ether dst 00:e0:2b:00:00:00" */
96 #define LLDPD_FILTER_EDP_F \
97 { 0x20, 0, 0, 0x00000002 }, \
98 { 0x15, 0, 3, 0x2b000000 }, \
99 { 0x28, 0, 0, 0x00000000 }, \
100 { 0x15, 0, 1, 0x000000e0 }, \
101 { 0x6, 0, 0, 0x0000ffff }, \
102 { 0x6, 0, 0, 0x00000000 },
103 struct sock_filter lldpd_filter_edp_f
[] = { LLDPD_FILTER_EDP_F
};
104 #define LLDPD_FILTER_ANY_F \
105 { 0x28, 0, 0, 0x0000000c }, \
106 { 0x15, 0, 4, 0x000088cc }, \
107 { 0x20, 0, 0, 0x00000002 }, \
108 { 0x15, 0, 2, 0xc200000e }, \
109 { 0x28, 0, 0, 0x00000000 }, \
110 { 0x15, 11, 12, 0x00000180 }, \
111 { 0x20, 0, 0, 0x00000002 }, \
112 { 0x15, 0, 2, 0x2b000000 }, \
113 { 0x28, 0, 0, 0x00000000 }, \
114 { 0x15, 7, 8, 0x000000e0 }, \
115 { 0x15, 1, 0, 0x0ccccccc }, \
116 { 0x15, 0, 2, 0x81000100 }, \
117 { 0x28, 0, 0, 0x00000000 }, \
118 { 0x15, 3, 4, 0x00000100 }, \
119 { 0x15, 0, 3, 0x52cccccc }, \
120 { 0x28, 0, 0, 0x00000000 }, \
121 { 0x15, 0, 1, 0x000001e0 }, \
122 { 0x6, 0, 0, 0x0000ffff }, \
123 { 0x6, 0, 0, 0x00000000 },
124 struct sock_filter lldpd_filter_any_f
[] = { LLDPD_FILTER_ANY_F
};
126 struct protocol protos
[] =
128 { LLDPD_MODE_LLDP
, 1, "LLDP", ' ', lldp_send
, lldp_decode
, NULL
,
129 LLDP_MULTICAST_ADDR
, lldpd_filter_lldp_f
, sizeof(lldpd_filter_lldp_f
) },
130 { LLDPD_MODE_CDPV1
, 0, "CDPv1", 'c', cdpv1_send
, cdp_decode
, cdpv1_guess
,
131 CDP_MULTICAST_ADDR
, lldpd_filter_cdp_f
, sizeof(lldpd_filter_cdp_f
) },
132 { LLDPD_MODE_CDPV2
, 0, "CDPv2", 'c', cdpv2_send
, cdp_decode
, cdpv2_guess
,
133 CDP_MULTICAST_ADDR
, lldpd_filter_cdp_f
, sizeof(lldpd_filter_cdp_f
) },
134 { LLDPD_MODE_SONMP
, 0, "SONMP", 's', sonmp_send
, sonmp_decode
, NULL
,
135 SONMP_MULTICAST_ADDR
, lldpd_filter_sonmp_f
, sizeof(lldpd_filter_sonmp_f
) },
136 { LLDPD_MODE_EDP
, 0, "EDP", 'e', edp_send
, edp_decode
, NULL
,
137 EDP_MULTICAST_ADDR
, lldpd_filter_edp_f
, sizeof(lldpd_filter_edp_f
) },
138 { LLDPD_MODE_FDP
, 0, "FDP", 'f', fdp_send
, cdp_decode
, NULL
,
139 FDP_MULTICAST_ADDR
, lldpd_filter_fdp_f
, sizeof(lldpd_filter_fdp_f
) },
140 { 0, 0, "any", ' ', NULL
, NULL
, NULL
,
141 {0,0,0,0,0,0}, lldpd_filter_any_f
, sizeof(lldpd_filter_any_f
) }
144 int lldpd_iface_switchto(struct lldpd
*, short int,
145 struct lldpd_hardware
*);
146 struct lldpd_hardware
*lldpd_port_add(struct lldpd
*, struct ifaddrs
*);
147 void lldpd_loop(struct lldpd
*);
148 void lldpd_shutdown(int);
150 void lldpd_send_all(struct lldpd
*);
151 void lldpd_recv_all(struct lldpd
*);
152 int lldpd_guess_type(struct lldpd
*, char *, int);
153 void lldpd_decode(struct lldpd
*, char *, int,
154 struct lldpd_hardware
*, int);
161 extern const char *__progname
;
163 fprintf(stderr
, "usage: %s [-dvcse] [-p|-P] [-m ip]\n", __progname
);
165 fprintf(stderr
, "usage: %s [-dvcsex] [-p|-P] [-m ip]\n", __progname
);
166 #endif /* USE_SNMP */
171 lldpd_iface_init_mtu(struct lldpd
*global
, struct lldpd_hardware
*hardware
)
176 memset(&ifr
, 0, sizeof(ifr
));
177 strlcpy(ifr
.ifr_name
, hardware
->h_ifname
, sizeof(ifr
.ifr_name
));
178 if (ioctl(global
->g_sock
, SIOCGIFMTU
, (char*)&ifr
) == -1) {
179 LLOG_WARN("unable to get MTU of %s, using 1500", hardware
->h_ifname
);
180 hardware
->h_mtu
= 1500;
182 hardware
->h_mtu
= ifr
.ifr_mtu
;
186 lldpd_iface_init_vlan(struct lldpd
*global
, struct lldpd_vif
*vif
)
191 lldpd_iface_init_mtu(global
, (struct lldpd_hardware
*)vif
);
192 status
= priv_iface_init((struct lldpd_hardware
*)vif
, -1);
197 filter
= LLDPD_MODE_ANY
;
199 filter
= LLDPD_MODE_LLDP
;
201 if (lldpd_iface_switchto(global
, filter
,
202 (struct lldpd_hardware
*)vif
) == -1) {
203 LLOG_WARNX("unable to apply filter");
207 lldpd_iface_multicast(global
, vif
->vif_ifname
, 0);
209 LLOG_DEBUG("vlan interface %s initialized (fd=%d)", vif
->vif_ifname
,
215 lldpd_iface_init(struct lldpd
*global
, struct lldpd_hardware
*hardware
)
217 int master
; /* Bond device */
218 char if_bond
[IFNAMSIZ
];
222 lldpd_iface_init_mtu(global
, hardware
);
223 status
= priv_iface_init(hardware
, -1);
227 if ((master
= iface_is_enslaved(global
, hardware
->h_ifname
)) != -1) {
228 /* With bonding device, we need to listen on the bond ! */
229 if (if_indextoname(master
, if_bond
) == NULL
) {
230 LLOG_WARN("unable to get index for interface %d (master of %s)",
231 master
, hardware
->h_ifname
);
234 hardware
->h_raw_real
= hardware
->h_raw
;
235 hardware
->h_master
= master
;
236 hardware
->h_raw
= -1;
237 status
= priv_iface_init(hardware
, master
);
239 close(hardware
->h_raw_real
);
240 if (hardware
->h_raw
!= -1)
241 close(hardware
->h_raw
);
247 filter
= LLDPD_MODE_ANY
;
249 filter
= LLDPD_MODE_LLDP
;
250 if (lldpd_iface_switchto(global
, filter
, hardware
) == -1) {
251 LLOG_WARNX("unable to apply filter");
256 lldpd_iface_multicast(global
, if_bond
, 0);
257 lldpd_iface_multicast(global
, hardware
->h_ifname
, 0);
259 LLOG_DEBUG("interface %s initialized (fd=%d)", hardware
->h_ifname
,
265 lldpd_iface_multicast(struct lldpd
*global
, const char *name
, int remove
)
269 for (i
=0; global
->g_protocols
[i
].mode
!= 0; i
++) {
270 if (!global
->g_protocols
[i
].enabled
) continue;
271 if ((rc
= priv_iface_multicast(name
,
272 global
->g_protocols
[i
].mac
, !remove
)) != 0) {
275 LLOG_INFO("unable to %s %s address to multicast filter for %s",
276 (remove
)?"delete":"add",
277 global
->g_protocols
[i
].name
,
284 lldpd_iface_close(struct lldpd
*global
, struct lldpd_hardware
*hardware
)
286 char listen
[IFNAMSIZ
];
288 close(hardware
->h_raw
);
289 hardware
->h_raw
= -1;
291 if (hardware
->h_raw_real
> 0) {
292 if (if_indextoname(hardware
->h_master
, listen
) == NULL
) {
293 LLOG_WARN("unable to get index for interface %d",
295 strlcpy(listen
, hardware
->h_ifname
, sizeof(listen
));
297 close(hardware
->h_raw_real
);
298 lldpd_iface_multicast(global
, listen
, 1);
300 strlcpy(listen
, hardware
->h_ifname
, sizeof(listen
));
301 lldpd_iface_multicast(global
, listen
, 1);
303 hardware
->h_raw_real
= -1;
308 lldpd_iface_switchto(struct lldpd
*cfg
, short int filter
, struct lldpd_hardware
*hardware
)
310 struct sock_fprog prog
;
313 memset(&prog
, 0, sizeof(prog
));
314 for (i
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
315 if (!cfg
->g_protocols
[i
].enabled
) continue;
316 if (cfg
->g_protocols
[i
].mode
== filter
)
319 prog
.filter
= cfg
->g_protocols
[i
].filter
;
320 prog
.len
= cfg
->g_protocols
[i
].filterlen
/ sizeof(struct sock_filter
);
321 if (setsockopt(hardware
->h_raw
, SOL_SOCKET
, SO_ATTACH_FILTER
,
322 &prog
, sizeof(prog
)) < 0) {
323 LLOG_WARN("unable to change filter for %s", hardware
->h_ifname
);
326 if ((hardware
->h_raw_real
> 0) &&
327 (setsockopt(hardware
->h_raw_real
, SOL_SOCKET
, SO_ATTACH_FILTER
,
328 &prog
, sizeof(prog
)) < 0)) {
329 LLOG_WARN("unable to change filter for real device %s", hardware
->h_ifname
);
337 lldpd_vlan_cleanup(struct lldpd_port
*port
)
339 struct lldpd_vlan
*vlan
, *vlan_next
;
340 for (vlan
= TAILQ_FIRST(&port
->p_vlans
);
344 vlan_next
= TAILQ_NEXT(vlan
, v_entries
);
345 TAILQ_REMOVE(&port
->p_vlans
, vlan
, v_entries
);
351 lldpd_port_cleanup(struct lldpd_port
*port
)
353 lldpd_vlan_cleanup(port
);
360 lldpd_chassis_cleanup(struct lldpd_chassis
*chassis
)
363 free(chassis
->c_name
);
364 free(chassis
->c_descr
);
369 lldpd_remote_cleanup(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
, int reset
)
371 if (hardware
->h_rport
!= NULL
) {
372 lldpd_port_cleanup(hardware
->h_rport
);
373 hardware
->h_rport
= NULL
;
375 if (hardware
->h_rchassis
!= NULL
) {
376 lldpd_chassis_cleanup(hardware
->h_rchassis
);
377 hardware
->h_rchassis
= NULL
;
379 hardware
->h_rlastchange
= hardware
->h_rlastupdate
= 0;
380 free(hardware
->h_rlastframe
);
381 hardware
->h_rlastframe
= NULL
;
382 if (reset
&& cfg
->g_multi
) {
383 hardware
->h_mode
= LLDPD_MODE_ANY
;
384 memset(hardware
->h_proto_macs
, 0, ETH_ALEN
*(cfg
->g_multi
+1));
385 hardware
->h_start_probe
= 0;
386 lldpd_iface_switchto(cfg
, LLDPD_MODE_ANY
, hardware
);
391 lldpd_cleanup(struct lldpd
*cfg
)
393 struct lldpd_hardware
*hardware
, *hardware_next
;
394 struct lldpd_vif
*vif
, *vif_next
;
396 for (hardware
= TAILQ_FIRST(&cfg
->g_hardware
); hardware
!= NULL
;
397 hardware
= hardware_next
) {
398 hardware_next
= TAILQ_NEXT(hardware
, h_entries
);
399 if (hardware
->h_flags
== 0) {
400 TAILQ_REMOVE(&cfg
->g_hardware
, hardware
, h_entries
);
401 lldpd_iface_close(cfg
, hardware
);
402 lldpd_vlan_cleanup(&hardware
->h_lport
);
403 lldpd_remote_cleanup(cfg
, hardware
, 1);
404 free(hardware
->h_proto_macs
);
405 free(hardware
->h_llastframe
);
407 } else if (hardware
->h_rchassis
!= NULL
) {
408 if (time(NULL
) - hardware
->h_rlastupdate
>
409 hardware
->h_rchassis
->c_ttl
) {
410 lldpd_remote_cleanup(cfg
, hardware
, 1);
411 hardware
->h_rx_ageout_cnt
++;
415 for (vif
= TAILQ_FIRST(&cfg
->g_vif
); vif
!= NULL
;
417 vif_next
= TAILQ_NEXT(vif
, vif_entries
);
418 if (vif
->vif_flags
== 0) {
419 TAILQ_REMOVE(&cfg
->g_vif
, vif
, vif_entries
);
420 lldpd_iface_close(cfg
, (struct lldpd_hardware
*)vif
);
427 lldpd_port_add_vlan(struct lldpd
*cfg
, struct ifaddrs
*ifa
)
429 struct lldpd_vif
*vif
;
430 struct lldpd_hardware
*hardware
;
431 struct vlan_ioctl_args ifv
;
433 TAILQ_FOREACH(vif
, &cfg
->g_vif
, vif_entries
) {
434 if (strcmp(vif
->vif_ifname
, ifa
->ifa_name
) == 0)
439 if ((vif
= (struct lldpd_vif
*)
440 calloc(1, sizeof(struct lldpd_vif
))) == NULL
)
443 vif
->vif_raw_real
= -1;
445 strlcpy(vif
->vif_ifname
, ifa
->ifa_name
, sizeof(vif
->vif_ifname
));
446 vif
->vif_flags
= ifa
->ifa_flags
;
448 if (vif
->vif_raw
== -1) {
450 if (lldpd_iface_init_vlan(cfg
, vif
) != 0) {
455 /* Find the real interface */
456 vif
->vif_real
= NULL
;
457 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
458 memset(&ifv
, 0, sizeof(ifv
));
459 ifv
.cmd
= GET_VLAN_REALDEV_NAME_CMD
;
460 strlcpy(ifv
.device1
, ifa
->ifa_name
, sizeof(ifv
.device1
));
461 if ((ioctl(cfg
->g_sock
, SIOCGIFVLAN
, &ifv
) >= 0) &&
462 (strncmp(hardware
->h_ifname
,
464 sizeof(ifv
.u
.device2
)) == 0))
465 vif
->vif_real
= hardware
;
467 if (vif
->vif_real
== NULL
) {
468 LLOG_WARNX("unable to find real interface for %s",
474 TAILQ_INSERT_TAIL(&cfg
->g_vif
, vif
, vif_entries
);
480 struct lldpd_hardware
*
481 lldpd_port_add(struct lldpd
*cfg
, struct ifaddrs
*ifa
)
483 struct ifaddrs
*oifap
, *oifa
;
484 struct lldpd_hardware
*hardware
;
485 struct lldpd_port
*port
;
486 struct lldpd_vlan
*vlan
;
487 struct vlan_ioctl_args ifv
;
488 struct ethtool_cmd ethc
;
491 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
492 if (strcmp(hardware
->h_ifname
, ifa
->ifa_name
) == 0)
496 if (hardware
== NULL
) {
497 if ((hardware
= (struct lldpd_hardware
*)
498 calloc(1, sizeof(struct lldpd_hardware
))) == NULL
)
500 hardware
->h_raw
= -1;
501 hardware
->h_raw_real
= -1;
502 hardware
->h_start_probe
= 0;
503 hardware
->h_proto_macs
= (u_int8_t
*)calloc(cfg
->g_multi
+1, ETH_ALEN
);
504 TAILQ_INIT(&hardware
->h_lport
.p_vlans
);
506 lldpd_vlan_cleanup(&hardware
->h_lport
);
509 port
= &hardware
->h_lport
;
510 hardware
->h_flags
= ifa
->ifa_flags
;
512 strlcpy(hardware
->h_ifname
, ifa
->ifa_name
, sizeof(hardware
->h_ifname
));
513 lladdr
= (u_int8_t
*)(((struct sockaddr_ll
*)ifa
->ifa_addr
)->sll_addr
);
514 memcpy(&hardware
->h_lladdr
, lladdr
, sizeof(hardware
->h_lladdr
));
515 port
->p_id_subtype
= LLDP_PORTID_SUBTYPE_LLADDR
;
516 port
->p_id
= (char*)hardware
->h_lladdr
;
517 port
->p_id_len
= sizeof(hardware
->h_lladdr
);
518 port
->p_descr
= hardware
->h_ifname
;
520 if (cfg
->g_lchassis
.c_id
== NULL
) {
521 /* Use the first port's l2 addr as the chassis ID */
522 if ((cfg
->g_lchassis
.c_id
= malloc(sizeof(hardware
->h_lladdr
))) == NULL
)
524 cfg
->g_lchassis
.c_id_subtype
= LLDP_CHASSISID_SUBTYPE_LLADDR
;
525 cfg
->g_lchassis
.c_id_len
= sizeof(hardware
->h_lladdr
);
526 memcpy(cfg
->g_lchassis
.c_id
,
527 hardware
->h_lladdr
, sizeof(hardware
->h_lladdr
));
530 /* Get VLANS and aggregation status */
531 if (getifaddrs(&oifap
) != 0)
532 fatal("lldpd_port_add: failed to get interface list");
533 for (oifa
= oifap
; oifa
!= NULL
; oifa
= oifa
->ifa_next
) {
534 /* Check if we already have checked this one */
536 TAILQ_FOREACH(vlan
, &port
->p_vlans
, v_entries
) {
537 if (strcmp(vlan
->v_name
, oifa
->ifa_name
) == 0)
542 /* Aggregation check */
543 if (iface_is_bond_slave(cfg
, hardware
->h_ifname
, oifa
->ifa_name
))
544 port
->p_aggregid
= if_nametoindex(oifa
->ifa_name
);
547 memset(&ifv
, 0, sizeof(ifv
));
548 ifv
.cmd
= GET_VLAN_REALDEV_NAME_CMD
;
549 strlcpy(ifv
.device1
, oifa
->ifa_name
, sizeof(ifv
.device1
));
550 if ((ioctl(cfg
->g_sock
, SIOCGIFVLAN
, &ifv
) >= 0) &&
551 ((iface_is_bond_slave(cfg
, hardware
->h_ifname
, ifv
.u
.device2
)) ||
552 (strncmp(hardware
->h_ifname
, ifv
.u
.device2
, sizeof(ifv
.u
.device2
)) == 0))) {
553 if ((vlan
= (struct lldpd_vlan
*)
554 calloc(1, sizeof(struct lldpd_vlan
))) == NULL
)
556 if ((vlan
->v_name
= strdup(oifa
->ifa_name
)) == NULL
) {
560 memset(&ifv
, 0, sizeof(ifv
));
561 ifv
.cmd
= GET_VLAN_VID_CMD
;
562 strlcpy(ifv
.device1
, oifa
->ifa_name
, sizeof(ifv
.device1
));
563 if (ioctl(cfg
->g_sock
, SIOCGIFVLAN
, &ifv
) < 0) {
564 /* Dunno what happened */
568 vlan
->v_vid
= ifv
.u
.VID
;
569 TAILQ_INSERT_TAIL(&port
->p_vlans
, vlan
, v_entries
);
576 if (priv_ethtool(hardware
->h_ifname
, ðc
) == 0) {
578 int advertised_ethtool_to_rfc3636
[][2] = {
579 {ADVERTISED_10baseT_Half
, LLDP_DOT3_LINK_AUTONEG_10BASE_T
},
580 {ADVERTISED_10baseT_Full
, LLDP_DOT3_LINK_AUTONEG_10BASET_FD
},
581 {ADVERTISED_100baseT_Half
, LLDP_DOT3_LINK_AUTONEG_100BASE_TX
},
582 {ADVERTISED_100baseT_Full
, LLDP_DOT3_LINK_AUTONEG_100BASE_TXFD
},
583 {ADVERTISED_1000baseT_Half
, LLDP_DOT3_LINK_AUTONEG_1000BASE_T
},
584 {ADVERTISED_1000baseT_Full
, LLDP_DOT3_LINK_AUTONEG_1000BASE_TFD
},
585 {ADVERTISED_10000baseT_Full
, LLDP_DOT3_LINK_AUTONEG_OTHER
},
586 {ADVERTISED_Pause
, LLDP_DOT3_LINK_AUTONEG_FDX_PAUSE
},
587 {ADVERTISED_Asym_Pause
, LLDP_DOT3_LINK_AUTONEG_FDX_APAUSE
},
588 {ADVERTISED_2500baseX_Full
, LLDP_DOT3_LINK_AUTONEG_OTHER
},
591 port
->p_autoneg_support
= (ethc
.supported
& SUPPORTED_Autoneg
) ? 1 : 0;
592 port
->p_autoneg_enabled
= (ethc
.autoneg
== AUTONEG_DISABLE
) ? 0 : 1;
593 for (j
=0; advertised_ethtool_to_rfc3636
[j
][0]; j
++) {
594 if (ethc
.advertising
& advertised_ethtool_to_rfc3636
[j
][0])
595 port
->p_autoneg_advertised
|= advertised_ethtool_to_rfc3636
[j
][1];
597 switch (ethc
.speed
) {
599 port
->p_mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
600 LLDP_DOT3_MAU_10BASETFD
: LLDP_DOT3_MAU_10BASETHD
;
601 if (ethc
.port
== PORT_BNC
) port
->p_mau_type
= LLDP_DOT3_MAU_10BASE2
;
602 if (ethc
.port
== PORT_FIBRE
)
603 port
->p_mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
604 LLDP_DOT3_MAU_10BASEFLDF
: LLDP_DOT3_MAU_10BASEFLHD
;
607 port
->p_mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
608 LLDP_DOT3_MAU_100BASETXFD
: LLDP_DOT3_MAU_100BASETXHD
;
609 if (ethc
.port
== PORT_BNC
)
610 port
->p_mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
611 LLDP_DOT3_MAU_100BASET2DF
: LLDP_DOT3_MAU_100BASET2HD
;
612 if (ethc
.port
== PORT_FIBRE
)
613 port
->p_mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
614 LLDP_DOT3_MAU_100BASEFXFD
: LLDP_DOT3_MAU_100BASEFXHD
;
617 port
->p_mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
618 LLDP_DOT3_MAU_1000BASETFD
: LLDP_DOT3_MAU_1000BASETHD
;
619 if (ethc
.port
== PORT_FIBRE
)
620 port
->p_mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
621 LLDP_DOT3_MAU_1000BASEXFD
: LLDP_DOT3_MAU_1000BASEXHD
;
624 port
->p_mau_type
= (ethc
.port
== PORT_FIBRE
) ? \
625 LLDP_DOT3_MAU_10GIGBASEX
: LLDP_DOT3_MAU_10GIGBASER
;
628 if (ethc
.port
== PORT_AUI
) port
->p_mau_type
= LLDP_DOT3_MAU_AUI
;
630 LLOG_DEBUG("unable to get eth info for %s", hardware
->h_ifname
);
632 if (!INTERFACE_OPENED(hardware
)) {
634 if (lldpd_iface_init(cfg
, hardware
) != 0) {
635 LLOG_WARN("unable to initialize %s", hardware
->h_ifname
);
636 lldpd_vlan_cleanup(&hardware
->h_lport
);
637 free(hardware
->h_proto_macs
);
642 TAILQ_INSERT_TAIL(&cfg
->g_hardware
, hardware
, h_entries
);
649 lldpd_guess_type(struct lldpd
*cfg
, char *frame
, int s
)
654 for (i
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
655 if (!cfg
->g_protocols
[i
].enabled
)
657 if (cfg
->g_protocols
[i
].guess
== NULL
) {
658 if (memcmp(frame
, cfg
->g_protocols
[i
].mac
, ETH_ALEN
) == 0)
659 return cfg
->g_protocols
[i
].mode
;
661 if (cfg
->g_protocols
[i
].guess(frame
, s
))
662 return cfg
->g_protocols
[i
].mode
;
669 lldpd_decode(struct lldpd
*cfg
, char *frame
, int s
,
670 struct lldpd_hardware
*hardware
, int bond
)
672 int result
= 0, i
, j
, candidatetonull
;
673 u_int8_t nullmac
[ETH_ALEN
] = {0,0,0,0,0,0};
674 u_int8_t broadcastmac
[ETH_ALEN
] = {0xff,0xff,0xff,0xff,0xff,0xff};
675 struct lldpd_chassis
*chassis
;
676 struct lldpd_port
*port
;
677 struct lldpd_hardware
*ohardware
, *firstnull
= NULL
, *older
= NULL
;
678 int guess
= LLDPD_MODE_LLDP
;
680 /* Discard VLAN frames */
681 if ((s
>= sizeof(struct ieee8023
)) &&
682 (((struct ieee8023
*)frame
)->size
== htons(ETHERTYPE_VLAN
)))
685 if ((hardware
->h_rlastframe
!= NULL
) &&
686 (hardware
->h_rlastframe
->size
== s
) &&
687 (memcmp(hardware
->h_rlastframe
->frame
, frame
, s
) == 0)) {
688 /* Already received the same frame */
689 hardware
->h_rlastupdate
= time(NULL
);
694 if (hardware
->h_mode
== LLDPD_MODE_ANY
)
695 guess
= lldpd_guess_type(cfg
, frame
, s
);
697 guess
= hardware
->h_mode
;
698 for (i
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
699 if (!cfg
->g_protocols
[i
].enabled
)
701 if (cfg
->g_protocols
[i
].mode
== guess
) {
702 if ((result
= cfg
->g_protocols
[i
].decode(cfg
, frame
,
703 s
, hardware
, &chassis
, &port
)) == -1)
708 if (cfg
->g_protocols
[i
].mode
== 0) {
709 LLOG_INFO("unable to guess frame type");
712 } else if (cfg
->g_protocols
[0].decode(cfg
, frame
, s
, hardware
,
713 &chassis
, &port
) == -1)
714 /* Nothing has been received */
718 /* Eh, wait ! The frame we just received was for a bonding
719 * device. We need to attach it to a real device. What is the
720 * best candidate? Drum rolling... */
721 TAILQ_FOREACH(ohardware
, &cfg
->g_hardware
, h_entries
) {
722 if (ohardware
->h_master
== hardware
->h_master
) {
724 if (ohardware
->h_rchassis
== NULL
) {
727 (ohardware
->h_mode
== LLDPD_MODE_ANY
)) {
729 cfg
->g_protocols
[i
].mode
!= 0;
731 if (!cfg
->g_protocols
[i
].enabled
)
733 if ((cfg
->g_protocols
[i
].mode
== guess
) &&
734 (memcmp(frame
+ ETH_ALEN
,
735 ohardware
->h_proto_macs
+ ETH_ALEN
*j
,
737 hardware
= ohardware
;
744 if (firstnull
!= NULL
) {
746 cfg
->g_protocols
[i
].mode
!= 0;
748 if (!cfg
->g_protocols
[i
].enabled
)
750 if ((cfg
->g_protocols
[i
].mode
== guess
) &&
752 ohardware
->h_proto_macs
+
765 /* Ok, this is the first candidate if we
766 * don't find a matching chassis/port */
767 if (candidatetonull
) firstnull
= ohardware
;
770 if ((older
== NULL
) ||
771 (older
->h_rlastupdate
> ohardware
->h_rlastupdate
))
772 /* If there is no matching chassis/port
773 * and no free hardware, we will use
776 if ((chassis
->c_id_subtype
!=
777 ohardware
->h_rchassis
->c_id_subtype
) ||
778 (chassis
->c_id_len
!= ohardware
->h_rchassis
->c_id_len
) ||
779 (memcmp(chassis
->c_id
, ohardware
->h_rchassis
->c_id
,
780 chassis
->c_id_len
) != 0) ||
781 (port
->p_id_subtype
!= ohardware
->h_rport
->p_id_subtype
) ||
782 (port
->p_id_len
!= ohardware
->h_rport
->p_id_len
) ||
783 (memcmp(port
->p_id
, ohardware
->h_rport
->p_id
,
784 port
->p_id_len
) != 0))
786 /* We got a match! */
787 hardware
= ohardware
; /* We switch hardware */
794 if (firstnull
!= NULL
)
795 hardware
= firstnull
;
796 else hardware
= older
;
801 (hardware
->h_mode
== LLDPD_MODE_ANY
)) {
806 for (i
=j
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
807 if (!cfg
->g_protocols
[i
].enabled
)
809 if (cfg
->g_protocols
[i
].mode
== guess
) {
810 mac
= hardware
->h_proto_macs
+ ETH_ALEN
*j
;
811 modename
= cfg
->g_protocols
[i
].name
;
812 filter
= cfg
->g_protocols
[i
].mode
;
817 if (cfg
->g_protocols
[i
].mode
== 0) {
818 LLOG_WARNX("should not be there");
822 if (hardware
->h_start_probe
== 0)
823 hardware
->h_start_probe
= time(NULL
) - 1;
824 /* Handle switching respecting probe time */
825 if ((memcmp(mac
, frame
+ ETH_ALEN
, ETH_ALEN
) == 0) &&
826 ((time(NULL
) - hardware
->h_start_probe
) > cfg
->g_probe_time
) &&
827 /* Don't switch to this protocol if not LLDP and LLDP is
828 * a valid candidate */
829 ((filter
== LLDPD_MODE_LLDP
) ||
830 (memcmp(hardware
->h_proto_macs
,
831 broadcastmac
, ETH_ALEN
) == 0) ||
832 (memcmp(hardware
->h_proto_macs
,
833 nullmac
, ETH_ALEN
) == 0))) {
834 LLOG_INFO("switching to %s on port %s", modename
,
836 hardware
->h_mode
= guess
;
837 lldpd_iface_switchto(cfg
, filter
, hardware
);
839 /* Wait twice probe time to be able to receive packets of all kind */
840 if ((time(NULL
) - hardware
->h_start_probe
) > cfg
->g_probe_time
* 2) {
841 LLOG_DEBUG("probe expired on %s, retry", hardware
->h_ifname
);
842 hardware
->h_start_probe
= 0;
843 memset(hardware
->h_proto_macs
, 0, ETH_ALEN
*(cfg
->g_multi
+1));
846 if (memcmp(mac
, broadcastmac
, ETH_ALEN
) == 0)
848 LLOG_INFO("received a %s frame on %s but wait for %d sec",
849 modename
, hardware
->h_ifname
, cfg
->g_probe_time
- time(NULL
) +
850 hardware
->h_start_probe
);
851 if (memcmp(mac
, frame
+ ETH_ALEN
, ETH_ALEN
) == 0)
853 if (memcmp(mac
, nullmac
, ETH_ALEN
) == 0) {
854 memcpy(mac
, frame
+ ETH_ALEN
, ETH_ALEN
);
857 LLOG_INFO("several MAC for %s on %s, discarding %s for this interface",
858 modename
, hardware
->h_ifname
, modename
);
859 memcpy(mac
, broadcastmac
, ETH_ALEN
);
865 if ((hardware
->h_rchassis
== NULL
) ||
866 (chassis
->c_id_subtype
!= hardware
->h_rchassis
->c_id_subtype
) ||
867 (chassis
->c_id_len
!= hardware
->h_rchassis
->c_id_len
) ||
868 (memcmp(chassis
->c_id
, hardware
->h_rchassis
->c_id
,
869 chassis
->c_id_len
) != 0))
872 /* We have our new frame */
873 lldpd_remote_cleanup(cfg
, hardware
, 0);
874 hardware
->h_rport
= port
;
875 hardware
->h_rchassis
= chassis
;
876 hardware
->h_rlastchange
= hardware
->h_rlastupdate
= time(NULL
);
878 /* We remember this frame */
879 free(hardware
->h_rlastframe
);
880 if ((hardware
->h_rlastframe
= (struct lldpd_frame
*)malloc(s
+
881 sizeof(int))) != NULL
) {
882 hardware
->h_rlastframe
->size
= s
;
883 memcpy(hardware
->h_rlastframe
->frame
, frame
, s
);
887 /* This is a new remote system */
888 LLOG_DEBUG("we discovered a new remote system on %s",
890 /* Do we already know this remote system? */
891 TAILQ_FOREACH(ohardware
, &cfg
->g_hardware
, h_entries
) {
892 if ((ohardware
->h_ifname
!= hardware
->h_ifname
) &&
893 (ohardware
->h_rchassis
!= NULL
) &&
894 (ohardware
->h_rchassis
->c_id_subtype
==
895 chassis
->c_id_subtype
) &&
896 (ohardware
->h_rchassis
->c_id_len
==
897 chassis
->c_id_len
) &&
898 (memcmp(ohardware
->h_rchassis
->c_id
,
899 chassis
->c_id
, chassis
->c_id_len
) == 0)) {
900 LLOG_DEBUG("but it was already on %s",
901 ohardware
->h_ifname
);
902 hardware
->h_rid
= ohardware
->h_rid
;
906 hardware
->h_rid
= ++cfg
->g_lastrid
;
911 lldpd_chassis_cleanup(chassis
);
912 lldpd_port_cleanup(port
);
917 lldpd_recv_all(struct lldpd
*cfg
)
919 struct lldpd_hardware
*hardware
;
920 struct lldpd_vif
*vif
;
921 struct lldpd_client
*client
, *client_next
;
924 struct sockaddr_ll from
;
929 struct timeval
*tvp
= &tv
;
931 int rc
, nfds
, n
, bond
;
935 tv
.tv_sec
= cfg
->g_delay
- (time(NULL
) - cfg
->g_lastsent
);
937 tv
.tv_sec
= LLDPD_TX_DELAY
;
938 if (tv
.tv_sec
>= cfg
->g_delay
)
939 tv
.tv_sec
= cfg
->g_delay
;
945 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
946 /* Ignore if interface is down */
947 if ((hardware
->h_flags
& IFF_UP
) == 0)
949 FD_SET(hardware
->h_raw
, &rfds
);
950 if (nfds
< hardware
->h_raw
)
951 nfds
= hardware
->h_raw
;
952 /* Listen to real interface too. In 2.6.27, we can
953 * receive packets if this is the slave interface. */
954 if (hardware
->h_raw_real
> 0) {
955 FD_SET(hardware
->h_raw_real
, &rfds
);
956 if (nfds
< hardware
->h_raw_real
)
957 nfds
= hardware
->h_raw_real
;
960 TAILQ_FOREACH(vif
, &cfg
->g_vif
, vif_entries
) {
961 if ((vif
->vif_flags
& IFF_UP
) == 0)
963 FD_SET(vif
->vif_raw
, &rfds
);
964 if (nfds
< vif
->vif_raw
)
967 TAILQ_FOREACH(client
, &cfg
->g_clients
, next
) {
968 FD_SET(client
->fd
, &rfds
);
969 if (nfds
< client
->fd
)
972 FD_SET(cfg
->g_ctl
, &rfds
);
973 if (nfds
< cfg
->g_ctl
)
978 snmp_select_info(&nfds
, &rfds
, tvp
, &fakeblock
);
979 #endif /* USE_SNMP */
985 rc
= select(nfds
+ 1, &rfds
, NULL
, NULL
, &tv
);
989 LLOG_WARN("failure on select");
999 #endif /* USE_SNMP */
1000 TAILQ_FOREACH(vif
, &cfg
->g_vif
, vif_entries
) {
1001 if (!FD_ISSET(vif
->vif_raw
, &rfds
))
1003 if ((buffer
= (char *)malloc(
1004 vif
->vif_mtu
)) == NULL
) {
1005 LLOG_WARN("failed to alloc reception buffer");
1008 fromlen
= sizeof(from
);
1009 if ((n
= recvfrom(vif
->vif_raw
,
1012 (struct sockaddr
*)&from
,
1014 LLOG_WARN("error while receiving frame on vlan %s",
1016 vif
->vif_real
->h_rx_discarded_cnt
++;
1020 if (from
.sll_pkttype
== PACKET_OUTGOING
) {
1024 if (!((cfg
->g_multi
) &&
1025 (vif
->vif_real
->h_mode
!= LLDPD_MODE_ANY
) &&
1026 (lldpd_guess_type(cfg
, buffer
, n
) !=
1027 vif
->vif_real
->h_mode
))) {
1028 vif
->vif_real
->h_rx_cnt
++;
1029 lldpd_decode(cfg
, buffer
, n
, vif
->vif_real
, 0);
1034 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
1035 /* We could have received something on _real_
1036 * interface. However, even in this case, this could be
1037 * just an outgoing packet. We will try to handle both
1038 * cases, but maybe not in the same select. */
1039 onreal
= ((hardware
->h_raw_real
> 0) &&
1040 (FD_ISSET(hardware
->h_raw_real
, &rfds
)));
1041 if (onreal
|| (FD_ISSET(hardware
->h_raw
, &rfds
))) {
1042 if ((buffer
= (char *)malloc(
1043 hardware
->h_mtu
)) == NULL
) {
1044 LLOG_WARN("failed to alloc reception buffer");
1047 fromlen
= sizeof(from
);
1049 onreal
?hardware
->h_raw_real
:hardware
->h_raw
,
1052 (struct sockaddr
*)&from
,
1054 LLOG_WARN("error while receiving frame on %s",
1055 hardware
->h_ifname
);
1056 hardware
->h_rx_discarded_cnt
++;
1060 if (from
.sll_pkttype
== PACKET_OUTGOING
) {
1065 /* If received on real interface, we act like if
1066 * this is not a bond! */
1067 if (!onreal
&& (hardware
->h_raw_real
> 0)) {
1068 /* Bonding. Is it for the correct
1069 * physical interface ? */
1070 if (from
.sll_ifindex
== hardware
->h_master
) {
1071 /* It seems that we don't know from
1072 which physical interface it comes
1073 (kernel < 2.6.24 ?) */
1075 } else if (from
.sll_ifindex
!=
1076 if_nametoindex(hardware
->h_ifname
)) {
1081 hardware
->h_rx_cnt
++;
1082 lldpd_decode(cfg
, buffer
, n
, hardware
, bond
);
1087 if (FD_ISSET(cfg
->g_ctl
, &rfds
)) {
1088 if (ctl_accept(cfg
, cfg
->g_ctl
) == -1)
1089 LLOG_WARN("unable to accept new client");
1091 for (client
= TAILQ_FIRST(&cfg
->g_clients
);
1093 client
= client_next
) {
1094 client_next
= TAILQ_NEXT(client
, next
);
1095 if (FD_ISSET(client
->fd
, &rfds
)) {
1097 if ((buffer
= (char *)malloc(MAX_HMSGSIZE
)) ==
1099 LLOG_WARN("failed to alloc reception buffer");
1102 if ((n
= recv(client
->fd
, buffer
,
1103 MAX_HMSGSIZE
, 0)) == -1) {
1104 LLOG_WARN("error while receiving message");
1109 client_handle_client(cfg
, client
, buffer
, n
);
1111 ctl_close(cfg
, client
->fd
); /* Will use TAILQ_REMOVE ! */
1119 netsnmp_check_outstanding_agent_requests();
1121 #endif /* USE_SNMP */
1122 } while ((rc
!= 0) || (time(NULL
) - cfg
->g_lastsent
< cfg
->g_delay
));
1126 lldpd_send_all(struct lldpd
*cfg
)
1128 struct lldpd_hardware
*hardware
;
1130 cfg
->g_lastsent
= time(NULL
);
1131 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
1132 /* Ignore if interface is down */
1133 if ((hardware
->h_flags
& IFF_UP
) == 0)
1136 for (i
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
1137 if (!cfg
->g_protocols
[i
].enabled
)
1139 if ((hardware
->h_mode
== cfg
->g_protocols
[i
].mode
) ||
1140 (cfg
->g_protocols
[i
].mode
== LLDPD_MODE_LLDP
))
1141 cfg
->g_protocols
[i
].send(cfg
, &cfg
->g_lchassis
, hardware
);
1147 lldpd_loop(struct lldpd
*cfg
)
1149 struct ifaddrs
*ifap
, *ifa
;
1150 struct sockaddr_ll
*sdl
;
1151 struct lldpd_hardware
*hardware
;
1152 struct lldpd_vif
*vif
;
1158 /* Set system name and description */
1159 if ((un
= (struct utsname
*)malloc(sizeof(struct utsname
))) == NULL
)
1162 fatal("failed to get system information");
1163 if ((hp
= priv_gethostbyname()) == NULL
)
1164 fatal("failed to get system name");
1165 free(cfg
->g_lchassis
.c_name
);
1166 free(cfg
->g_lchassis
.c_descr
);
1167 if ((cfg
->g_lchassis
.c_name
= strdup(hp
)) == NULL
)
1169 if (asprintf(&cfg
->g_lchassis
.c_descr
, "%s %s %s %s",
1170 un
->sysname
, un
->release
, un
->version
, un
->machine
) == -1)
1171 fatal("failed to set system description");
1174 /* Check forwarding */
1175 cfg
->g_lchassis
.c_cap_enabled
= 0;
1176 if ((f
= priv_open("/proc/sys/net/ipv4/ip_forward")) >= 0) {
1177 if ((read(f
, &status
, 1) == 1) && (status
== '1')) {
1178 cfg
->g_lchassis
.c_cap_enabled
= LLDP_CAP_ROUTER
;
1183 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
)
1184 hardware
->h_flags
= 0;
1185 TAILQ_FOREACH(vif
, &cfg
->g_vif
, vif_entries
)
1188 if (getifaddrs(&ifap
) != 0)
1189 fatal("lldpd_loop: failed to get interface list");
1191 cfg
->g_lchassis
.c_mgmt
.s_addr
= INADDR_ANY
;
1192 for (ifa
= ifap
; ifa
!= NULL
; ifa
= ifa
->ifa_next
) {
1193 if (cfg
->g_lchassis
.c_mgmt
.s_addr
== INADDR_ANY
)
1194 /* Get management address, if available */
1195 if ((ifa
->ifa_addr
!= NULL
) &&
1196 (ifa
->ifa_addr
->sa_family
== AF_INET
)) {
1197 struct sockaddr_in
*sa
;
1198 sa
= (struct sockaddr_in
*)ifa
->ifa_addr
;
1199 if ((ntohl(*(u_int32_t
*)&sa
->sin_addr
) != INADDR_LOOPBACK
) &&
1200 (cfg
->g_mgmt_pattern
== NULL
)) {
1201 memcpy(&cfg
->g_lchassis
.c_mgmt
,
1203 sizeof(struct in_addr
));
1204 cfg
->g_lchassis
.c_mgmt_if
= if_nametoindex(ifa
->ifa_name
);
1206 else if (cfg
->g_mgmt_pattern
!= NULL
) {
1208 ip
= inet_ntoa(sa
->sin_addr
);
1209 if (fnmatch(cfg
->g_mgmt_pattern
,
1211 memcpy(&cfg
->g_lchassis
.c_mgmt
,
1213 sizeof(struct in_addr
));
1214 cfg
->g_lchassis
.c_mgmt_if
=
1215 if_nametoindex(ifa
->ifa_name
);
1220 if (ifa
->ifa_addr
== NULL
||
1221 ifa
->ifa_addr
->sa_family
!= PF_PACKET
)
1224 sdl
= (struct sockaddr_ll
*)ifa
->ifa_addr
;
1225 if (sdl
->sll_hatype
!= ARPHRD_ETHER
|| !sdl
->sll_halen
)
1228 if (iface_is_bridge(cfg
, ifa
->ifa_name
)) {
1229 cfg
->g_lchassis
.c_cap_enabled
|= LLDP_CAP_BRIDGE
;
1233 if ((iface_is_vlan(cfg
, ifa
->ifa_name
)) ||
1234 (iface_is_bond(cfg
, ifa
->ifa_name
)))
1237 if (!(ifa
->ifa_flags
& IFF_MULTICAST
))
1240 if (iface_is_wireless(cfg
, ifa
->ifa_name
))
1241 cfg
->g_lchassis
.c_cap_enabled
|= LLDP_CAP_WLAN
;
1243 if (lldpd_port_add(cfg
, ifa
) == NULL
)
1244 LLOG_WARNX("failed to allocate port %s, skip it",
1249 if (cfg
->g_listen_vlans
) {
1250 for (ifa
= ifap
; ifa
!= NULL
; ifa
= ifa
->ifa_next
) {
1251 if ((iface_is_vlan(cfg
, ifa
->ifa_name
)) &&
1252 (lldpd_port_add_vlan(cfg
, ifa
) == NULL
)) {
1253 LLOG_WARNX("unable to allocate vlan %s, skip it",
1263 lldpd_send_all(cfg
);
1264 lldpd_recv_all(cfg
);
1268 lldpd_shutdown(int sig
)
1270 LLOG_INFO("signal received, exiting");
1274 /* For signal handling */
1275 struct lldpd
*gcfg
= NULL
;
1280 struct lldpd_hardware
*hardware
;
1281 struct lldpd_vif
*vif
;
1284 TAILQ_FOREACH(hardware
, &gcfg
->g_hardware
, h_entries
) {
1285 if (INTERFACE_OPENED(hardware
))
1286 lldpd_iface_close(gcfg
, hardware
);
1288 TAILQ_FOREACH(vif
, &gcfg
->g_vif
, vif_entries
) {
1289 if (vif
->vif_raw
!= -1)
1290 lldpd_iface_close(gcfg
, (struct lldpd_hardware
*)vif
);
1295 #endif /* USE_SNMP */
1299 main(int argc
, char *argv
[])
1302 int ch
, snmp
= 0, debug
= 0;
1304 char *popt
, opts
[] = "vdxm:p:@ ";
1305 int probe
= 0, i
, found
, vlan
= 0;
1310 * Get and parse command line options
1312 popt
= index(opts
, '@');
1313 for (i
=0; protos
[i
].mode
!= 0; i
++) {
1314 if (protos
[i
].enabled
== 1) continue;
1315 *(popt
++) = protos
[i
].arg
;
1318 while ((ch
= getopt(argc
, argv
, opts
)) != -1) {
1330 probe
= atoi(optarg
);
1337 for (i
=0; protos
[i
].mode
!= 0; i
++) {
1338 if (protos
[i
].enabled
) continue;
1339 if (ch
== protos
[i
].arg
) {
1340 protos
[i
].enabled
= 1;
1354 if (daemon(0, 0) != 0)
1355 fatal("failed to detach daemon");
1356 if ((pid
= open(LLDPD_PID_FILE
,
1357 O_TRUNC
| O_CREAT
| O_WRONLY
)) == -1)
1358 fatal("unable to open pid file " LLDPD_PID_FILE
);
1359 if (asprintf(&spid
, "%d\n", getpid()) == -1)
1360 fatal("unable to create pid file " LLDPD_PID_FILE
);
1361 if (write(pid
, spid
, strlen(spid
)) == -1)
1362 fatal("unable to write pid file " LLDPD_PID_FILE
);
1367 priv_init(PRIVSEP_CHROOT
);
1369 if (probe
== 0) probe
= LLDPD_TTL
;
1371 if ((cfg
= (struct lldpd
*)
1372 calloc(1, sizeof(struct lldpd
))) == NULL
)
1375 cfg
->g_mgmt_pattern
= mgmtp
;
1376 cfg
->g_listen_vlans
= vlan
;
1378 /* Get ioctl socket */
1379 if ((cfg
->g_sock
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1)
1380 fatal("failed to get ioctl socket");
1381 cfg
->g_delay
= LLDPD_TX_DELAY
;
1383 /* Set system capabilities */
1384 cfg
->g_lchassis
.c_cap_available
= LLDP_CAP_BRIDGE
| LLDP_CAP_WLAN
|
1388 cfg
->g_lchassis
.c_ttl
= LLDPD_TTL
;
1390 cfg
->g_protocols
= protos
;
1391 cfg
->g_probe_time
= probe
;
1392 for (i
=0; protos
[i
].mode
!= 0; i
++)
1393 if (protos
[i
].enabled
) {
1395 LLOG_INFO("protocol %s enabled", protos
[i
].name
);
1397 LLOG_INFO("protocol %s disabled", protos
[i
].name
);
1400 TAILQ_INIT(&cfg
->g_hardware
);
1401 TAILQ_INIT(&cfg
->g_vif
);
1406 agent_init(cfg
, debug
);
1408 #endif /* USE_SNMP */
1411 if ((cfg
->g_ctl
= priv_ctl_create(cfg
)) == -1)
1412 fatalx("unable to create control socket " LLDPD_CTL_SOCKET
);
1413 TAILQ_INIT(&cfg
->g_clients
);
1416 if (atexit(lldpd_exit
) != 0) {
1419 fatal("unable to set exit function");
1422 /* Signal handling */
1423 signal(SIGHUP
, lldpd_shutdown
);
1424 signal(SIGINT
, lldpd_shutdown
);
1425 signal(SIGTERM
, lldpd_shutdown
);