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