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