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