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