]> git.ipfire.org Git - thirdparty/lldpd.git/blob - src/lldpd.c
Use strdup instead of asprintf("%s")
[thirdparty/lldpd.git] / src / lldpd.c
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 <libgen.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
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
49 void usage(void);
50
51 int lldpd_iface_init(struct lldpd *, struct lldpd_hardware *);
52 int lldpd_iface_init_vlan(struct lldpd *, struct lldpd_vif *);
53 void lldpd_iface_init_mtu(struct lldpd *, struct lldpd_hardware *);
54 int lldpd_iface_close(struct lldpd *, struct lldpd_hardware *);
55 void 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 },
67 struct sock_filter lldpd_filter_lldp_f[] = { LLDPD_FILTER_LLDP_F };
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 },
76 struct sock_filter lldpd_filter_fdp_f[] = { LLDPD_FILTER_FDP_F };
77 /* "ether dst 01:00:0c:cc:cc:cc" */
78 #define LLDPD_FILTER_CDP_F \
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 },
85 struct 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 },
94 struct 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 },
103 struct 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 }, \
110 { 0x15, 11, 12, 0x00000180 }, \
111 { 0x20, 0, 0, 0x00000002 }, \
112 { 0x15, 0, 2, 0x2b000000 }, \
113 { 0x28, 0, 0, 0x00000000 }, \
114 { 0x15, 7, 8, 0x000000e0 }, \
115 { 0x15, 1, 0, 0x0ccccccc }, \
116 { 0x15, 0, 2, 0x81000100 }, \
117 { 0x28, 0, 0, 0x00000000 }, \
118 { 0x15, 3, 4, 0x00000100 }, \
119 { 0x15, 0, 3, 0x52cccccc }, \
120 { 0x28, 0, 0, 0x00000000 }, \
121 { 0x15, 0, 1, 0x000001e0 }, \
122 { 0x6, 0, 0, 0x0000ffff }, \
123 { 0x6, 0, 0, 0x00000000 },
124 struct sock_filter lldpd_filter_any_f[] = { LLDPD_FILTER_ANY_F };
125
126 struct 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) },
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) },
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
144 int lldpd_iface_switchto(struct lldpd *, short int,
145 struct lldpd_hardware *);
146 struct lldpd_hardware *lldpd_port_add(struct lldpd *, struct ifaddrs *);
147 void lldpd_loop(struct lldpd *);
148 void lldpd_shutdown(int);
149 void lldpd_exit();
150 void lldpd_send_all(struct lldpd *);
151 void lldpd_recv_all(struct lldpd *);
152 int lldpd_guess_type(struct lldpd *, char *, int);
153 void lldpd_decode(struct lldpd *, char *, int,
154 struct lldpd_hardware *, int);
155
156 char **saved_argv;
157
158 void
159 usage(void)
160 {
161 extern const char *__progname;
162 #ifndef USE_SNMP
163 fprintf(stderr, "usage: %s [-dvcse] [-p|-P] [-m ip]\n", __progname);
164 #else /* USE_SNMP */
165 fprintf(stderr, "usage: %s [-dvcsex] [-p|-P] [-m ip]\n", __progname);
166 #endif /* USE_SNMP */
167 exit(1);
168 }
169
170 void
171 lldpd_iface_init_mtu(struct lldpd *global, struct lldpd_hardware *hardware)
172 {
173 struct ifreq ifr;
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;
183 }
184
185 int
186 lldpd_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);
192 status = priv_iface_init((struct lldpd_hardware*)vif, -1);
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
214 int
215 lldpd_iface_init(struct lldpd *global, struct lldpd_hardware *hardware)
216 {
217 int master; /* Bond device */
218 char if_bond[IFNAMSIZ];
219 int status;
220 short int filter;
221
222 lldpd_iface_init_mtu(global, hardware);
223 status = priv_iface_init(hardware, -1);
224 if (status != 0)
225 return status;
226
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;
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 }
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
264 void
265 lldpd_iface_multicast(struct lldpd *global, const char *name, int remove)
266 {
267 int i, rc;
268
269 for (i=0; global->g_protocols[i].mode != 0; i++) {
270 if (!global->g_protocols[i].enabled) continue;
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);
279 }
280 }
281 }
282
283 int
284 lldpd_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
307 int
308 lldpd_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
336 void
337 lldpd_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
350 void
351 lldpd_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
359 void
360 lldpd_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
368 void
369 lldpd_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
390 void
391 lldpd_cleanup(struct lldpd *cfg)
392 {
393 struct lldpd_hardware *hardware, *hardware_next;
394 struct lldpd_vif *vif, *vif_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 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
426 struct lldpd_vif *
427 lldpd_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 }
454
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;
478 }
479
480 struct lldpd_hardware *
481 lldpd_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;
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 ((vlan->v_name = strdup(oifa->ifa_name)) == NULL) {
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 */
576 if (priv_ethtool(hardware->h_ifname, &ethc) == 0) {
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;
629 } else
630 LLOG_DEBUG("unable to get eth info for %s", hardware->h_ifname);
631
632 if (!INTERFACE_OPENED(hardware)) {
633
634 if (lldpd_iface_init(cfg, hardware) != 0) {
635 LLOG_WARN("unable to initialize %s", hardware->h_ifname);
636 lldpd_vlan_cleanup(&hardware->h_lport);
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
648 int
649 lldpd_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
668 void
669 lldpd_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
680 /* Discard VLAN frames */
681 if ((s >= sizeof(struct ieee8023)) &&
682 (((struct ieee8023*)frame)->size == htons(ETHERTYPE_VLAN)))
683 return;
684
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
910 cleanup:
911 lldpd_chassis_cleanup(chassis);
912 lldpd_port_cleanup(port);
913 return;
914 }
915
916 void
917 lldpd_recv_all(struct lldpd *cfg)
918 {
919 struct lldpd_hardware *hardware;
920 struct lldpd_vif *vif;
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 }
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 }
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 */
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 }
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)
1109 client_handle_client(cfg, client, buffer, n);
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
1125 void
1126 lldpd_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
1146 void
1147 lldpd_loop(struct lldpd *cfg)
1148 {
1149 struct ifaddrs *ifap, *ifa;
1150 struct sockaddr_ll *sdl;
1151 struct lldpd_hardware *hardware;
1152 struct lldpd_vif *vif;
1153 int f;
1154 char status;
1155 struct utsname *un;
1156 char *hp;
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");
1163 if ((hp = priv_gethostbyname()) == NULL)
1164 fatal("failed to get system name");
1165 free(cfg->g_lchassis.c_name);
1166 free(cfg->g_lchassis.c_descr);
1167 if ((cfg->g_lchassis.c_name = strdup(hp)) == NULL)
1168 fatal(NULL);
1169 if (asprintf(&cfg->g_lchassis.c_descr, "%s %s %s %s",
1170 un->sysname, un->release, un->version, un->machine) == -1)
1171 fatal("failed to set system description");
1172 free(un);
1173
1174 /* Check forwarding */
1175 cfg->g_lchassis.c_cap_enabled = 0;
1176 if ((f = priv_open("/proc/sys/net/ipv4/ip_forward")) >= 0) {
1177 if ((read(f, &status, 1) == 1) && (status == '1')) {
1178 cfg->g_lchassis.c_cap_enabled = LLDP_CAP_ROUTER;
1179 }
1180 close(f);
1181 }
1182
1183 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries)
1184 hardware->h_flags = 0;
1185 TAILQ_FOREACH(vif, &cfg->g_vif, vif_entries)
1186 vif->vif_flags = 0;
1187
1188 if (getifaddrs(&ifap) != 0)
1189 fatal("lldpd_loop: failed to get interface list");
1190
1191 cfg->g_lchassis.c_mgmt.s_addr = INADDR_ANY;
1192 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
1193 if (cfg->g_lchassis.c_mgmt.s_addr == INADDR_ANY)
1194 /* Get management address, if available */
1195 if ((ifa->ifa_addr != NULL) &&
1196 (ifa->ifa_addr->sa_family == AF_INET)) {
1197 struct sockaddr_in *sa;
1198 sa = (struct sockaddr_in *)ifa->ifa_addr;
1199 if ((ntohl(*(u_int32_t*)&sa->sin_addr) != INADDR_LOOPBACK) &&
1200 (cfg->g_mgmt_pattern == NULL)) {
1201 memcpy(&cfg->g_lchassis.c_mgmt,
1202 &sa->sin_addr,
1203 sizeof(struct in_addr));
1204 cfg->g_lchassis.c_mgmt_if = if_nametoindex(ifa->ifa_name);
1205 }
1206 else if (cfg->g_mgmt_pattern != NULL) {
1207 char *ip;
1208 ip = inet_ntoa(sa->sin_addr);
1209 if (fnmatch(cfg->g_mgmt_pattern,
1210 ip, 0) == 0) {
1211 memcpy(&cfg->g_lchassis.c_mgmt,
1212 &sa->sin_addr,
1213 sizeof(struct in_addr));
1214 cfg->g_lchassis.c_mgmt_if =
1215 if_nametoindex(ifa->ifa_name);
1216 }
1217 }
1218 }
1219
1220 if (ifa->ifa_addr == NULL ||
1221 ifa->ifa_addr->sa_family != PF_PACKET)
1222 continue;
1223
1224 sdl = (struct sockaddr_ll *)ifa->ifa_addr;
1225 if (sdl->sll_hatype != ARPHRD_ETHER || !sdl->sll_halen)
1226 continue;
1227
1228 if (iface_is_bridge(cfg, ifa->ifa_name)) {
1229 cfg->g_lchassis.c_cap_enabled |= LLDP_CAP_BRIDGE;
1230 continue;
1231 }
1232
1233 if ((iface_is_vlan(cfg, ifa->ifa_name)) ||
1234 (iface_is_bond(cfg, ifa->ifa_name)))
1235 continue;
1236
1237 if (!(ifa->ifa_flags & IFF_MULTICAST))
1238 continue;
1239
1240 if (iface_is_wireless(cfg, ifa->ifa_name))
1241 cfg->g_lchassis.c_cap_enabled |= LLDP_CAP_WLAN;
1242
1243 if (lldpd_port_add(cfg, ifa) == NULL)
1244 LLOG_WARNX("failed to allocate port %s, skip it",
1245 ifa->ifa_name);
1246 }
1247
1248 /* Handle VLAN */
1249 if (cfg->g_listen_vlans) {
1250 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
1251 if ((iface_is_vlan(cfg, ifa->ifa_name)) &&
1252 (lldpd_port_add_vlan(cfg, ifa) == NULL)) {
1253 LLOG_WARNX("unable to allocate vlan %s, skip it",
1254 ifa->ifa_name);
1255 }
1256 }
1257 }
1258
1259 freeifaddrs(ifap);
1260
1261 lldpd_cleanup(cfg);
1262
1263 lldpd_send_all(cfg);
1264 lldpd_recv_all(cfg);
1265 }
1266
1267 void
1268 lldpd_shutdown(int sig)
1269 {
1270 LLOG_INFO("signal received, exiting");
1271 exit(0);
1272 }
1273
1274 /* For signal handling */
1275 struct lldpd *gcfg = NULL;
1276
1277 void
1278 lldpd_exit()
1279 {
1280 struct lldpd_hardware *hardware;
1281 struct lldpd_vif *vif;
1282 close(gcfg->g_ctl);
1283 priv_ctl_cleanup();
1284 TAILQ_FOREACH(hardware, &gcfg->g_hardware, h_entries) {
1285 if (INTERFACE_OPENED(hardware))
1286 lldpd_iface_close(gcfg, hardware);
1287 }
1288 TAILQ_FOREACH(vif, &gcfg->g_vif, vif_entries) {
1289 if (vif->vif_raw != -1)
1290 lldpd_iface_close(gcfg, (struct lldpd_hardware*)vif);
1291 }
1292 #ifdef USE_SNMP
1293 if (gcfg->g_snmp)
1294 agent_shutdown();
1295 #endif /* USE_SNMP */
1296 }
1297
1298 int
1299 main(int argc, char *argv[])
1300 {
1301 struct lldpd *cfg;
1302 int ch, snmp = 0, debug = 0;
1303 char *mgmtp = NULL;
1304 char *popt, opts[] = "vdxm:p:@ ";
1305 int probe = 0, i, found, vlan = 0;
1306
1307 saved_argv = argv;
1308
1309 /*
1310 * Get and parse command line options
1311 */
1312 popt = index(opts, '@');
1313 for (i=0; protos[i].mode != 0; i++) {
1314 if (protos[i].enabled == 1) continue;
1315 *(popt++) = protos[i].arg;
1316 }
1317 *popt = '\0';
1318 while ((ch = getopt(argc, argv, opts)) != -1) {
1319 switch (ch) {
1320 case 'v':
1321 vlan = 1;
1322 break;
1323 case 'd':
1324 debug++;
1325 break;
1326 case 'm':
1327 mgmtp = optarg;
1328 break;
1329 case 'p':
1330 probe = atoi(optarg);
1331 break;
1332 case 'x':
1333 snmp = 1;
1334 break;
1335 default:
1336 found = 0;
1337 for (i=0; protos[i].mode != 0; i++) {
1338 if (protos[i].enabled) continue;
1339 if (ch == protos[i].arg) {
1340 protos[i].enabled = 1;
1341 found = 1;
1342 }
1343 }
1344 if (!found)
1345 usage();
1346 }
1347 }
1348
1349 log_init(debug);
1350
1351 if (!debug) {
1352 int pid;
1353 char *spid;
1354 if (daemon(0, 0) != 0)
1355 fatal("failed to detach daemon");
1356 if ((pid = open(LLDPD_PID_FILE,
1357 O_TRUNC | O_CREAT | O_WRONLY)) == -1)
1358 fatal("unable to open pid file " LLDPD_PID_FILE);
1359 if (asprintf(&spid, "%d\n", getpid()) == -1)
1360 fatal("unable to create pid file " LLDPD_PID_FILE);
1361 if (write(pid, spid, strlen(spid)) == -1)
1362 fatal("unable to write pid file " LLDPD_PID_FILE);
1363 free(spid);
1364 close(pid);
1365 }
1366
1367 priv_init(PRIVSEP_CHROOT);
1368
1369 if (probe == 0) probe = LLDPD_TTL;
1370
1371 if ((cfg = (struct lldpd *)
1372 calloc(1, sizeof(struct lldpd))) == NULL)
1373 fatal(NULL);
1374
1375 cfg->g_mgmt_pattern = mgmtp;
1376 cfg->g_listen_vlans = vlan;
1377
1378 /* Get ioctl socket */
1379 if ((cfg->g_sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
1380 fatal("failed to get ioctl socket");
1381 cfg->g_delay = LLDPD_TX_DELAY;
1382
1383 /* Set system capabilities */
1384 cfg->g_lchassis.c_cap_available = LLDP_CAP_BRIDGE | LLDP_CAP_WLAN |
1385 LLDP_CAP_ROUTER;
1386
1387 /* Set TTL */
1388 cfg->g_lchassis.c_ttl = LLDPD_TTL;
1389
1390 cfg->g_protocols = protos;
1391 cfg->g_probe_time = probe;
1392 for (i=0; protos[i].mode != 0; i++)
1393 if (protos[i].enabled) {
1394 cfg->g_multi++;
1395 LLOG_INFO("protocol %s enabled", protos[i].name);
1396 } else
1397 LLOG_INFO("protocol %s disabled", protos[i].name);
1398 cfg->g_multi--;
1399
1400 TAILQ_INIT(&cfg->g_hardware);
1401 TAILQ_INIT(&cfg->g_vif);
1402
1403 #ifdef USE_SNMP
1404 if (snmp) {
1405 cfg->g_snmp = 1;
1406 agent_init(cfg, debug);
1407 }
1408 #endif /* USE_SNMP */
1409
1410 /* Create socket */
1411 if ((cfg->g_ctl = priv_ctl_create(cfg)) == -1)
1412 fatalx("unable to create control socket " LLDPD_CTL_SOCKET);
1413 TAILQ_INIT(&cfg->g_clients);
1414
1415 gcfg = cfg;
1416 if (atexit(lldpd_exit) != 0) {
1417 close(cfg->g_ctl);
1418 priv_ctl_cleanup();
1419 fatal("unable to set exit function");
1420 }
1421
1422 /* Signal handling */
1423 signal(SIGHUP, lldpd_shutdown);
1424 signal(SIGINT, lldpd_shutdown);
1425 signal(SIGTERM, lldpd_shutdown);
1426
1427 for (;;)
1428 lldpd_loop(cfg);
1429
1430 return (0);
1431 }