]> git.ipfire.org Git - thirdparty/lldpd.git/blame - src/lldpd.c
Sometimes, CDP are transmitted over administration VLAN. We try to
[thirdparty/lldpd.git] / src / lldpd.c
CommitLineData
43c02e7b
VB
1/*
2 * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
3 *
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.
7 *
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.
15 */
16
17#include "lldpd.h"
18
19#include <stdio.h>
20#include <unistd.h>
21#include <errno.h>
22#include <signal.h>
23#include <sys/stat.h>
24#include <fcntl.h>
25#include <fnmatch.h>
26#include <time.h>
27#include <netdb.h>
28#include <sys/utsname.h>
29#include <sys/types.h>
30#include <sys/socket.h>
31#include <sys/select.h>
32#include <sys/time.h>
33#include <sys/ioctl.h>
34#include <arpa/inet.h>
35#include <netpacket/packet.h>
36#include <ifaddrs.h>
37#include <net/if_arp.h>
38#include <linux/filter.h>
39#include <linux/if_vlan.h>
40#include <linux/sockios.h>
41#include <linux/ethtool.h>
42
43#ifdef USE_SNMP
44#include <net-snmp/net-snmp-config.h>
45#include <net-snmp/net-snmp-includes.h>
46#include <net-snmp/agent/net-snmp-agent-includes.h>
47#include <net-snmp/agent/snmp_vars.h>
48#endif /* USE_SNMP */
49
50void usage(void);
51
52int lldpd_iface_init(struct lldpd *, struct lldpd_hardware *);
53int lldpd_iface_close(struct lldpd *, struct lldpd_hardware *);
54void lldpd_iface_multicast(struct lldpd *, const char *, int);
55
56/* "ether proto 0x88cc and ether dst 01:80:c2:00:00:0e" */
57#define LLDPD_FILTER_LLDP_F \
58 { 0x28, 0, 0, 0x0000000c }, \
59 { 0x15, 0, 5, 0x000088cc }, \
60 { 0x20, 0, 0, 0x00000002 }, \
61 { 0x15, 0, 3, 0xc200000e }, \
62 { 0x28, 0, 0, 0x00000000 }, \
63 { 0x15, 0, 1, 0x00000180 }, \
64 { 0x6, 0, 0, 0x0000ffff }, \
65 { 0x6, 0, 0, 0x00000000 },
66struct sock_filter lldpd_filter_lldp_f[] = { LLDPD_FILTER_LLDP_F };
dc1539a4 67/* "(ether dst 01:00:0c:cc:cc:cc) or (vlan and ether dst 01:00:0c:cc:cc:cc)" */
43c02e7b 68#define LLDPD_FILTER_CDP_F \
dc1539a4
VB
69 { 0x20, 0, 0, 0x00000002 }, \
70 { 0x15, 0, 2, 0x0ccccccc }, \
71 { 0x28, 0, 0, 0x00000000 }, \
72 { 0x15, 6, 0, 0x00000100 }, \
73 { 0x28, 0, 0, 0x0000000c }, \
74 { 0x15, 0, 5, 0x00008100 }, \
75 { 0x20, 0, 0, 0x00000002 }, \
76 { 0x15, 0, 3, 0x0ccccccc }, \
77 { 0x28, 0, 0, 0x00000000 }, \
78 { 0x15, 0, 1, 0x00000100 }, \
79 { 0x6, 0, 0, 0x0000ffff }, \
80 { 0x6, 0, 0, 0x00000000 },
43c02e7b
VB
81struct sock_filter lldpd_filter_cdp_f[] = { LLDPD_FILTER_CDP_F };
82/* "ether dst 01:00:81:00:01:00" */
83#define LLDPD_FILTER_SONMP_F \
84 { 0x20, 0, 0, 0x00000002 }, \
85 { 0x15, 0, 3, 0x81000100 }, \
86 { 0x28, 0, 0, 0x00000000 }, \
87 { 0x15, 0, 1, 0x00000100 }, \
88 { 0x6, 0, 0, 0x0000ffff }, \
89 { 0x6, 0, 0, 0x00000000 },
90struct sock_filter lldpd_filter_sonmp_f[] = { LLDPD_FILTER_SONMP_F };
91/* "ether dst 00:e0:2b:00:00:00" */
92#define LLDPD_FILTER_EDP_F \
93 { 0x20, 0, 0, 0x00000002 }, \
94 { 0x15, 0, 3, 0x2b000000 }, \
95 { 0x28, 0, 0, 0x00000000 }, \
96 { 0x15, 0, 1, 0x000000e0 }, \
97 { 0x6, 0, 0, 0x0000ffff }, \
98 { 0x6, 0, 0, 0x00000000 },
99struct sock_filter lldpd_filter_edp_f[] = { LLDPD_FILTER_EDP_F };
100#define LLDPD_FILTER_ANY_F \
101 { 0x28, 0, 0, 0x0000000c }, \
102 { 0x15, 0, 4, 0x000088cc }, \
103 { 0x20, 0, 0, 0x00000002 }, \
104 { 0x15, 0, 2, 0xc200000e }, \
105 { 0x28, 0, 0, 0x00000000 }, \
106 { 0x15, 8, 9, 0x00000180 }, \
107 { 0x20, 0, 0, 0x00000002 }, \
108 { 0x15, 0, 2, 0x2b000000 }, \
109 { 0x28, 0, 0, 0x00000000 }, \
110 { 0x15, 4, 5, 0x000000e0 }, \
111 { 0x15, 1, 0, 0x0ccccccc }, \
112 { 0x15, 0, 3, 0x81000100 }, \
113 { 0x28, 0, 0, 0x00000000 }, \
114 { 0x15, 0, 1, 0x00000100 }, \
115 { 0x6, 0, 0, 0x0000ffff }, \
116 { 0x6, 0, 0, 0x00000000 },
117struct sock_filter lldpd_filter_any_f[] = { LLDPD_FILTER_ANY_F };
118
119struct protocol protos[] =
120{
121 { LLDPD_MODE_LLDP, 1, "LLDP", ' ', lldp_send, lldp_decode, NULL,
122 LLDP_MULTICAST_ADDR, lldpd_filter_lldp_f, sizeof(lldpd_filter_lldp_f) },
123 { LLDPD_MODE_CDPV1, 0, "CDPv1", 'c', cdpv1_send, cdp_decode, cdpv1_guess,
124 CDP_MULTICAST_ADDR, lldpd_filter_cdp_f, sizeof(lldpd_filter_cdp_f) },
125 { LLDPD_MODE_CDPV2, 0, "CDPv2", 'c', cdpv2_send, cdp_decode, cdpv2_guess,
126 CDP_MULTICAST_ADDR, lldpd_filter_cdp_f, sizeof(lldpd_filter_cdp_f) },
127 { LLDPD_MODE_SONMP, 0, "SONMP", 's', sonmp_send, sonmp_decode, NULL,
128 SONMP_MULTICAST_ADDR, lldpd_filter_sonmp_f, sizeof(lldpd_filter_sonmp_f) },
129 { LLDPD_MODE_EDP, 0, "EDP", 'e', edp_send, edp_decode, NULL,
130 EDP_MULTICAST_ADDR, lldpd_filter_edp_f, sizeof(lldpd_filter_edp_f) },
131 { 0, 0, "any", ' ', NULL, NULL, NULL,
132 {0,0,0,0,0,0}, lldpd_filter_any_f, sizeof(lldpd_filter_any_f) }
133};
134
135int lldpd_iface_switchto(struct lldpd *, short int,
136 struct lldpd_hardware *);
137struct lldpd_hardware *lldpd_port_add(struct lldpd *, struct ifaddrs *);
138void lldpd_loop(struct lldpd *);
139void lldpd_hangup(int);
140void lldpd_shutdown(int);
141void lldpd_exit();
142void lldpd_send_all(struct lldpd *);
143void lldpd_recv_all(struct lldpd *);
144int lldpd_guess_type(struct lldpd *, char *, int);
145void lldpd_decode(struct lldpd *, char *, int,
146 struct lldpd_hardware *, int);
147void lldpd_handle_client(struct lldpd *, struct lldpd_client *,
148 char *, int);
149
150void lldpd_handle_none(struct lldpd *, struct hmsg *,
151 struct hmsg *);
152void lldpd_handle_get_interfaces(struct lldpd *, struct hmsg *,
153 struct hmsg *);
154void lldpd_handle_get_port_related(struct lldpd *, struct hmsg *,
155 struct hmsg *);
156void lldpd_handle_shutdown(struct lldpd *, struct hmsg *,
157 struct hmsg *);
158
159struct client_handle {
160 enum hmsg_type type;
161 void (*handle)(struct lldpd*, struct hmsg*, struct hmsg*);
162};
163
164struct client_handle client_handles[] = {
165 { HMSG_NONE, lldpd_handle_none },
166 { HMSG_GET_INTERFACES, lldpd_handle_get_interfaces },
167 { HMSG_GET_CHASSIS, lldpd_handle_get_port_related },
168 { HMSG_GET_PORT, lldpd_handle_get_port_related },
169 { HMSG_GET_VLANS, lldpd_handle_get_port_related },
170 { HMSG_SHUTDOWN, lldpd_handle_shutdown },
171 { 0, NULL } };
172
173char **saved_argv;
174
175void
176usage(void)
177{
178 extern const char *__progname;
179#ifndef USE_SNMP
180 fprintf(stderr, "usage: %s [-d] [-c] [-s] [-e] [-p|-P] [-m ip]\n", __progname);
181#else /* USE_SNMP */
182 fprintf(stderr, "usage: %s [-d] [-c] [-s] [-e] [-p|-P] [-m ip] [-x]\n", __progname);
183#endif /* USE_SNMP */
184 exit(1);
185}
186
187int
188lldpd_iface_init(struct lldpd *global, struct lldpd_hardware *hardware)
189{
190 struct sockaddr_ll sa;
191 struct ifreq ifr;
192 int master; /* Bond device */
193 char if_bond[IFNAMSIZ];
194 int un = 1;
195 short int filter;
196
197 /* get MTU */
198 memset(&ifr, 0, sizeof(ifr));
199 strlcpy(ifr.ifr_name, hardware->h_ifname, sizeof(ifr.ifr_name));
200 if (ioctl(global->g_sock, SIOCGIFMTU, (char*)&ifr) == -1) {
201 LLOG_WARN("unable to get MTU of %s, using 1500", hardware->h_ifname);
202 hardware->h_mtu = 1500;
203 } else
204 hardware->h_mtu = ifr.ifr_mtu;
205
206 /* Open listening socket to receive/send frames */
207 if ((hardware->h_raw = socket(PF_PACKET, SOCK_RAW,
208 htons(ETH_P_ALL))) < 0)
209 return errno;
210 memset(&sa, 0, sizeof(sa));
211 sa.sll_family = AF_PACKET;
212 sa.sll_protocol = 0;
213 sa.sll_ifindex = if_nametoindex(hardware->h_ifname);
214 if (bind(hardware->h_raw, (struct sockaddr*)&sa, sizeof(sa)) < 0)
215 return errno;
216
217 if ((master = iface_is_enslaved(global, hardware->h_ifname)) != -1) {
218 /* With bonding device, we need to listen on the bond ! */
219 if (if_indextoname(master, if_bond) == NULL) {
220 LLOG_WARN("unable to get index for interface %d (master of %s)",
221 master, hardware->h_ifname);
222 return ENETDOWN;
223 }
224 hardware->h_raw_real = hardware->h_raw;
225 hardware->h_master = master;
226 hardware->h_raw = -1;
227 if ((hardware->h_raw = socket(PF_PACKET, SOCK_RAW,
228 htons(ETH_P_ALL))) < 0)
229 return errno;
230 memset(&sa, 0, sizeof(sa));
231 sa.sll_family = AF_PACKET;
232 sa.sll_protocol = 0;
233 sa.sll_ifindex = master;
234 if (bind(hardware->h_raw, (struct sockaddr*)&sa,
235 sizeof(sa)) < 0)
236 return errno;
237 /* With bonding, we need to listen to bond device. We use
238 * setsockopt() PACKET_ORIGDEV to get physical device instead of
239 * bond device */
240 if (setsockopt(hardware->h_raw, SOL_PACKET,
241 PACKET_ORIGDEV, &un, sizeof(un)) == -1) {
242 LLOG_WARN("unable to setsockopt for master bonding device of %s. "
243 "You will get inaccurate results",
244 hardware->h_ifname);
245 }
246 }
247
248 if (global->g_multi)
249 filter = LLDPD_MODE_ANY;
250 else
251 filter = LLDPD_MODE_LLDP;
252 if (lldpd_iface_switchto(global, filter, hardware) == -1) {
253 LLOG_WARNX("unable to apply filter");
254 return ENETDOWN;
255 }
256
257 if (master != -1)
258 lldpd_iface_multicast(global, if_bond, 0);
259 lldpd_iface_multicast(global, hardware->h_ifname, 0);
260
261 LLOG_DEBUG("interface %s initialized (fd=%d)", hardware->h_ifname,
262 hardware->h_raw);
263 return 0;
264}
265
266void
267lldpd_iface_multicast(struct lldpd *global, const char *name, int remove)
268{
269 struct ifreq ifr;
270 int i;
271
272 for (i=0; global->g_protocols[i].mode != 0; i++) {
273 if (!global->g_protocols[i].enabled) continue;
274 memset(&ifr, 0, sizeof(ifr));
275 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
276 memcpy(ifr.ifr_hwaddr.sa_data,
277 global->g_protocols[i].mac, ETH_ALEN);
278 if (ioctl(global->g_sock, (remove)?SIOCDELMULTI:SIOCADDMULTI,
279 &ifr) < 0) {
280 if (errno == ENOENT)
281 return;
282 LLOG_INFO("unable to %s %s address to multicast filter for %s",
283 (remove)?"delete":"add",
284 global->g_protocols[i].name,
285 name);
286 }
287 }
288}
289
290int
291lldpd_iface_close(struct lldpd *global, struct lldpd_hardware *hardware)
292{
293 char listen[IFNAMSIZ];
294
295 close(hardware->h_raw);
296 hardware->h_raw = -1;
297
298 if (hardware->h_raw_real > 0) {
299 if (if_indextoname(hardware->h_master, listen) == NULL) {
300 LLOG_WARN("unable to get index for interface %d",
301 hardware->h_master);
302 strlcpy(listen, hardware->h_ifname, sizeof(listen));
303 }
304 close(hardware->h_raw_real);
305 lldpd_iface_multicast(global, listen, 1);
306 }
307 strlcpy(listen, hardware->h_ifname, sizeof(listen));
308 lldpd_iface_multicast(global, listen, 1);
309
310 hardware->h_raw_real = -1;
311 return 0;
312}
313
314int
315lldpd_iface_switchto(struct lldpd *cfg, short int filter, struct lldpd_hardware *hardware)
316{
317 struct sock_fprog prog;
318 int i;
319
320 memset(&prog, 0, sizeof(prog));
321 for (i=0; cfg->g_protocols[i].mode != 0; i++) {
322 if (!cfg->g_protocols[i].enabled) continue;
323 if (cfg->g_protocols[i].mode == filter)
324 break;
325 }
326 prog.filter = cfg->g_protocols[i].filter;
327 prog.len = cfg->g_protocols[i].filterlen / sizeof(struct sock_filter);
328 if (setsockopt(hardware->h_raw, SOL_SOCKET, SO_ATTACH_FILTER,
329 &prog, sizeof(prog)) < 0) {
330 LLOG_WARN("unable to change filter for %s", hardware->h_ifname);
331 return -1;
332 }
333 if ((hardware->h_raw_real > 0) &&
334 (setsockopt(hardware->h_raw_real, SOL_SOCKET, SO_ATTACH_FILTER,
335 &prog, sizeof(prog)) < 0)) {
336 LLOG_WARN("unable to change filter for real device %s", hardware->h_ifname);
337 return -1;
338 }
339 return 0;
340}
341
342
343void
344lldpd_vlan_cleanup(struct lldpd_port *port)
345{
346 struct lldpd_vlan *vlan, *vlan_next;
347 for (vlan = TAILQ_FIRST(&port->p_vlans);
348 vlan != NULL;
349 vlan = vlan_next) {
350 free(vlan->v_name);
351 vlan_next = TAILQ_NEXT(vlan, v_entries);
352 TAILQ_REMOVE(&port->p_vlans, vlan, v_entries);
353 free(vlan);
354 }
355}
356
357void
358lldpd_port_cleanup(struct lldpd_port *port)
359{
360 lldpd_vlan_cleanup(port);
361 free(port->p_id);
362 free(port->p_descr);
363 free(port);
364}
365
366void
367lldpd_chassis_cleanup(struct lldpd_chassis *chassis)
368{
369 free(chassis->c_id);
370 free(chassis->c_name);
371 free(chassis->c_descr);
372 free(chassis);
373}
374
375void
376lldpd_remote_cleanup(struct lldpd *cfg, struct lldpd_hardware *hardware, int reset)
377{
378 if (hardware->h_rport != NULL) {
379 lldpd_port_cleanup(hardware->h_rport);
380 hardware->h_rport = NULL;
381 }
382 if (hardware->h_rchassis != NULL) {
383 lldpd_chassis_cleanup(hardware->h_rchassis);
384 hardware->h_rchassis = NULL;
385 }
386 hardware->h_rlastchange = hardware->h_rlastupdate = 0;
387 free(hardware->h_rlastframe);
388 hardware->h_rlastframe = NULL;
389 if (reset && cfg->g_multi) {
390 hardware->h_mode = LLDPD_MODE_ANY;
391 memset(hardware->h_proto_macs, 0, ETH_ALEN*(cfg->g_multi+1));
392 hardware->h_start_probe = 0;
393 lldpd_iface_switchto(cfg, LLDPD_MODE_ANY, hardware);
394 }
395}
396
397void
398lldpd_cleanup(struct lldpd *cfg)
399{
400 struct lldpd_hardware *hardware, *hardware_next;
401
402 for (hardware = TAILQ_FIRST(&cfg->g_hardware); hardware != NULL;
403 hardware = hardware_next) {
404 hardware_next = TAILQ_NEXT(hardware, h_entries);
405 if (hardware->h_flags == 0) {
406 TAILQ_REMOVE(&cfg->g_hardware, hardware, h_entries);
407 lldpd_iface_close(cfg, hardware);
408 lldpd_vlan_cleanup(&hardware->h_lport);
409 lldpd_remote_cleanup(cfg, hardware, 1);
410 free(hardware->h_proto_macs);
411 free(hardware->h_llastframe);
412 free(hardware);
413 } else if (hardware->h_rchassis != NULL) {
414 if (time(NULL) - hardware->h_rlastupdate >
415 hardware->h_rchassis->c_ttl) {
416 lldpd_remote_cleanup(cfg, hardware, 1);
417 hardware->h_rx_ageout_cnt++;
418 }
419 }
420 }
421}
422
423struct lldpd_hardware *
424lldpd_port_add(struct lldpd *cfg, struct ifaddrs *ifa)
425{
426 struct ifaddrs *oifap, *oifa;
427 struct lldpd_hardware *hardware;
428 struct lldpd_port *port;
429 struct lldpd_vlan *vlan;
430 struct ifreq ifr;
431 struct vlan_ioctl_args ifv;
432 struct ethtool_cmd ethc;
433 u_int8_t *lladdr;
434
435 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
436 if (strcmp(hardware->h_ifname, ifa->ifa_name) == 0)
437 break;
438 }
439
440 if (hardware == NULL) {
441 if ((hardware = (struct lldpd_hardware *)
442 calloc(1, sizeof(struct lldpd_hardware))) == NULL)
443 return (NULL);
444 hardware->h_raw = -1;
445 hardware->h_raw_real = -1;
446 hardware->h_start_probe = 0;
447 hardware->h_proto_macs = (u_int8_t*)calloc(cfg->g_multi+1, ETH_ALEN);
448 TAILQ_INIT(&hardware->h_lport.p_vlans);
449 } else {
450 lldpd_vlan_cleanup(&hardware->h_lport);
451 }
452
453 port = &hardware->h_lport;
454 hardware->h_flags = ifa->ifa_flags;
455
456 strlcpy(hardware->h_ifname, ifa->ifa_name, sizeof(hardware->h_ifname));
457 lladdr = (u_int8_t*)(((struct sockaddr_ll *)ifa->ifa_addr)->sll_addr);
458 memcpy(&hardware->h_lladdr, lladdr, sizeof(hardware->h_lladdr));
459 port->p_id_subtype = LLDP_PORTID_SUBTYPE_LLADDR;
460 port->p_id = (char*)hardware->h_lladdr;
461 port->p_id_len = sizeof(hardware->h_lladdr);
462 port->p_descr = hardware->h_ifname;
463
464 if (cfg->g_lchassis.c_id == NULL) {
465 /* Use the first port's l2 addr as the chassis ID */
466 if ((cfg->g_lchassis.c_id = malloc(sizeof(hardware->h_lladdr))) == NULL)
467 fatal(NULL);
468 cfg->g_lchassis.c_id_subtype = LLDP_CHASSISID_SUBTYPE_LLADDR;
469 cfg->g_lchassis.c_id_len = sizeof(hardware->h_lladdr);
470 memcpy(cfg->g_lchassis.c_id,
471 hardware->h_lladdr, sizeof(hardware->h_lladdr));
472 }
473
474 /* Get VLANS and aggregation status */
475 if (getifaddrs(&oifap) != 0)
476 fatal("lldpd_port_add: failed to get interface list");
477 for (oifa = oifap; oifa != NULL; oifa = oifa->ifa_next) {
478 /* Check if we already have checked this one */
479 int skip = 0;
480 TAILQ_FOREACH(vlan, &port->p_vlans, v_entries) {
481 if (strcmp(vlan->v_name, oifa->ifa_name) == 0)
482 skip = 1;
483 }
484 if (skip) continue;
485
486 /* Aggregation check */
487 if (iface_is_bond_slave(cfg, hardware->h_ifname, oifa->ifa_name))
488 port->p_aggregid = if_nametoindex(oifa->ifa_name);
489
490 /* VLAN check */
491 memset(&ifv, 0, sizeof(ifv));
492 ifv.cmd = GET_VLAN_REALDEV_NAME_CMD;
493 strlcpy(ifv.device1, oifa->ifa_name, sizeof(ifv.device1));
494 if ((ioctl(cfg->g_sock, SIOCGIFVLAN, &ifv) >= 0) &&
495 ((iface_is_bond_slave(cfg, hardware->h_ifname, ifv.u.device2)) ||
496 (strncmp(hardware->h_ifname, ifv.u.device2, sizeof(ifv.u.device2)) == 0))) {
497 if ((vlan = (struct lldpd_vlan *)
498 calloc(1, sizeof(struct lldpd_vlan))) == NULL)
499 continue;
500 if (asprintf(&vlan->v_name, "%s", oifa->ifa_name) == -1) {
501 free(vlan);
502 continue;
503 }
504 memset(&ifv, 0, sizeof(ifv));
505 ifv.cmd = GET_VLAN_VID_CMD;
506 strlcpy(ifv.device1, oifa->ifa_name, sizeof(ifv.device1));
507 if (ioctl(cfg->g_sock, SIOCGIFVLAN, &ifv) < 0) {
508 /* Dunno what happened */
509 free(vlan->v_name);
510 free(vlan);
511 } else {
512 vlan->v_vid = ifv.u.VID;
513 TAILQ_INSERT_TAIL(&port->p_vlans, vlan, v_entries);
514 }
515 }
516 }
517 freeifaddrs(oifap);
518
519 /* MAC/PHY */
520 memset(&ifr, 0, sizeof(ifr));
521 memset(&ethc, 0, sizeof(ethc));
522 strlcpy(ifr.ifr_name, hardware->h_ifname, sizeof(ifr.ifr_name));
523 ifr.ifr_data = (caddr_t)&ethc;
524 ethc.cmd = ETHTOOL_GSET;
525 if (ioctl(cfg->g_sock, SIOCETHTOOL, &ifr) == 0) {
526 int j;
527 int advertised_ethtool_to_rfc3636[][2] = {
528 {ADVERTISED_10baseT_Half, LLDP_DOT3_LINK_AUTONEG_10BASE_T},
529 {ADVERTISED_10baseT_Full, LLDP_DOT3_LINK_AUTONEG_10BASET_FD},
530 {ADVERTISED_100baseT_Half, LLDP_DOT3_LINK_AUTONEG_100BASE_TX},
531 {ADVERTISED_100baseT_Full, LLDP_DOT3_LINK_AUTONEG_100BASE_TXFD},
532 {ADVERTISED_1000baseT_Half, LLDP_DOT3_LINK_AUTONEG_1000BASE_T},
533 {ADVERTISED_1000baseT_Full, LLDP_DOT3_LINK_AUTONEG_1000BASE_TFD},
534 {ADVERTISED_10000baseT_Full, LLDP_DOT3_LINK_AUTONEG_OTHER},
535 {ADVERTISED_Pause, LLDP_DOT3_LINK_AUTONEG_FDX_PAUSE},
536 {ADVERTISED_Asym_Pause, LLDP_DOT3_LINK_AUTONEG_FDX_APAUSE},
537 {ADVERTISED_2500baseX_Full, LLDP_DOT3_LINK_AUTONEG_OTHER},
538 {0,0}};
539
540 port->p_autoneg_support = (ethc.supported & SUPPORTED_Autoneg) ? 1 : 0;
541 port->p_autoneg_enabled = (ethc.autoneg == AUTONEG_DISABLE) ? 0 : 1;
542 for (j=0; advertised_ethtool_to_rfc3636[j][0]; j++) {
543 if (ethc.advertising & advertised_ethtool_to_rfc3636[j][0])
544 port->p_autoneg_advertised |= advertised_ethtool_to_rfc3636[j][1];
545 }
546 switch (ethc.speed) {
547 case SPEED_10:
548 port->p_mau_type = (ethc.duplex == DUPLEX_FULL) ? \
549 LLDP_DOT3_MAU_10BASETFD : LLDP_DOT3_MAU_10BASETHD;
550 if (ethc.port == PORT_BNC) port->p_mau_type = LLDP_DOT3_MAU_10BASE2;
551 if (ethc.port == PORT_FIBRE)
552 port->p_mau_type = (ethc.duplex == DUPLEX_FULL) ? \
553 LLDP_DOT3_MAU_10BASEFLDF : LLDP_DOT3_MAU_10BASEFLHD;
554 break;
555 case SPEED_100:
556 port->p_mau_type = (ethc.duplex == DUPLEX_FULL) ? \
557 LLDP_DOT3_MAU_100BASETXFD : LLDP_DOT3_MAU_100BASETXHD;
558 if (ethc.port == PORT_BNC)
559 port->p_mau_type = (ethc.duplex == DUPLEX_FULL) ? \
560 LLDP_DOT3_MAU_100BASET2DF : LLDP_DOT3_MAU_100BASET2HD;
561 if (ethc.port == PORT_FIBRE)
562 port->p_mau_type = (ethc.duplex == DUPLEX_FULL) ? \
563 LLDP_DOT3_MAU_100BASEFXFD : LLDP_DOT3_MAU_100BASEFXHD;
564 break;
565 case SPEED_1000:
566 port->p_mau_type = (ethc.duplex == DUPLEX_FULL) ? \
567 LLDP_DOT3_MAU_1000BASETFD : LLDP_DOT3_MAU_1000BASETHD;
568 if (ethc.port == PORT_FIBRE)
569 port->p_mau_type = (ethc.duplex == DUPLEX_FULL) ? \
570 LLDP_DOT3_MAU_1000BASEXFD : LLDP_DOT3_MAU_1000BASEXHD;
571 break;
572 case SPEED_10000:
573 port->p_mau_type = (ethc.port == PORT_FIBRE) ? \
574 LLDP_DOT3_MAU_10GIGBASEX : LLDP_DOT3_MAU_10GIGBASER;
575 break;
576 }
577 if (ethc.port == PORT_AUI) port->p_mau_type = LLDP_DOT3_MAU_AUI;
578 }
579
580 if (!INTERFACE_OPENED(hardware)) {
581
582 if (lldpd_iface_init(cfg, hardware) != 0) {
583 lldpd_vlan_cleanup(&hardware->h_lport);
584 free(hardware->h_lladdr);
585 free(hardware->h_proto_macs);
586 free(hardware);
587 return (NULL);
588 }
589
590 TAILQ_INSERT_TAIL(&cfg->g_hardware, hardware, h_entries);
591 }
592
593 return (hardware);
594}
595
596int
597lldpd_guess_type(struct lldpd *cfg, char *frame, int s)
598{
599 int i;
600 if (s < ETH_ALEN)
601 return -1;
602 for (i=0; cfg->g_protocols[i].mode != 0; i++) {
603 if (!cfg->g_protocols[i].enabled)
604 continue;
605 if (cfg->g_protocols[i].guess == NULL) {
606 if (memcmp(frame, cfg->g_protocols[i].mac, ETH_ALEN) == 0)
607 return cfg->g_protocols[i].mode;
608 } else {
609 if (cfg->g_protocols[i].guess(frame, s))
610 return cfg->g_protocols[i].mode;
611 }
612 }
613 return -1;
614}
615
616void
617lldpd_decode(struct lldpd *cfg, char *frame, int s,
618 struct lldpd_hardware *hardware, int bond)
619{
620 int result = 0, i, j, candidatetonull;
621 u_int8_t nullmac[ETH_ALEN] = {0,0,0,0,0,0};
622 u_int8_t broadcastmac[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff};
623 struct lldpd_chassis *chassis;
624 struct lldpd_port *port;
625 struct lldpd_hardware *ohardware, *firstnull = NULL, *older = NULL;
626 int guess = LLDPD_MODE_LLDP;
627
628 if ((hardware->h_rlastframe != NULL) &&
629 (hardware->h_rlastframe->size == s) &&
630 (memcmp(hardware->h_rlastframe->frame, frame, s) == 0)) {
631 /* Already received the same frame */
632 hardware->h_rlastupdate = time(NULL);
633 return;
634 }
635
636 if (cfg->g_multi) {
637 if (hardware->h_mode == LLDPD_MODE_ANY)
638 guess = lldpd_guess_type(cfg, frame, s);
639 else
640 guess = hardware->h_mode;
641 for (i=0; cfg->g_protocols[i].mode != 0; i++) {
642 if (!cfg->g_protocols[i].enabled)
643 continue;
644 if (cfg->g_protocols[i].mode == guess) {
645 if ((result = cfg->g_protocols[i].decode(cfg, frame,
646 s, hardware, &chassis, &port)) == -1)
647 return;
648 break;
649 }
650 }
651 if (cfg->g_protocols[i].mode == 0) {
652 LLOG_INFO("unable to guess frame type");
653 return;
654 }
655 } else if (cfg->g_protocols[0].decode(cfg, frame, s, hardware,
656 &chassis, &port) == -1)
657 /* Nothing has been received */
658 return;
659
660 if (bond) {
661 /* Eh, wait ! The frame we just received was for a bonding
662 * device. We need to attach it to a real device. What is the
663 * best candidate? Drum rolling... */
664 TAILQ_FOREACH(ohardware, &cfg->g_hardware, h_entries) {
665 if (ohardware->h_master == hardware->h_master) {
666 /* Same bond */
667 if (ohardware->h_rchassis == NULL) {
668 candidatetonull = 1;
669 if (cfg->g_multi &&
670 (ohardware->h_mode == LLDPD_MODE_ANY)) {
671 for (i=j=0;
672 cfg->g_protocols[i].mode != 0;
673 i++) {
674 if (!cfg->g_protocols[i].enabled)
675 continue;
676 if ((cfg->g_protocols[i].mode == guess) &&
677 (memcmp(frame + ETH_ALEN,
678 ohardware->h_proto_macs + ETH_ALEN*j,
679 ETH_ALEN) == 0)) {
680 hardware = ohardware;
681 bond = 0;
682 break;
683 }
684 j++;
685 }
686 if (!bond) break;
687 if (firstnull != NULL) {
688 for (i=j=0;
689 cfg->g_protocols[i].mode != 0;
690 i++) {
691 if (!cfg->g_protocols[i].enabled)
692 continue;
693 if ((cfg->g_protocols[i].mode == guess) &&
694 (memcmp(nullmac,
695 ohardware->h_proto_macs +
696 ETH_ALEN*j,
697 ETH_ALEN) != 0)) {
698 /* We need to
699 * find a better
700 * candidate */
701 candidatetonull = 0;
702 break;
703 }
704 j++;
705 }
706 }
707 }
708 /* Ok, this is the first candidate if we
709 * don't find a matching chassis/port */
710 if (candidatetonull) firstnull = ohardware;
711 continue;
712 }
713 if ((older == NULL) ||
714 (older->h_rlastupdate > ohardware->h_rlastupdate))
715 /* If there is no matching chassis/port
716 * and no free hardware, we will use
717 * this one. */
718 older = ohardware;
719 if ((chassis->c_id_subtype !=
720 ohardware->h_rchassis->c_id_subtype) ||
721 (chassis->c_id_len != ohardware->h_rchassis->c_id_len) ||
722 (memcmp(chassis->c_id, ohardware->h_rchassis->c_id,
723 chassis->c_id_len) != 0) ||
724 (port->p_id_subtype != ohardware->h_rport->p_id_subtype) ||
725 (port->p_id_len != ohardware->h_rport->p_id_len) ||
726 (memcmp(port->p_id, ohardware->h_rport->p_id,
727 port->p_id_len) != 0))
728 continue;
729 /* We got a match! */
730 hardware = ohardware; /* We switch hardware */
731 bond = 0;
732 break;
733 }
734 }
735 if (bond) {
736 /* No match found */
737 if (firstnull != NULL)
738 hardware = firstnull;
739 else hardware = older;
740 }
741 }
742
743 if (cfg->g_multi &&
744 (hardware->h_mode == LLDPD_MODE_ANY)) {
745 u_int8_t *mac;
746 char *modename;
747 int filter;
748
749 for (i=j=0; cfg->g_protocols[i].mode != 0; i++) {
750 if (!cfg->g_protocols[i].enabled)
751 continue;
752 if (cfg->g_protocols[i].mode == guess) {
753 mac = hardware->h_proto_macs + ETH_ALEN*j;
754 modename = cfg->g_protocols[i].name;
755 filter = cfg->g_protocols[i].mode;
756 break;
757 }
758 j++;
759 }
760 if (cfg->g_protocols[i].mode == 0) {
761 LLOG_WARNX("should not be there");
762 goto cleanup;
763 }
764
765 if (hardware->h_start_probe == 0)
766 hardware->h_start_probe = time(NULL) - 1;
767 /* Handle switching respecting probe time */
768 if ((memcmp(mac, frame + ETH_ALEN, ETH_ALEN) == 0) &&
769 ((time(NULL) - hardware->h_start_probe) > cfg->g_probe_time) &&
770 /* Don't switch to this protocol if not LLDP and LLDP is
771 * a valid candidate */
772 ((filter == LLDPD_MODE_LLDP) ||
773 (memcmp(hardware->h_proto_macs,
774 broadcastmac, ETH_ALEN) == 0) ||
775 (memcmp(hardware->h_proto_macs,
776 nullmac, ETH_ALEN) == 0))) {
777 LLOG_INFO("switching to %s on port %s", modename,
778 hardware->h_ifname);
779 hardware->h_mode = guess;
780 lldpd_iface_switchto(cfg, filter, hardware);
781 } else {
782 /* Wait twice probe time to be able to receive packets of all kind */
783 if ((time(NULL) - hardware->h_start_probe) > cfg->g_probe_time * 2) {
784 LLOG_DEBUG("probe expired on %s, retry", hardware->h_ifname);
785 hardware->h_start_probe = 0;
786 memset(hardware->h_proto_macs, 0, ETH_ALEN*(cfg->g_multi+1));
787 goto cleanup;
788 }
789 if (memcmp(mac, broadcastmac, ETH_ALEN) == 0)
790 goto cleanup;
791 LLOG_INFO("received a %s frame on %s but wait for %d sec",
792 modename, hardware->h_ifname, cfg->g_probe_time - time(NULL) +
793 hardware->h_start_probe);
794 if (memcmp(mac, frame + ETH_ALEN, ETH_ALEN) == 0)
795 goto cleanup;
796 if (memcmp(mac, nullmac, ETH_ALEN) == 0) {
797 memcpy(mac, frame + ETH_ALEN, ETH_ALEN);
798 goto cleanup;
799 }
800 LLOG_INFO("several MAC for %s on %s, discarding %s for this interface",
801 modename, hardware->h_ifname, modename);
802 memcpy(mac, broadcastmac, ETH_ALEN);
803 goto cleanup;
804 }
805 }
806
807 result = 0;
808 if ((hardware->h_rchassis == NULL) ||
809 (chassis->c_id_subtype != hardware->h_rchassis->c_id_subtype) ||
810 (chassis->c_id_len != hardware->h_rchassis->c_id_len) ||
811 (memcmp(chassis->c_id, hardware->h_rchassis->c_id,
812 chassis->c_id_len) != 0))
813 result = 1;
814
815 /* We have our new frame */
816 lldpd_remote_cleanup(cfg, hardware, 0);
817 hardware->h_rport = port;
818 hardware->h_rchassis = chassis;
819 hardware->h_rlastchange = hardware->h_rlastupdate = time(NULL);
820
821 /* We remember this frame */
822 free(hardware->h_rlastframe);
823 if ((hardware->h_rlastframe = (struct lldpd_frame *)malloc(s +
824 sizeof(int))) != NULL) {
825 hardware->h_rlastframe->size = s;
826 memcpy(hardware->h_rlastframe->frame, frame, s);
827 }
828
829 if (result) {
830 /* This is a new remote system */
831 LLOG_DEBUG("we discovered a new remote system on %s",
832 hardware->h_ifname);
833 /* Do we already know this remote system? */
834 TAILQ_FOREACH(ohardware, &cfg->g_hardware, h_entries) {
835 if ((ohardware->h_ifname != hardware->h_ifname) &&
836 (ohardware->h_rchassis != NULL) &&
837 (ohardware->h_rchassis->c_id_subtype ==
838 chassis->c_id_subtype) &&
839 (ohardware->h_rchassis->c_id_len ==
840 chassis->c_id_len) &&
841 (memcmp(ohardware->h_rchassis->c_id,
842 chassis->c_id, chassis->c_id_len) == 0)) {
843 LLOG_DEBUG("but it was already on %s",
844 ohardware->h_ifname);
845 hardware->h_rid = ohardware->h_rid;
846 return;
847 }
848 }
849 hardware->h_rid = ++cfg->g_lastrid;
850 }
851 return;
852
853cleanup:
854 lldpd_chassis_cleanup(chassis);
855 lldpd_port_cleanup(port);
856 return;
857}
858
859void
860lldpd_handle_client(struct lldpd *cfg, struct lldpd_client *client,
861 char *buffer, int n)
862{
863 struct hmsg *h; /* Reception */
864 struct hmsg *t; /* Sending */
865 struct client_handle *ch;
866
867 if (n < sizeof(struct hmsg_hdr)) {
868 LLOG_WARNX("too short message request received");
869 return;
870 }
871 h = (struct hmsg *)buffer;
872 n -= sizeof(struct hmsg_hdr);
873 if (n != h->hdr.len) {
874 LLOG_WARNX("incorrect message size received from %d",
875 h->hdr.pid);
876 return;
877 }
878
879 if ((t = (struct hmsg*)calloc(1, MAX_HMSGSIZE)) == NULL) {
880 LLOG_WARNX("unable to allocate memory to answer to %d",
881 h->hdr.pid);
882 return;
883 }
884 ctl_msg_init(t, h->hdr.type);
885 for (ch = client_handles; ch->handle != NULL; ch++) {
886 if (ch->type == h->hdr.type) {
887 ch->handle(cfg, h, t);
888 if (t->hdr.len == -1) {
889 t->hdr.len = 0;
890 t->hdr.type = HMSG_NONE;
891 }
892 if (ctl_msg_send(client->fd, t) == -1)
893 LLOG_WARN("unable to send answer to client %d",
894 h->hdr.pid);
895 free(t);
896 return;
897 }
898 }
899
900 LLOG_WARNX("unknown message request (%d) received from %d",
901 h->hdr.type, h->hdr.pid);
902 free(t);
903 return;
904}
905
906void
907lldpd_handle_shutdown(struct lldpd *cfg, struct hmsg *r, struct hmsg *s)
908{
909 LLOG_INFO("received shutdown request from client %d",
910 r->hdr.pid);
911 exit(0);
912}
913
914void
915lldpd_handle_none(struct lldpd *cfg, struct hmsg *r, struct hmsg *s)
916{
917 LLOG_INFO("received noop request from client %d",
918 r->hdr.pid);
919 s->hdr.len = -1;
920}
921
922void
923lldpd_handle_get_interfaces(struct lldpd *cfg, struct hmsg *r, struct hmsg *s)
924{
925 struct lldpd_interface *iff, *iff_next;
926 struct lldpd_hardware *hardware;
927 void *p;
928
929 /* Build the list of interfaces */
930 TAILQ_HEAD(, lldpd_interface) ifs;
931 TAILQ_INIT(&ifs);
932 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
933 if ((iff = (struct lldpd_interface*)malloc(sizeof(
934 struct lldpd_interface))) == NULL)
935 fatal(NULL);
936 iff->name = hardware->h_ifname;
937 TAILQ_INSERT_TAIL(&ifs, iff, next);
938 }
939
940 p = &s->data;
941 if (ctl_msg_pack_list(STRUCT_LLDPD_INTERFACE, &ifs,
942 sizeof(struct lldpd_interface), s, &p) == -1) {
943 LLOG_WARNX("unable to pack list of interfaces");
944 s->hdr.len = -1;
945 }
946
947 /* Free the temporary list */
948 for (iff = TAILQ_FIRST(&ifs);
949 iff != NULL;
950 iff = iff_next) {
951 iff_next = TAILQ_NEXT(iff, next);
952 TAILQ_REMOVE(&ifs, iff, next);
953 free(iff);
954 }
955}
956
957void
958lldpd_handle_get_port_related(struct lldpd *cfg, struct hmsg *r, struct hmsg *s)
959{
960 char *ifname;
961 struct lldpd_hardware *hardware;
962 void *p;
963
964 ifname = (char*)(&r->data);
965 if (ifname[r->hdr.len - 1] != 0) {
966 LLOG_WARNX("bad message format for get port related message");
967 s->hdr.len = -1;
968 return;
969 }
970 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
971 if (strncmp(ifname, hardware->h_ifname, IFNAMSIZ) == 0) {
972 if ((hardware->h_rport == NULL) ||
973 (hardware->h_rchassis == NULL)) {
974 s->hdr.len = 0;
975 s->hdr.type = HMSG_NONE;
976 return;
977 }
978 p = &s->data;
979 switch (r->hdr.type) {
980 case HMSG_GET_VLANS:
981 if (ctl_msg_pack_list(STRUCT_LLDPD_VLAN,
982 &hardware->h_rport->p_vlans,
983 sizeof(struct lldpd_vlan), s, &p) == -1) {
984 LLOG_WARNX("unable to send vlans information for "
985 "interface %s for %d", ifname, r->hdr.pid);
986 s->hdr.len = -1;
987 return;
988 }
989 break;
990 case HMSG_GET_PORT:
991 if (ctl_msg_pack_structure(STRUCT_LLDPD_PORT,
992 hardware->h_rport,
993 sizeof(struct lldpd_port), s, &p) == -1) {
994 LLOG_WARNX("unable to send port information for "
995 "interface %s for %d", ifname, r->hdr.pid);
996 s->hdr.len = -1;
997 return;
998 }
999 break;
1000 case HMSG_GET_CHASSIS:
1001 if (ctl_msg_pack_structure(STRUCT_LLDPD_CHASSIS,
1002 hardware->h_rchassis,
1003 sizeof(struct lldpd_chassis), s, &p) == -1) {
1004 LLOG_WARNX("unable to send chassis information for "
1005 "interface %s for %d", ifname, r->hdr.pid);
1006 s->hdr.len = -1;
1007 return;
1008 }
1009 break;
1010 default:
1011 LLOG_WARNX("don't know what to do");
1012 s->hdr.len = -1;
1013 return;
1014 }
1015 return;
1016 }
1017 }
1018 LLOG_WARNX("requested interface %s by %d was not found",
1019 ifname, r->hdr.pid);
1020 s->hdr.len = -1;
1021 return;
1022}
1023
1024void
1025lldpd_recv_all(struct lldpd *cfg)
1026{
1027 struct lldpd_hardware *hardware;
1028 struct lldpd_client *client, *client_next;
1029 fd_set rfds;
1030 struct timeval tv;
1031 struct sockaddr_ll from;
1032 socklen_t fromlen;
1033 int onreal;
1034#ifdef USE_SNMP
1035 int fakeblock = 0;
1036 struct timeval *tvp = &tv;
1037#endif
1038 int rc, nfds, n, bond;
1039 char *buffer;
1040
1041 do {
1042 tv.tv_sec = cfg->g_delay - (time(NULL) - cfg->g_lastsent);
1043 if (tv.tv_sec < 0)
1044 tv.tv_sec = LLDPD_TX_DELAY;
1045 if (tv.tv_sec >= cfg->g_delay)
1046 tv.tv_sec = cfg->g_delay;
1047 tv.tv_usec = 0;
1048
1049 FD_ZERO(&rfds);
1050 nfds = -1;
1051
1052 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
1053 /* Ignore if interface is down */
1054 if ((hardware->h_flags & IFF_UP) == 0)
1055 continue;
1056 FD_SET(hardware->h_raw, &rfds);
1057 if (nfds < hardware->h_raw)
1058 nfds = hardware->h_raw;
1059 /* Listen to real interface too. In 2.6.27, we can
1060 * receive packets if this is the slave interface. */
1061 if (hardware->h_raw_real > 0) {
1062 FD_SET(hardware->h_raw_real, &rfds);
1063 if (nfds < hardware->h_raw_real)
1064 nfds = hardware->h_raw_real;
1065 }
1066 }
1067 TAILQ_FOREACH(client, &cfg->g_clients, next) {
1068 FD_SET(client->fd, &rfds);
1069 if (nfds < client->fd)
1070 nfds = client->fd;
1071 }
1072 FD_SET(cfg->g_ctl, &rfds);
1073 if (nfds < cfg->g_ctl)
1074 nfds = cfg->g_ctl;
1075
1076#ifdef USE_SNMP
1077 if (cfg->g_snmp)
1078 snmp_select_info(&nfds, &rfds, tvp, &fakeblock);
1079#endif /* USE_SNMP */
1080 if (nfds == -1) {
1081 sleep(cfg->g_delay);
1082 return;
1083 }
1084
1085 rc = select(nfds + 1, &rfds, NULL, NULL, &tv);
1086 if (rc == -1) {
1087 if (errno == EINTR)
1088 continue;
1089 LLOG_WARN("failure on select");
1090 break;
1091 }
1092#ifdef USE_SNMP
1093 if (cfg->g_snmp) {
1094 if (rc > 0)
1095 snmp_read(&rfds);
1096 else if (rc == 0)
1097 snmp_timeout();
1098 }
1099#endif /* USE_SNMP */
1100 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
1101 /* We could have received something on _real_
1102 * interface. However, even in this case, this could be
1103 * just an outgoing packet. We will try to handle both
1104 * cases, but maybe not in the same select. */
1105 onreal = ((hardware->h_raw_real > 0) &&
1106 (FD_ISSET(hardware->h_raw_real, &rfds)));
1107 if (onreal || (FD_ISSET(hardware->h_raw, &rfds))) {
1108 if ((buffer = (char *)malloc(
1109 hardware->h_mtu)) == NULL) {
1110 LLOG_WARN("failed to alloc reception buffer");
1111 continue;
1112 }
1113 fromlen = sizeof(from);
1114 if ((n = recvfrom(
1115 onreal?hardware->h_raw_real:hardware->h_raw,
1116 buffer,
1117 hardware->h_mtu, 0,
1118 (struct sockaddr *)&from,
1119 &fromlen)) == -1) {
1120 LLOG_WARN("error while receiving frame on %s",
1121 hardware->h_ifname);
1122 hardware->h_rx_discarded_cnt++;
1123 free(buffer);
1124 continue;
1125 }
1126 if (from.sll_pkttype == PACKET_OUTGOING) {
1127 free(buffer);
1128 continue;
1129 }
1130 bond = 0;
1131 /* If received on real interface, we act like if
1132 * this is not a bond! */
1133 if (!onreal && (hardware->h_raw_real > 0)) {
1134 /* Bonding. Is it for the correct
1135 * physical interface ? */
1136 if (from.sll_ifindex == hardware->h_master) {
1137 /* It seems that we don't know from
1138 which physical interface it comes
1139 (kernel < 2.6.24 ?) */
1140 bond = 1;
1141 } else if (from.sll_ifindex !=
1142 if_nametoindex(hardware->h_ifname)) {
1143 free(buffer);
1144 continue;
1145 }
1146 }
1147 hardware->h_rx_cnt++;
1148 lldpd_decode(cfg, buffer, n, hardware, bond);
1149 free(buffer);
1150 }
1151
1152 }
1153 if (FD_ISSET(cfg->g_ctl, &rfds)) {
1154 if (ctl_accept(cfg, cfg->g_ctl) == -1)
1155 LLOG_WARN("unable to accept new client");
1156 }
1157 for (client = TAILQ_FIRST(&cfg->g_clients);
1158 client != NULL;
1159 client = client_next) {
1160 client_next = TAILQ_NEXT(client, next);
1161 if (FD_ISSET(client->fd, &rfds)) {
1162 /* Got a message */
1163 if ((buffer = (char *)malloc(MAX_HMSGSIZE)) ==
1164 NULL) {
1165 LLOG_WARN("failed to alloc reception buffer");
1166 continue;
1167 }
1168 if ((n = recv(client->fd, buffer,
1169 MAX_HMSGSIZE, 0)) == -1) {
1170 LLOG_WARN("error while receiving message");
1171 free(buffer);
1172 continue;
1173 }
1174 if (n > 0)
1175 lldpd_handle_client(cfg, client, buffer, n);
1176 else
1177 ctl_close(cfg, client->fd); /* Will use TAILQ_REMOVE ! */
1178 free(buffer);
1179 }
1180 }
1181
1182#ifdef USE_SNMP
1183 if (cfg->g_snmp) {
1184 run_alarms();
1185 netsnmp_check_outstanding_agent_requests();
1186 }
1187#endif /* USE_SNMP */
1188 } while ((rc != 0) || (time(NULL) - cfg->g_lastsent < cfg->g_delay));
1189}
1190
1191void
1192lldpd_send_all(struct lldpd *cfg)
1193{
1194 struct lldpd_hardware *hardware;
1195 int i;
1196 cfg->g_lastsent = time(NULL);
1197 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
1198 /* Ignore if interface is down */
1199 if ((hardware->h_flags & IFF_UP) == 0)
1200 continue;
1201
1202 for (i=0; cfg->g_protocols[i].mode != 0; i++) {
1203 if (!cfg->g_protocols[i].enabled)
1204 continue;
1205 if ((hardware->h_mode == cfg->g_protocols[i].mode) ||
1206 (cfg->g_protocols[i].mode == LLDPD_MODE_LLDP))
1207 cfg->g_protocols[i].send(cfg, &cfg->g_lchassis, hardware);
1208 }
1209 }
1210}
1211
1212void
1213lldpd_loop(struct lldpd *cfg)
1214{
1215 struct ifaddrs *ifap, *ifa;
1216 struct sockaddr_ll *sdl;
1217 struct lldpd_hardware *hardware;
1218 int f;
1219 char status;
1220 struct utsname *un;
1221 struct hostent *hp;
1222
1223 /* Set system name and description */
1224 if ((un = (struct utsname*)malloc(sizeof(struct utsname))) == NULL)
1225 fatal(NULL);
1226 if (uname(un) != 0)
1227 fatal("failed to get system information");
1228 if ((hp = gethostbyname(un->nodename)) == NULL)
1229 fatal("failed to get system name");
1230 free(cfg->g_lchassis.c_name);
1231 free(cfg->g_lchassis.c_descr);
1232 if (asprintf(&cfg->g_lchassis.c_name, "%s",
1233 hp->h_name) == -1)
1234 fatal("failed to set system name");
1235 if (asprintf(&cfg->g_lchassis.c_descr, "%s %s %s %s",
1236 un->sysname, un->release, un->version, un->machine) == -1)
1237 fatal("failed to set system description");
1238 free(un);
1239
1240 /* Check forwarding */
1241 cfg->g_lchassis.c_cap_enabled = 0;
1242 if ((f = open("/proc/sys/net/ipv4/ip_forward", 0)) >= 0) {
1243 if ((read(f, &status, 1) == 1) && (status == '1'))
1244 cfg->g_lchassis.c_cap_enabled = LLDP_CAP_ROUTER;
1245 close(f);
1246 }
1247
1248 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries)
1249 hardware->h_flags = 0;
1250
1251 if (getifaddrs(&ifap) != 0)
1252 fatal("lldpd_loop: failed to get interface list");
1253
1254 cfg->g_lchassis.c_mgmt.s_addr = INADDR_ANY;
1255 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
1256 if (cfg->g_lchassis.c_mgmt.s_addr == INADDR_ANY)
1257 /* Get management address, if available */
1258 if ((ifa->ifa_addr != NULL) &&
1259 (ifa->ifa_addr->sa_family == AF_INET)) {
1260 struct sockaddr_in *sa;
1261 sa = (struct sockaddr_in *)ifa->ifa_addr;
1262 if ((ntohl(*(u_int32_t*)&sa->sin_addr) != INADDR_LOOPBACK) &&
1263 (cfg->g_mgmt_pattern == NULL)) {
1264 memcpy(&cfg->g_lchassis.c_mgmt,
1265 &sa->sin_addr,
1266 sizeof(struct in_addr));
1267 cfg->g_lchassis.c_mgmt_if = if_nametoindex(ifa->ifa_name);
1268 }
1269 else if (cfg->g_mgmt_pattern != NULL) {
1270 char *ip;
1271 ip = inet_ntoa(sa->sin_addr);
1272 if (fnmatch(cfg->g_mgmt_pattern,
1273 ip, 0) == 0) {
1274 memcpy(&cfg->g_lchassis.c_mgmt,
1275 &sa->sin_addr,
1276 sizeof(struct in_addr));
1277 cfg->g_lchassis.c_mgmt_if =
1278 if_nametoindex(ifa->ifa_name);
1279 }
1280 }
1281 }
1282
1283 if (iface_is_bridge(cfg, ifa->ifa_name)) {
1284 cfg->g_lchassis.c_cap_enabled |= LLDP_CAP_BRIDGE;
1285 continue;
1286 }
1287
1288 if ((iface_is_vlan(cfg, ifa->ifa_name)) ||
1289 (iface_is_bond(cfg, ifa->ifa_name)))
1290 continue;
1291
1292 if (ifa->ifa_addr == NULL ||
1293 ifa->ifa_addr->sa_family != PF_PACKET)
1294 continue;
1295
1296 if (!(ifa->ifa_flags & IFF_MULTICAST))
1297 continue;
1298
1299 sdl = (struct sockaddr_ll *)ifa->ifa_addr;
1300 if (sdl->sll_hatype != ARPHRD_ETHER || !sdl->sll_halen)
1301 continue;
1302
1303 if (iface_is_wireless(cfg, ifa->ifa_name))
1304 cfg->g_lchassis.c_cap_enabled |= LLDP_CAP_WLAN;
1305
1306
1307 if (lldpd_port_add(cfg, ifa) == NULL)
1308 LLOG_WARNX("failed to allocate port %s, skip it",
1309 ifa->ifa_name);
1310 }
1311
1312 freeifaddrs(ifap);
1313
1314 lldpd_cleanup(cfg);
1315
1316 lldpd_send_all(cfg);
1317 lldpd_recv_all(cfg);
1318}
1319
1320void
1321lldpd_hangup(int sig)
1322{
1323 /* Re-execute */
1324 LLOG_INFO("sighup received, reloading");
1325 lldpd_exit();
1326 execv(saved_argv[0], saved_argv);
1327}
1328
1329void
1330lldpd_shutdown(int sig)
1331{
1332 LLOG_INFO("signal received, exiting");
1333 exit(0);
1334}
1335
1336/* For signal handling */
1337struct lldpd *gcfg = NULL;
1338
1339void
1340lldpd_exit()
1341{
1342 struct lldpd_hardware *hardware;
1343 ctl_cleanup(gcfg->g_ctl, LLDPD_CTL_SOCKET);
1344 TAILQ_FOREACH(hardware, &gcfg->g_hardware, h_entries) {
1345 if (INTERFACE_OPENED(hardware))
1346 lldpd_iface_close(gcfg, hardware);
1347 }
1348#ifdef USE_SNMP
1349 if (gcfg->g_snmp)
1350 agent_shutdown();
1351#endif /* USE_SNMP */
1352}
1353
1354int
1355main(int argc, char *argv[])
1356{
1357 struct lldpd *cfg;
1358 int ch, snmp = 0, debug = 0;
1359 char *mgmtp = NULL;
1360 char *popt, opts[] = "dxm:p:@ ";
1361 int probe = 0, i, found;
1362
1363 saved_argv = argv;
1364
1365 /*
1366 * Get and parse command line options
1367 */
1368 popt = index(opts, '@');
1369 for (i=0; protos[i].mode != 0; i++) {
1370 if (protos[i].enabled == 1) continue;
1371 *(popt++) = protos[i].arg;
1372 }
1373 *popt = '\0';
1374 while ((ch = getopt(argc, argv, opts)) != -1) {
1375 switch (ch) {
1376 case 'd':
1377 debug++;
1378 break;
1379 case 'm':
1380 mgmtp = optarg;
1381 break;
1382 case 'p':
1383 probe = atoi(optarg);
1384 break;
1385 case 'x':
1386 snmp = 1;
1387 break;
1388 default:
1389 found = 0;
1390 for (i=0; protos[i].mode != 0; i++) {
1391 if (protos[i].enabled) continue;
1392 if (ch == protos[i].arg) {
1393 protos[i].enabled = 1;
1394 found = 1;
1395 }
1396 }
1397 if (!found)
1398 usage();
1399 }
1400 }
1401
1402 log_init(debug);
1403
1404 if (probe == 0) probe = LLDPD_TTL;
1405
1406 if ((cfg = (struct lldpd *)
1407 calloc(1, sizeof(struct lldpd))) == NULL)
1408 fatal(NULL);
1409
1410 if (mgmtp != NULL)
1411 cfg->g_mgmt_pattern = mgmtp;
1412
1413 /* Get ioctl socket */
1414 if ((cfg->g_sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
1415 fatal("failed to get ioctl socket");
1416 cfg->g_delay = LLDPD_TX_DELAY;
1417
1418 /* Set system capabilities */
1419 cfg->g_lchassis.c_cap_available = LLDP_CAP_BRIDGE | LLDP_CAP_WLAN |
1420 LLDP_CAP_ROUTER;
1421
1422 /* Set TTL */
1423 cfg->g_lchassis.c_ttl = LLDPD_TTL;
1424
1425 cfg->g_protocols = protos;
1426 cfg->g_probe_time = probe;
1427 for (i=0; protos[i].mode != 0; i++)
1428 if (protos[i].enabled) {
1429 cfg->g_multi++;
1430 LLOG_INFO("protocol %s enabled", protos[i].name);
1431 } else
1432 LLOG_INFO("protocol %s disabled", protos[i].name);
1433 cfg->g_multi--;
1434
1435 TAILQ_INIT(&cfg->g_hardware);
1436
1437#ifdef USE_SNMP
1438 if (snmp) {
1439 cfg->g_snmp = 1;
1440 agent_init(cfg, debug);
1441 }
1442#endif /* USE_SNMP */
1443
1444 /* Create socket */
1445 if ((cfg->g_ctl = ctl_create(cfg, LLDPD_CTL_SOCKET)) == -1)
1446 fatal("unable to create control socket " LLDPD_CTL_SOCKET);
1447
1448 if (!debug && daemon(0, 0) != 0) {
1449 ctl_cleanup(cfg->g_ctl, LLDPD_CTL_SOCKET);
1450 fatal("failed to detach daemon");
1451 }
1452 gcfg = cfg;
1453 if (atexit(lldpd_exit) != 0) {
1454 ctl_cleanup(cfg->g_ctl, LLDPD_CTL_SOCKET);
1455 fatal("unable to set exit function");
1456 }
1457 if (!debug) {
1458 int pid;
1459 char *spid;
1460 if ((pid = open(LLDPD_PID_FILE,
1461 O_TRUNC | O_CREAT | O_WRONLY)) == -1)
1462 fatal("unable to open pid file " LLDPD_PID_FILE);
1463 if (asprintf(&spid, "%d\n", getpid()) == -1)
1464 fatal("unable to create pid file " LLDPD_PID_FILE);
1465 if (write(pid, spid, strlen(spid)) == -1)
1466 fatal("unable to write pid file " LLDPD_PID_FILE);
1467 free(spid);
1468 close(pid);
1469 }
1470
1471 /* Signal handling */
1472 signal(SIGHUP, lldpd_hangup);
1473 signal(SIGINT, lldpd_shutdown);
1474 signal(SIGTERM, lldpd_shutdown);
1475
1476 for (;;)
1477 lldpd_loop(cfg);
1478
1479 return (0);
1480}