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