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