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