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