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