]> git.ipfire.org Git - thirdparty/lldpd.git/blob - src/lldpd.c
Allow to send LLDP-MED location.
[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 <ifaddrs.h>
36 #include <net/if_arp.h>
37 #include <linux/filter.h>
38 #include <linux/if_vlan.h>
39 #include <linux/if_packet.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 #ifdef ENABLE_FDP
69 /* "ether dst 01:e0:52:cc:cc:cc" */
70 #define LLDPD_FILTER_FDP_F \
71 { 0x20, 0, 0, 0x00000002 }, \
72 { 0x15, 0, 3, 0x52cccccc }, \
73 { 0x28, 0, 0, 0x00000000 }, \
74 { 0x15, 0, 1, 0x000001e0 }, \
75 { 0x6, 0, 0, 0x0000ffff }, \
76 { 0x6, 0, 0, 0x00000000 },
77 struct sock_filter lldpd_filter_fdp_f[] = { LLDPD_FILTER_FDP_F };
78 #endif /* ENABLE_FDP */
79 #ifdef ENABLE_CDP
80 /* "ether dst 01:00:0c:cc:cc:cc" */
81 #define LLDPD_FILTER_CDP_F \
82 { 0x20, 0, 0, 0x00000002 }, \
83 { 0x15, 0, 3, 0x0ccccccc }, \
84 { 0x28, 0, 0, 0x00000000 }, \
85 { 0x15, 0, 1, 0x00000100 }, \
86 { 0x6, 0, 0, 0x0000ffff }, \
87 { 0x6, 0, 0, 0x00000000 },
88 struct sock_filter lldpd_filter_cdp_f[] = { LLDPD_FILTER_CDP_F };
89 #endif /* ENABLE_CDP */
90 #ifdef ENABLE_SONMP
91 /* "ether dst 01:00:81:00:01:00" */
92 #define LLDPD_FILTER_SONMP_F \
93 { 0x20, 0, 0, 0x00000002 }, \
94 { 0x15, 0, 3, 0x81000100 }, \
95 { 0x28, 0, 0, 0x00000000 }, \
96 { 0x15, 0, 1, 0x00000100 }, \
97 { 0x6, 0, 0, 0x0000ffff }, \
98 { 0x6, 0, 0, 0x00000000 },
99 struct sock_filter lldpd_filter_sonmp_f[] = { LLDPD_FILTER_SONMP_F };
100 #endif /* ENABLE_SONMP */
101 #ifdef ENABLE_EDP
102 /* "ether dst 00:e0:2b:00:00:00" */
103 #define LLDPD_FILTER_EDP_F \
104 { 0x20, 0, 0, 0x00000002 }, \
105 { 0x15, 0, 3, 0x2b000000 }, \
106 { 0x28, 0, 0, 0x00000000 }, \
107 { 0x15, 0, 1, 0x000000e0 }, \
108 { 0x6, 0, 0, 0x0000ffff }, \
109 { 0x6, 0, 0, 0x00000000 },
110 #endif /* ENABLE_EDP */
111 struct sock_filter lldpd_filter_edp_f[] = { LLDPD_FILTER_EDP_F };
112 #define LLDPD_FILTER_ANY_F \
113 { 0x28, 0, 0, 0x0000000c }, \
114 { 0x15, 0, 4, 0x000088cc }, \
115 { 0x20, 0, 0, 0x00000002 }, \
116 { 0x15, 0, 2, 0xc200000e }, \
117 { 0x28, 0, 0, 0x00000000 }, \
118 { 0x15, 11, 12, 0x00000180 }, \
119 { 0x20, 0, 0, 0x00000002 }, \
120 { 0x15, 0, 2, 0x2b000000 }, \
121 { 0x28, 0, 0, 0x00000000 }, \
122 { 0x15, 7, 8, 0x000000e0 }, \
123 { 0x15, 1, 0, 0x0ccccccc }, \
124 { 0x15, 0, 2, 0x81000100 }, \
125 { 0x28, 0, 0, 0x00000000 }, \
126 { 0x15, 3, 4, 0x00000100 }, \
127 { 0x15, 0, 3, 0x52cccccc }, \
128 { 0x28, 0, 0, 0x00000000 }, \
129 { 0x15, 0, 1, 0x000001e0 }, \
130 { 0x6, 0, 0, 0x0000ffff }, \
131 { 0x6, 0, 0, 0x00000000 },
132 struct sock_filter lldpd_filter_any_f[] = { LLDPD_FILTER_ANY_F };
133
134 struct protocol protos[] =
135 {
136 { LLDPD_MODE_LLDP, 1, "LLDP", ' ', lldp_send, lldp_decode, NULL,
137 LLDP_MULTICAST_ADDR, lldpd_filter_lldp_f, sizeof(lldpd_filter_lldp_f) },
138 #ifdef ENABLE_CDP
139 { LLDPD_MODE_CDPV1, 0, "CDPv1", 'c', cdpv1_send, cdp_decode, cdpv1_guess,
140 CDP_MULTICAST_ADDR, lldpd_filter_cdp_f, sizeof(lldpd_filter_cdp_f) },
141 { LLDPD_MODE_CDPV2, 0, "CDPv2", 'c', cdpv2_send, cdp_decode, cdpv2_guess,
142 CDP_MULTICAST_ADDR, lldpd_filter_cdp_f, sizeof(lldpd_filter_cdp_f) },
143 #endif
144 #ifdef ENABLE_SONMP
145 { LLDPD_MODE_SONMP, 0, "SONMP", 's', sonmp_send, sonmp_decode, NULL,
146 SONMP_MULTICAST_ADDR, lldpd_filter_sonmp_f, sizeof(lldpd_filter_sonmp_f) },
147 #endif
148 #ifdef ENABLE_EDP
149 { LLDPD_MODE_EDP, 0, "EDP", 'e', edp_send, edp_decode, NULL,
150 EDP_MULTICAST_ADDR, lldpd_filter_edp_f, sizeof(lldpd_filter_edp_f) },
151 #endif
152 #ifdef ENABLE_FDP
153 { LLDPD_MODE_FDP, 0, "FDP", 'f', fdp_send, cdp_decode, NULL,
154 FDP_MULTICAST_ADDR, lldpd_filter_fdp_f, sizeof(lldpd_filter_fdp_f) },
155 #endif
156 { 0, 0, "any", ' ', NULL, NULL, NULL,
157 {0,0,0,0,0,0}, lldpd_filter_any_f, sizeof(lldpd_filter_any_f) }
158 };
159
160 int lldpd_iface_switchto(struct lldpd *, short int,
161 struct lldpd_hardware *);
162 struct lldpd_hardware *lldpd_port_add(struct lldpd *, struct ifaddrs *);
163 void lldpd_loop(struct lldpd *);
164 void lldpd_shutdown(int);
165 void lldpd_exit();
166 void lldpd_send_all(struct lldpd *);
167 void lldpd_recv_all(struct lldpd *);
168 int lldpd_guess_type(struct lldpd *, char *, int);
169 void lldpd_decode(struct lldpd *, char *, int,
170 struct lldpd_hardware *, int);
171 #ifdef ENABLE_LLDPMED
172 void lldpd_med(struct lldpd_chassis *);
173 #endif
174
175 char **saved_argv;
176
177 void
178 usage(void)
179 {
180 extern const char *__progname;
181 fprintf(stderr, "usage: %s [options]\n", __progname);
182 fprintf(stderr, "see manual page lldpd(8) for more information\n");
183 exit(1);
184 }
185
186 void
187 lldpd_iface_init_mtu(struct lldpd *global, struct lldpd_hardware *hardware)
188 {
189 struct ifreq ifr;
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
201 int
202 lldpd_iface_init_vlan(struct lldpd *global, struct lldpd_vif *vif)
203 {
204 int status;
205 short int filter;
206
207 lldpd_iface_init_mtu(global, (struct lldpd_hardware*)vif);
208 status = priv_iface_init((struct lldpd_hardware*)vif, -1);
209 if (status != 0)
210 return status;
211
212 if (global->g_multi)
213 filter = LLDPD_MODE_ANY;
214 else
215 filter = LLDPD_MODE_LLDP;
216
217 if (lldpd_iface_switchto(global, filter,
218 (struct lldpd_hardware*)vif) == -1) {
219 LLOG_WARNX("unable to apply filter");
220 return ENETDOWN;
221 }
222
223 lldpd_iface_multicast(global, vif->vif_ifname, 0);
224
225 LLOG_DEBUG("vlan interface %s initialized (fd=%d)", vif->vif_ifname,
226 vif->vif_raw);
227 return 0;
228 }
229
230 int
231 lldpd_iface_init(struct lldpd *global, struct lldpd_hardware *hardware)
232 {
233 int master; /* Bond device */
234 char if_bond[IFNAMSIZ];
235 int status;
236 short int filter;
237
238 lldpd_iface_init_mtu(global, hardware);
239 status = priv_iface_init(hardware, -1);
240 if (status != 0)
241 return status;
242
243 if ((master = iface_is_enslaved(global, hardware->h_ifname)) != -1) {
244 /* With bonding device, we need to listen on the bond ! */
245 if (if_indextoname(master, if_bond) == NULL) {
246 LLOG_WARN("unable to get index for interface %d (master of %s)",
247 master, hardware->h_ifname);
248 return ENETDOWN;
249 }
250 hardware->h_raw_real = hardware->h_raw;
251 hardware->h_master = master;
252 hardware->h_raw = -1;
253 status = priv_iface_init(hardware, master);
254 if (status != 0) {
255 close(hardware->h_raw_real);
256 if (hardware->h_raw != -1)
257 close(hardware->h_raw);
258 return status;
259 }
260 }
261
262 if (global->g_multi)
263 filter = LLDPD_MODE_ANY;
264 else
265 filter = LLDPD_MODE_LLDP;
266 if (lldpd_iface_switchto(global, filter, hardware) == -1) {
267 LLOG_WARNX("unable to apply filter");
268 return ENETDOWN;
269 }
270
271 if (master != -1)
272 lldpd_iface_multicast(global, if_bond, 0);
273 lldpd_iface_multicast(global, hardware->h_ifname, 0);
274
275 LLOG_DEBUG("interface %s initialized (fd=%d)", hardware->h_ifname,
276 hardware->h_raw);
277 return 0;
278 }
279
280 void
281 lldpd_iface_multicast(struct lldpd *global, const char *name, int remove)
282 {
283 int i, rc;
284
285 for (i=0; global->g_protocols[i].mode != 0; i++) {
286 if (!global->g_protocols[i].enabled) continue;
287 if ((rc = priv_iface_multicast(name,
288 global->g_protocols[i].mac, !remove)) != 0) {
289 errno = rc;
290 if (errno != ENOENT)
291 LLOG_INFO("unable to %s %s address to multicast filter for %s",
292 (remove)?"delete":"add",
293 global->g_protocols[i].name,
294 name);
295 }
296 }
297 }
298
299 int
300 lldpd_iface_close(struct lldpd *global, struct lldpd_hardware *hardware)
301 {
302 char listen[IFNAMSIZ];
303
304 close(hardware->h_raw);
305 hardware->h_raw = -1;
306
307 if (hardware->h_raw_real > 0) {
308 if (if_indextoname(hardware->h_master, listen) == NULL) {
309 LLOG_WARN("unable to get index for interface %d",
310 hardware->h_master);
311 strlcpy(listen, hardware->h_ifname, sizeof(listen));
312 }
313 close(hardware->h_raw_real);
314 lldpd_iface_multicast(global, listen, 1);
315 }
316 strlcpy(listen, hardware->h_ifname, sizeof(listen));
317 lldpd_iface_multicast(global, listen, 1);
318
319 hardware->h_raw_real = -1;
320 return 0;
321 }
322
323 int
324 lldpd_iface_switchto(struct lldpd *cfg, short int filter, struct lldpd_hardware *hardware)
325 {
326 struct sock_fprog prog;
327 int i;
328
329 memset(&prog, 0, sizeof(prog));
330 for (i=0; cfg->g_protocols[i].mode != 0; i++) {
331 if (!cfg->g_protocols[i].enabled) continue;
332 if (cfg->g_protocols[i].mode == filter)
333 break;
334 }
335 prog.filter = cfg->g_protocols[i].filter;
336 prog.len = cfg->g_protocols[i].filterlen / sizeof(struct sock_filter);
337 if (setsockopt(hardware->h_raw, SOL_SOCKET, SO_ATTACH_FILTER,
338 &prog, sizeof(prog)) < 0) {
339 LLOG_WARN("unable to change filter for %s", hardware->h_ifname);
340 return -1;
341 }
342 if ((hardware->h_raw_real > 0) &&
343 (setsockopt(hardware->h_raw_real, SOL_SOCKET, SO_ATTACH_FILTER,
344 &prog, sizeof(prog)) < 0)) {
345 LLOG_WARN("unable to change filter for real device %s", hardware->h_ifname);
346 return -1;
347 }
348 return 0;
349 }
350
351 #ifdef ENABLE_DOT1
352 void
353 lldpd_vlan_cleanup(struct lldpd_port *port)
354 {
355 struct lldpd_vlan *vlan, *vlan_next;
356 for (vlan = TAILQ_FIRST(&port->p_vlans);
357 vlan != NULL;
358 vlan = vlan_next) {
359 free(vlan->v_name);
360 vlan_next = TAILQ_NEXT(vlan, v_entries);
361 TAILQ_REMOVE(&port->p_vlans, vlan, v_entries);
362 free(vlan);
363 }
364 }
365 #endif
366
367 void
368 lldpd_port_cleanup(struct lldpd_port *port)
369 {
370 #ifdef ENABLE_DOT1
371 lldpd_vlan_cleanup(port);
372 #endif
373 free(port->p_id);
374 free(port->p_descr);
375 free(port);
376 }
377
378 void
379 lldpd_chassis_cleanup(struct lldpd_chassis *chassis)
380 {
381 #ifdef ENABLE_LLDPMED
382 int i;
383 free(chassis->c_med_hw);
384 free(chassis->c_med_fw);
385 free(chassis->c_med_sn);
386 free(chassis->c_med_manuf);
387 free(chassis->c_med_model);
388 free(chassis->c_med_asset);
389 for (i=0; i < LLDPMED_LOCFORMAT_LAST; i++)
390 free(chassis->c_med_location[i].data);
391 #endif
392 free(chassis->c_id);
393 free(chassis->c_name);
394 free(chassis->c_descr);
395 free(chassis);
396 }
397
398 void
399 lldpd_remote_cleanup(struct lldpd *cfg, struct lldpd_hardware *hardware, int reset)
400 {
401 if (hardware->h_rport != NULL) {
402 lldpd_port_cleanup(hardware->h_rport);
403 hardware->h_rport = NULL;
404 }
405 if (hardware->h_rchassis != NULL) {
406 lldpd_chassis_cleanup(hardware->h_rchassis);
407 hardware->h_rchassis = NULL;
408 }
409 hardware->h_rlastchange = hardware->h_rlastupdate = 0;
410 free(hardware->h_rlastframe);
411 hardware->h_rlastframe = NULL;
412 if (reset && cfg->g_multi) {
413 hardware->h_mode = LLDPD_MODE_ANY;
414 memset(hardware->h_proto_macs, 0, ETH_ALEN*(cfg->g_multi+1));
415 hardware->h_start_probe = 0;
416 lldpd_iface_switchto(cfg, LLDPD_MODE_ANY, hardware);
417 }
418 }
419
420 void
421 lldpd_hardware_cleanup(struct lldpd_hardware *hardware)
422 {
423 #ifdef ENABLE_DOT1
424 lldpd_vlan_cleanup(&hardware->h_lport);
425 #endif
426 free(hardware->h_proto_macs);
427 free(hardware->h_llastframe);
428 free(hardware);
429 }
430
431 void
432 lldpd_cleanup(struct lldpd *cfg)
433 {
434 struct lldpd_hardware *hardware, *hardware_next;
435 struct lldpd_vif *vif, *vif_next;
436
437 for (hardware = TAILQ_FIRST(&cfg->g_hardware); hardware != NULL;
438 hardware = hardware_next) {
439 hardware_next = TAILQ_NEXT(hardware, h_entries);
440 if (hardware->h_flags == 0) {
441 TAILQ_REMOVE(&cfg->g_hardware, hardware, h_entries);
442 lldpd_iface_close(cfg, hardware);
443 lldpd_remote_cleanup(cfg, hardware, 1);
444 lldpd_hardware_cleanup(hardware);
445 } else if (hardware->h_rchassis != NULL) {
446 if (time(NULL) - hardware->h_rlastupdate >
447 hardware->h_rchassis->c_ttl) {
448 lldpd_remote_cleanup(cfg, hardware, 1);
449 hardware->h_rx_ageout_cnt++;
450 }
451 }
452 }
453 for (vif = TAILQ_FIRST(&cfg->g_vif); vif != NULL;
454 vif = vif_next) {
455 vif_next = TAILQ_NEXT(vif, vif_entries);
456 if (vif->vif_flags == 0) {
457 TAILQ_REMOVE(&cfg->g_vif, vif, vif_entries);
458 lldpd_iface_close(cfg, (struct lldpd_hardware*)vif);
459 free(vif);
460 }
461 }
462 }
463
464 struct lldpd_vif *
465 lldpd_port_add_vlan(struct lldpd *cfg, struct ifaddrs *ifa)
466 {
467 struct lldpd_vif *vif;
468 struct lldpd_hardware *hardware;
469 struct vlan_ioctl_args ifv;
470
471 TAILQ_FOREACH(vif, &cfg->g_vif, vif_entries) {
472 if (strcmp(vif->vif_ifname, ifa->ifa_name) == 0)
473 break;
474 }
475
476 if (vif == NULL) {
477 if ((vif = (struct lldpd_vif *)
478 calloc(1, sizeof(struct lldpd_vif))) == NULL)
479 return NULL;
480 vif->vif_raw = -1;
481 vif->vif_raw_real = -1;
482 }
483 strlcpy(vif->vif_ifname, ifa->ifa_name, sizeof(vif->vif_ifname));
484 vif->vif_flags = ifa->ifa_flags;
485
486 if (vif->vif_raw == -1) {
487
488 if (lldpd_iface_init_vlan(cfg, vif) != 0) {
489 free(vif);
490 return NULL;
491 }
492
493 /* Find the real interface */
494 vif->vif_real = NULL;
495 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
496 memset(&ifv, 0, sizeof(ifv));
497 ifv.cmd = GET_VLAN_REALDEV_NAME_CMD;
498 strlcpy(ifv.device1, ifa->ifa_name, sizeof(ifv.device1));
499 if ((ioctl(cfg->g_sock, SIOCGIFVLAN, &ifv) >= 0) &&
500 (strncmp(hardware->h_ifname,
501 ifv.u.device2,
502 sizeof(ifv.u.device2)) == 0))
503 vif->vif_real = hardware;
504 }
505 if (vif->vif_real == NULL) {
506 LLOG_WARNX("unable to find real interface for %s",
507 ifa->ifa_name);
508 free(vif);
509 return NULL;
510 }
511
512 TAILQ_INSERT_TAIL(&cfg->g_vif, vif, vif_entries);
513 }
514
515 return vif;
516 }
517
518 struct lldpd_hardware *
519 lldpd_port_add(struct lldpd *cfg, struct ifaddrs *ifa)
520 {
521 #if defined (ENABLE_DOT1) || defined (ENABLE_DOT3)
522 struct ifaddrs *oifap, *oifa;
523 #endif
524 struct lldpd_hardware *hardware;
525 struct lldpd_port *port;
526 #ifdef ENABLE_DOT1
527 struct lldpd_vlan *vlan;
528 struct vlan_ioctl_args ifv;
529 #endif
530 #ifdef ENABLE_DOT3
531 struct ethtool_cmd ethc;
532 #endif
533 u_int8_t *lladdr;
534
535 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
536 if (strcmp(hardware->h_ifname, ifa->ifa_name) == 0)
537 break;
538 }
539
540 if (hardware == NULL) {
541 if ((hardware = (struct lldpd_hardware *)
542 calloc(1, sizeof(struct lldpd_hardware))) == NULL)
543 return (NULL);
544 hardware->h_raw = -1;
545 hardware->h_raw_real = -1;
546 hardware->h_start_probe = 0;
547 hardware->h_proto_macs = (u_int8_t*)calloc(cfg->g_multi+1, ETH_ALEN);
548 #ifdef ENABLE_DOT1
549 TAILQ_INIT(&hardware->h_lport.p_vlans);
550 } else {
551 lldpd_vlan_cleanup(&hardware->h_lport);
552 #endif
553 }
554
555 port = &hardware->h_lport;
556 hardware->h_flags = ifa->ifa_flags;
557
558 strlcpy(hardware->h_ifname, ifa->ifa_name, sizeof(hardware->h_ifname));
559 lladdr = (u_int8_t*)(((struct sockaddr_ll *)ifa->ifa_addr)->sll_addr);
560 memcpy(&hardware->h_lladdr, lladdr, sizeof(hardware->h_lladdr));
561 iface_get_permanent_mac(cfg, hardware);
562 port->p_id_subtype = LLDP_PORTID_SUBTYPE_LLADDR;
563 if ((port->p_id = calloc(1, sizeof(hardware->h_lladdr))) == NULL)
564 fatal(NULL);
565 memcpy(port->p_id, hardware->h_lladdr, sizeof(hardware->h_lladdr));
566 port->p_id_len = sizeof(hardware->h_lladdr);
567 port->p_descr = hardware->h_ifname;
568
569 if (cfg->g_lchassis.c_id == NULL) {
570 /* Use the first port's l2 addr as the chassis ID */
571 if ((cfg->g_lchassis.c_id = malloc(sizeof(hardware->h_lladdr))) == NULL)
572 fatal(NULL);
573 cfg->g_lchassis.c_id_subtype = LLDP_CHASSISID_SUBTYPE_LLADDR;
574 cfg->g_lchassis.c_id_len = sizeof(hardware->h_lladdr);
575 memcpy(cfg->g_lchassis.c_id,
576 hardware->h_lladdr, sizeof(hardware->h_lladdr));
577 }
578
579 /* Get VLANS and aggregation status */
580 #if defined (ENABLE_DOT3) || defined (ENABLE_DOT1)
581 if (getifaddrs(&oifap) != 0)
582 fatal("lldpd_port_add: failed to get interface list");
583 for (oifa = oifap; oifa != NULL; oifa = oifa->ifa_next) {
584 #ifdef ENABLE_DOT1
585 /* Check if we already have checked this one */
586 int skip = 0;
587 TAILQ_FOREACH(vlan, &port->p_vlans, v_entries) {
588 if (strcmp(vlan->v_name, oifa->ifa_name) == 0)
589 skip = 1;
590 }
591 if (skip) continue;
592 #endif
593
594 /* Aggregation check */
595 #ifdef ENABLE_DOT3
596 if (iface_is_bond_slave(cfg, hardware->h_ifname, oifa->ifa_name, NULL))
597 port->p_aggregid = if_nametoindex(oifa->ifa_name);
598 #endif
599
600 #ifdef ENABLE_DOT1
601 /* VLAN check */
602 memset(&ifv, 0, sizeof(ifv));
603 ifv.cmd = GET_VLAN_REALDEV_NAME_CMD;
604 strlcpy(ifv.device1, oifa->ifa_name, sizeof(ifv.device1));
605 if ((ioctl(cfg->g_sock, SIOCGIFVLAN, &ifv) >= 0) &&
606 ((iface_is_bond_slave(cfg, hardware->h_ifname, ifv.u.device2, NULL)) ||
607 (strncmp(hardware->h_ifname, ifv.u.device2, sizeof(ifv.u.device2)) == 0))) {
608 if ((vlan = (struct lldpd_vlan *)
609 calloc(1, sizeof(struct lldpd_vlan))) == NULL)
610 continue;
611 if ((vlan->v_name = strdup(oifa->ifa_name)) == NULL) {
612 free(vlan);
613 continue;
614 }
615 memset(&ifv, 0, sizeof(ifv));
616 ifv.cmd = GET_VLAN_VID_CMD;
617 strlcpy(ifv.device1, oifa->ifa_name, sizeof(ifv.device1));
618 if (ioctl(cfg->g_sock, SIOCGIFVLAN, &ifv) < 0) {
619 /* Dunno what happened */
620 free(vlan->v_name);
621 free(vlan);
622 } else {
623 vlan->v_vid = ifv.u.VID;
624 TAILQ_INSERT_TAIL(&port->p_vlans, vlan, v_entries);
625 }
626 }
627 #endif
628 }
629 freeifaddrs(oifap);
630 #endif
631
632 #ifdef ENABLE_DOT3
633 /* MAC/PHY */
634 if (priv_ethtool(hardware->h_ifname, &ethc) == 0) {
635 int j;
636 int advertised_ethtool_to_rfc3636[][2] = {
637 {ADVERTISED_10baseT_Half, LLDP_DOT3_LINK_AUTONEG_10BASE_T},
638 {ADVERTISED_10baseT_Full, LLDP_DOT3_LINK_AUTONEG_10BASET_FD},
639 {ADVERTISED_100baseT_Half, LLDP_DOT3_LINK_AUTONEG_100BASE_TX},
640 {ADVERTISED_100baseT_Full, LLDP_DOT3_LINK_AUTONEG_100BASE_TXFD},
641 {ADVERTISED_1000baseT_Half, LLDP_DOT3_LINK_AUTONEG_1000BASE_T},
642 {ADVERTISED_1000baseT_Full, LLDP_DOT3_LINK_AUTONEG_1000BASE_TFD},
643 {ADVERTISED_10000baseT_Full, LLDP_DOT3_LINK_AUTONEG_OTHER},
644 {ADVERTISED_Pause, LLDP_DOT3_LINK_AUTONEG_FDX_PAUSE},
645 {ADVERTISED_Asym_Pause, LLDP_DOT3_LINK_AUTONEG_FDX_APAUSE},
646 {ADVERTISED_2500baseX_Full, LLDP_DOT3_LINK_AUTONEG_OTHER},
647 {0,0}};
648
649 port->p_autoneg_support = (ethc.supported & SUPPORTED_Autoneg) ? 1 : 0;
650 port->p_autoneg_enabled = (ethc.autoneg == AUTONEG_DISABLE) ? 0 : 1;
651 for (j=0; advertised_ethtool_to_rfc3636[j][0]; j++) {
652 if (ethc.advertising & advertised_ethtool_to_rfc3636[j][0])
653 port->p_autoneg_advertised |= advertised_ethtool_to_rfc3636[j][1];
654 }
655 switch (ethc.speed) {
656 case SPEED_10:
657 port->p_mau_type = (ethc.duplex == DUPLEX_FULL) ? \
658 LLDP_DOT3_MAU_10BASETFD : LLDP_DOT3_MAU_10BASETHD;
659 if (ethc.port == PORT_BNC) port->p_mau_type = LLDP_DOT3_MAU_10BASE2;
660 if (ethc.port == PORT_FIBRE)
661 port->p_mau_type = (ethc.duplex == DUPLEX_FULL) ? \
662 LLDP_DOT3_MAU_10BASEFLDF : LLDP_DOT3_MAU_10BASEFLHD;
663 break;
664 case SPEED_100:
665 port->p_mau_type = (ethc.duplex == DUPLEX_FULL) ? \
666 LLDP_DOT3_MAU_100BASETXFD : LLDP_DOT3_MAU_100BASETXHD;
667 if (ethc.port == PORT_BNC)
668 port->p_mau_type = (ethc.duplex == DUPLEX_FULL) ? \
669 LLDP_DOT3_MAU_100BASET2DF : LLDP_DOT3_MAU_100BASET2HD;
670 if (ethc.port == PORT_FIBRE)
671 port->p_mau_type = (ethc.duplex == DUPLEX_FULL) ? \
672 LLDP_DOT3_MAU_100BASEFXFD : LLDP_DOT3_MAU_100BASEFXHD;
673 break;
674 case SPEED_1000:
675 port->p_mau_type = (ethc.duplex == DUPLEX_FULL) ? \
676 LLDP_DOT3_MAU_1000BASETFD : LLDP_DOT3_MAU_1000BASETHD;
677 if (ethc.port == PORT_FIBRE)
678 port->p_mau_type = (ethc.duplex == DUPLEX_FULL) ? \
679 LLDP_DOT3_MAU_1000BASEXFD : LLDP_DOT3_MAU_1000BASEXHD;
680 break;
681 case SPEED_10000:
682 port->p_mau_type = (ethc.port == PORT_FIBRE) ? \
683 LLDP_DOT3_MAU_10GIGBASEX : LLDP_DOT3_MAU_10GIGBASER;
684 break;
685 }
686 if (ethc.port == PORT_AUI) port->p_mau_type = LLDP_DOT3_MAU_AUI;
687 } else
688 LLOG_DEBUG("unable to get eth info for %s", hardware->h_ifname);
689 #endif
690
691 if (!INTERFACE_OPENED(hardware)) {
692
693 if (lldpd_iface_init(cfg, hardware) != 0) {
694 LLOG_WARN("unable to initialize %s", hardware->h_ifname);
695 lldpd_hardware_cleanup(hardware);
696 return (NULL);
697 }
698
699 TAILQ_INSERT_TAIL(&cfg->g_hardware, hardware, h_entries);
700 }
701
702 return (hardware);
703 }
704
705 int
706 lldpd_guess_type(struct lldpd *cfg, char *frame, int s)
707 {
708 int i;
709 if (s < ETH_ALEN)
710 return -1;
711 for (i=0; cfg->g_protocols[i].mode != 0; i++) {
712 if (!cfg->g_protocols[i].enabled)
713 continue;
714 if (cfg->g_protocols[i].guess == NULL) {
715 if (memcmp(frame, cfg->g_protocols[i].mac, ETH_ALEN) == 0)
716 return cfg->g_protocols[i].mode;
717 } else {
718 if (cfg->g_protocols[i].guess(frame, s))
719 return cfg->g_protocols[i].mode;
720 }
721 }
722 return -1;
723 }
724
725 void
726 lldpd_decode(struct lldpd *cfg, char *frame, int s,
727 struct lldpd_hardware *hardware, int bond)
728 {
729 int result = 0, i, j, candidatetonull;
730 u_int8_t nullmac[ETH_ALEN] = {0,0,0,0,0,0};
731 u_int8_t broadcastmac[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff};
732 struct lldpd_chassis *chassis;
733 struct lldpd_port *port;
734 struct lldpd_hardware *ohardware, *firstnull = NULL, *older = NULL;
735 int guess = LLDPD_MODE_LLDP;
736
737 /* Discard VLAN frames */
738 if ((s >= sizeof(struct ieee8023)) &&
739 (((struct ieee8023*)frame)->size == htons(ETHERTYPE_VLAN)))
740 return;
741
742 if ((hardware->h_rlastframe != NULL) &&
743 (hardware->h_rlastframe->size == s) &&
744 (memcmp(hardware->h_rlastframe->frame, frame, s) == 0)) {
745 /* Already received the same frame */
746 hardware->h_rlastupdate = time(NULL);
747 return;
748 }
749
750 if (cfg->g_multi) {
751 if (hardware->h_mode == LLDPD_MODE_ANY)
752 guess = lldpd_guess_type(cfg, frame, s);
753 else
754 guess = hardware->h_mode;
755 for (i=0; cfg->g_protocols[i].mode != 0; i++) {
756 if (!cfg->g_protocols[i].enabled)
757 continue;
758 if (cfg->g_protocols[i].mode == guess) {
759 if ((result = cfg->g_protocols[i].decode(cfg, frame,
760 s, hardware, &chassis, &port)) == -1)
761 return;
762 break;
763 }
764 }
765 if (cfg->g_protocols[i].mode == 0) {
766 LLOG_INFO("unable to guess frame type");
767 return;
768 }
769 } else if (cfg->g_protocols[0].decode(cfg, frame, s, hardware,
770 &chassis, &port) == -1)
771 /* Nothing has been received */
772 return;
773
774 if (bond) {
775 /* Eh, wait ! The frame we just received was for a bonding
776 * device. We need to attach it to a real device. What is the
777 * best candidate? Drum rolling... */
778 TAILQ_FOREACH(ohardware, &cfg->g_hardware, h_entries) {
779 if (ohardware->h_master == hardware->h_master) {
780 /* Same bond */
781 if (ohardware->h_rchassis == NULL) {
782 candidatetonull = 1;
783 if (cfg->g_multi &&
784 (ohardware->h_mode == LLDPD_MODE_ANY)) {
785 for (i=j=0;
786 cfg->g_protocols[i].mode != 0;
787 i++) {
788 if (!cfg->g_protocols[i].enabled)
789 continue;
790 if ((cfg->g_protocols[i].mode == guess) &&
791 (memcmp(frame + ETH_ALEN,
792 ohardware->h_proto_macs + ETH_ALEN*j,
793 ETH_ALEN) == 0)) {
794 hardware = ohardware;
795 bond = 0;
796 break;
797 }
798 j++;
799 }
800 if (!bond) break;
801 if (firstnull != NULL) {
802 for (i=j=0;
803 cfg->g_protocols[i].mode != 0;
804 i++) {
805 if (!cfg->g_protocols[i].enabled)
806 continue;
807 if ((cfg->g_protocols[i].mode == guess) &&
808 (memcmp(nullmac,
809 ohardware->h_proto_macs +
810 ETH_ALEN*j,
811 ETH_ALEN) != 0)) {
812 /* We need to
813 * find a better
814 * candidate */
815 candidatetonull = 0;
816 break;
817 }
818 j++;
819 }
820 }
821 }
822 /* Ok, this is the first candidate if we
823 * don't find a matching chassis/port */
824 if (candidatetonull) firstnull = ohardware;
825 continue;
826 }
827 if ((older == NULL) ||
828 (older->h_rlastupdate > ohardware->h_rlastupdate))
829 /* If there is no matching chassis/port
830 * and no free hardware, we will use
831 * this one. */
832 older = ohardware;
833 if ((chassis->c_id_subtype !=
834 ohardware->h_rchassis->c_id_subtype) ||
835 (chassis->c_id_len != ohardware->h_rchassis->c_id_len) ||
836 (memcmp(chassis->c_id, ohardware->h_rchassis->c_id,
837 chassis->c_id_len) != 0) ||
838 (port->p_id_subtype != ohardware->h_rport->p_id_subtype) ||
839 (port->p_id_len != ohardware->h_rport->p_id_len) ||
840 (memcmp(port->p_id, ohardware->h_rport->p_id,
841 port->p_id_len) != 0))
842 continue;
843 /* We got a match! */
844 hardware = ohardware; /* We switch hardware */
845 bond = 0;
846 break;
847 }
848 }
849 if (bond) {
850 /* No match found */
851 if (firstnull != NULL)
852 hardware = firstnull;
853 else hardware = older;
854 }
855 }
856
857 if (cfg->g_multi &&
858 (hardware->h_mode == LLDPD_MODE_ANY)) {
859 u_int8_t *mac;
860 char *modename;
861 int filter;
862
863 for (i=j=0; cfg->g_protocols[i].mode != 0; i++) {
864 if (!cfg->g_protocols[i].enabled)
865 continue;
866 if (cfg->g_protocols[i].mode == guess) {
867 mac = hardware->h_proto_macs + ETH_ALEN*j;
868 modename = cfg->g_protocols[i].name;
869 filter = cfg->g_protocols[i].mode;
870 break;
871 }
872 j++;
873 }
874 if (cfg->g_protocols[i].mode == 0) {
875 LLOG_WARNX("should not be there");
876 goto cleanup;
877 }
878
879 if (hardware->h_start_probe == 0)
880 hardware->h_start_probe = time(NULL) - 1;
881 /* Handle switching respecting probe time */
882 if ((memcmp(mac, frame + ETH_ALEN, ETH_ALEN) == 0) &&
883 ((time(NULL) - hardware->h_start_probe) > cfg->g_probe_time) &&
884 /* Don't switch to this protocol if not LLDP and LLDP is
885 * a valid candidate */
886 ((filter == LLDPD_MODE_LLDP) ||
887 (memcmp(hardware->h_proto_macs,
888 broadcastmac, ETH_ALEN) == 0) ||
889 (memcmp(hardware->h_proto_macs,
890 nullmac, ETH_ALEN) == 0))) {
891 LLOG_INFO("switching to %s on port %s", modename,
892 hardware->h_ifname);
893 hardware->h_mode = guess;
894 lldpd_iface_switchto(cfg, filter, hardware);
895 } else {
896 /* Wait twice probe time to be able to receive packets of all kind */
897 if ((time(NULL) - hardware->h_start_probe) > cfg->g_probe_time * 2) {
898 LLOG_DEBUG("probe expired on %s, retry", hardware->h_ifname);
899 hardware->h_start_probe = 0;
900 memset(hardware->h_proto_macs, 0, ETH_ALEN*(cfg->g_multi+1));
901 goto cleanup;
902 }
903 if (memcmp(mac, broadcastmac, ETH_ALEN) == 0)
904 goto cleanup;
905 LLOG_INFO("received a %s frame on %s but wait for %d sec",
906 modename, hardware->h_ifname, cfg->g_probe_time - time(NULL) +
907 hardware->h_start_probe);
908 if (memcmp(mac, frame + ETH_ALEN, ETH_ALEN) == 0)
909 goto cleanup;
910 if (memcmp(mac, nullmac, ETH_ALEN) == 0) {
911 memcpy(mac, frame + ETH_ALEN, ETH_ALEN);
912 goto cleanup;
913 }
914 LLOG_INFO("several MAC for %s on %s, discarding %s for this interface",
915 modename, hardware->h_ifname, modename);
916 memcpy(mac, broadcastmac, ETH_ALEN);
917 goto cleanup;
918 }
919 }
920
921 result = 0;
922 if ((hardware->h_rchassis == NULL) ||
923 (chassis->c_id_subtype != hardware->h_rchassis->c_id_subtype) ||
924 (chassis->c_id_len != hardware->h_rchassis->c_id_len) ||
925 (memcmp(chassis->c_id, hardware->h_rchassis->c_id,
926 chassis->c_id_len) != 0))
927 result = 1;
928
929 /* We have our new frame */
930 lldpd_remote_cleanup(cfg, hardware, 0);
931 hardware->h_rport = port;
932 hardware->h_rchassis = chassis;
933 hardware->h_rlastchange = hardware->h_rlastupdate = time(NULL);
934
935 /* We remember this frame */
936 free(hardware->h_rlastframe);
937 if ((hardware->h_rlastframe = (struct lldpd_frame *)malloc(s +
938 sizeof(int))) != NULL) {
939 hardware->h_rlastframe->size = s;
940 memcpy(hardware->h_rlastframe->frame, frame, s);
941 }
942
943 if (result) {
944 /* This is a new remote system */
945 LLOG_DEBUG("we discovered a new remote system on %s",
946 hardware->h_ifname);
947 /* Do we already know this remote system? */
948 TAILQ_FOREACH(ohardware, &cfg->g_hardware, h_entries) {
949 if ((ohardware->h_ifname != hardware->h_ifname) &&
950 (ohardware->h_rchassis != NULL) &&
951 (ohardware->h_rchassis->c_id_subtype ==
952 chassis->c_id_subtype) &&
953 (ohardware->h_rchassis->c_id_len ==
954 chassis->c_id_len) &&
955 (memcmp(ohardware->h_rchassis->c_id,
956 chassis->c_id, chassis->c_id_len) == 0)) {
957 LLOG_DEBUG("but it was already on %s",
958 ohardware->h_ifname);
959 hardware->h_rid = ohardware->h_rid;
960 return;
961 }
962 }
963 hardware->h_rid = ++cfg->g_lastrid;
964 }
965 return;
966
967 cleanup:
968 lldpd_chassis_cleanup(chassis);
969 lldpd_port_cleanup(port);
970 return;
971 }
972
973 void
974 lldpd_recv_all(struct lldpd *cfg)
975 {
976 struct lldpd_hardware *hardware;
977 struct lldpd_vif *vif;
978 struct lldpd_client *client, *client_next;
979 fd_set rfds;
980 struct timeval tv;
981 struct sockaddr_ll from;
982 socklen_t fromlen;
983 int onreal;
984 #ifdef USE_SNMP
985 int fakeblock = 0;
986 struct timeval *tvp = &tv;
987 #endif
988 int rc, nfds, n, bond;
989 char *buffer;
990
991 do {
992 tv.tv_sec = cfg->g_delay - (time(NULL) - cfg->g_lastsent);
993 if (tv.tv_sec < 0)
994 tv.tv_sec = LLDPD_TX_DELAY;
995 if (tv.tv_sec >= cfg->g_delay)
996 tv.tv_sec = cfg->g_delay;
997 tv.tv_usec = 0;
998
999 FD_ZERO(&rfds);
1000 nfds = -1;
1001
1002 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
1003 /* Ignore if interface is down */
1004 if ((hardware->h_flags & IFF_UP) == 0)
1005 continue;
1006 FD_SET(hardware->h_raw, &rfds);
1007 if (nfds < hardware->h_raw)
1008 nfds = hardware->h_raw;
1009 /* Listen to real interface too. In 2.6.27, we can
1010 * receive packets if this is the slave interface. */
1011 if (hardware->h_raw_real > 0) {
1012 FD_SET(hardware->h_raw_real, &rfds);
1013 if (nfds < hardware->h_raw_real)
1014 nfds = hardware->h_raw_real;
1015 }
1016 }
1017 TAILQ_FOREACH(vif, &cfg->g_vif, vif_entries) {
1018 if ((vif->vif_flags & IFF_UP) == 0)
1019 continue;
1020 FD_SET(vif->vif_raw, &rfds);
1021 if (nfds < vif->vif_raw)
1022 nfds = vif->vif_raw;
1023 }
1024 TAILQ_FOREACH(client, &cfg->g_clients, next) {
1025 FD_SET(client->fd, &rfds);
1026 if (nfds < client->fd)
1027 nfds = client->fd;
1028 }
1029 FD_SET(cfg->g_ctl, &rfds);
1030 if (nfds < cfg->g_ctl)
1031 nfds = cfg->g_ctl;
1032
1033 #ifdef USE_SNMP
1034 if (cfg->g_snmp)
1035 snmp_select_info(&nfds, &rfds, tvp, &fakeblock);
1036 #endif /* USE_SNMP */
1037 if (nfds == -1) {
1038 sleep(cfg->g_delay);
1039 return;
1040 }
1041
1042 rc = select(nfds + 1, &rfds, NULL, NULL, &tv);
1043 if (rc == -1) {
1044 if (errno == EINTR)
1045 continue;
1046 LLOG_WARN("failure on select");
1047 break;
1048 }
1049 #ifdef USE_SNMP
1050 if (cfg->g_snmp) {
1051 if (rc > 0)
1052 snmp_read(&rfds);
1053 else if (rc == 0)
1054 snmp_timeout();
1055 }
1056 #endif /* USE_SNMP */
1057 TAILQ_FOREACH(vif, &cfg->g_vif, vif_entries) {
1058 if (!FD_ISSET(vif->vif_raw, &rfds))
1059 continue;
1060 if ((buffer = (char *)malloc(
1061 vif->vif_mtu)) == NULL) {
1062 LLOG_WARN("failed to alloc reception buffer");
1063 continue;
1064 }
1065 fromlen = sizeof(from);
1066 if ((n = recvfrom(vif->vif_raw,
1067 buffer,
1068 vif->vif_mtu, 0,
1069 (struct sockaddr *)&from,
1070 &fromlen)) == -1) {
1071 LLOG_WARN("error while receiving frame on vlan %s",
1072 vif->vif_ifname);
1073 vif->vif_real->h_rx_discarded_cnt++;
1074 free(buffer);
1075 continue;
1076 }
1077 if (from.sll_pkttype == PACKET_OUTGOING) {
1078 free(buffer);
1079 continue;
1080 }
1081 if (!((cfg->g_multi) &&
1082 (vif->vif_real->h_mode != LLDPD_MODE_ANY) &&
1083 (lldpd_guess_type(cfg, buffer, n) !=
1084 vif->vif_real->h_mode))) {
1085 vif->vif_real->h_rx_cnt++;
1086 lldpd_decode(cfg, buffer, n, vif->vif_real, 0);
1087 }
1088
1089 free(buffer);
1090 }
1091 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
1092 /* We could have received something on _real_
1093 * interface. However, even in this case, this could be
1094 * just an outgoing packet. We will try to handle both
1095 * cases, but maybe not in the same select. */
1096 onreal = ((hardware->h_raw_real > 0) &&
1097 (FD_ISSET(hardware->h_raw_real, &rfds)));
1098 if (onreal || (FD_ISSET(hardware->h_raw, &rfds))) {
1099 if ((buffer = (char *)malloc(
1100 hardware->h_mtu)) == NULL) {
1101 LLOG_WARN("failed to alloc reception buffer");
1102 continue;
1103 }
1104 fromlen = sizeof(from);
1105 if ((n = recvfrom(
1106 onreal?hardware->h_raw_real:hardware->h_raw,
1107 buffer,
1108 hardware->h_mtu, 0,
1109 (struct sockaddr *)&from,
1110 &fromlen)) == -1) {
1111 LLOG_WARN("error while receiving frame on %s",
1112 hardware->h_ifname);
1113 hardware->h_rx_discarded_cnt++;
1114 free(buffer);
1115 continue;
1116 }
1117 if (from.sll_pkttype == PACKET_OUTGOING) {
1118 free(buffer);
1119 continue;
1120 }
1121 bond = 0;
1122 /* If received on real interface, we act like if
1123 * this is not a bond! */
1124 if (!onreal && (hardware->h_raw_real > 0)) {
1125 /* Bonding. Is it for the correct
1126 * physical interface ? */
1127 if (from.sll_ifindex == hardware->h_master) {
1128 /* It seems that we don't know from
1129 which physical interface it comes
1130 (kernel < 2.6.24 ?) */
1131 bond = 1;
1132 } else if (from.sll_ifindex !=
1133 if_nametoindex(hardware->h_ifname)) {
1134 free(buffer);
1135 continue;
1136 }
1137 }
1138 hardware->h_rx_cnt++;
1139 lldpd_decode(cfg, buffer, n, hardware, bond);
1140 free(buffer);
1141 }
1142
1143 }
1144 if (FD_ISSET(cfg->g_ctl, &rfds)) {
1145 if (ctl_accept(cfg, cfg->g_ctl) == -1)
1146 LLOG_WARN("unable to accept new client");
1147 }
1148 for (client = TAILQ_FIRST(&cfg->g_clients);
1149 client != NULL;
1150 client = client_next) {
1151 client_next = TAILQ_NEXT(client, next);
1152 if (FD_ISSET(client->fd, &rfds)) {
1153 /* Got a message */
1154 if ((buffer = (char *)malloc(MAX_HMSGSIZE)) ==
1155 NULL) {
1156 LLOG_WARN("failed to alloc reception buffer");
1157 continue;
1158 }
1159 if ((n = recv(client->fd, buffer,
1160 MAX_HMSGSIZE, 0)) == -1) {
1161 LLOG_WARN("error while receiving message");
1162 free(buffer);
1163 continue;
1164 }
1165 if (n > 0)
1166 client_handle_client(cfg, client, buffer, n);
1167 else
1168 ctl_close(cfg, client->fd); /* Will use TAILQ_REMOVE ! */
1169 free(buffer);
1170 }
1171 }
1172
1173 #ifdef USE_SNMP
1174 if (cfg->g_snmp) {
1175 run_alarms();
1176 netsnmp_check_outstanding_agent_requests();
1177 }
1178 #endif /* USE_SNMP */
1179 } while ((rc != 0) || (time(NULL) - cfg->g_lastsent < cfg->g_delay));
1180 }
1181
1182 void
1183 lldpd_send_all(struct lldpd *cfg)
1184 {
1185 struct lldpd_hardware *hardware;
1186 u_int8_t saved_lladdr[ETHER_ADDR_LEN];
1187 int i, altermac;
1188
1189 cfg->g_lastsent = time(NULL);
1190 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
1191 /* Ignore if interface is down */
1192 if ((hardware->h_flags & IFF_UP) == 0)
1193 continue;
1194
1195 /* When sending on inactive slaves, just send using a 0:0:0:0:0:0 address */
1196 altermac = 0;
1197 if ((hardware->h_raw_real > 0) &&
1198 (!iface_is_slave_active(cfg, hardware->h_master,
1199 hardware->h_ifname))) {
1200 altermac = 1;
1201 memcpy(saved_lladdr, hardware->h_lladdr, ETHER_ADDR_LEN);
1202 memset(hardware->h_lladdr, 0, ETHER_ADDR_LEN);
1203 }
1204
1205 for (i=0; cfg->g_protocols[i].mode != 0; i++) {
1206 if (!cfg->g_protocols[i].enabled)
1207 continue;
1208 if ((hardware->h_mode == cfg->g_protocols[i].mode) ||
1209 (cfg->g_protocols[i].mode == LLDPD_MODE_LLDP))
1210 cfg->g_protocols[i].send(cfg, &cfg->g_lchassis, hardware);
1211 }
1212 /* Restore MAC if needed */
1213 if (altermac)
1214 memcpy(hardware->h_lladdr, saved_lladdr, ETHER_ADDR_LEN);
1215 }
1216 }
1217
1218 #ifdef ENABLE_LLDPMED
1219 void
1220 lldpd_med(struct lldpd_chassis *chassis)
1221 {
1222 free(chassis->c_med_hw);
1223 free(chassis->c_med_fw);
1224 free(chassis->c_med_sn);
1225 free(chassis->c_med_manuf);
1226 free(chassis->c_med_model);
1227 free(chassis->c_med_asset);
1228 chassis->c_med_hw = dmi_hw();
1229 chassis->c_med_fw = dmi_fw();
1230 chassis->c_med_sn = dmi_sn();
1231 chassis->c_med_manuf = dmi_manuf();
1232 chassis->c_med_model = dmi_model();
1233 chassis->c_med_asset = dmi_asset();
1234 }
1235 #endif
1236
1237 void
1238 lldpd_loop(struct lldpd *cfg)
1239 {
1240 struct ifaddrs *ifap, *ifa;
1241 struct sockaddr_ll *sdl;
1242 struct lldpd_hardware *hardware;
1243 struct lldpd_vif *vif;
1244 int f;
1245 char status;
1246 struct utsname *un;
1247 char *hp;
1248
1249 /* Set system name and description */
1250 if ((un = (struct utsname*)malloc(sizeof(struct utsname))) == NULL)
1251 fatal(NULL);
1252 if (uname(un) != 0)
1253 fatal("failed to get system information");
1254 if ((hp = priv_gethostbyname()) == NULL)
1255 fatal("failed to get system name");
1256 free(cfg->g_lchassis.c_name);
1257 free(cfg->g_lchassis.c_descr);
1258 if ((cfg->g_lchassis.c_name = strdup(hp)) == NULL)
1259 fatal(NULL);
1260 if (asprintf(&cfg->g_lchassis.c_descr, "%s %s %s %s",
1261 un->sysname, un->release, un->version, un->machine) == -1)
1262 fatal("failed to set system description");
1263
1264 /* Check forwarding */
1265 cfg->g_lchassis.c_cap_enabled = 0;
1266 if ((f = priv_open("/proc/sys/net/ipv4/ip_forward")) >= 0) {
1267 if ((read(f, &status, 1) == 1) && (status == '1')) {
1268 cfg->g_lchassis.c_cap_enabled = LLDP_CAP_ROUTER;
1269 }
1270 close(f);
1271 }
1272 #ifdef ENABLE_LLDPMED
1273 if (cfg->g_lchassis.c_cap_available & LLDP_CAP_TELEPHONE)
1274 cfg->g_lchassis.c_cap_enabled |= LLDP_CAP_TELEPHONE;
1275 lldpd_med(&cfg->g_lchassis);
1276 free(cfg->g_lchassis.c_med_sw);
1277 cfg->g_lchassis.c_med_sw = strdup(un->release);
1278 #endif
1279 free(un);
1280
1281 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries)
1282 hardware->h_flags = 0;
1283 TAILQ_FOREACH(vif, &cfg->g_vif, vif_entries)
1284 vif->vif_flags = 0;
1285
1286 if (getifaddrs(&ifap) != 0)
1287 fatal("lldpd_loop: failed to get interface list");
1288
1289 cfg->g_lchassis.c_mgmt.s_addr = INADDR_ANY;
1290 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
1291 if (cfg->g_lchassis.c_mgmt.s_addr == INADDR_ANY)
1292 /* Get management address, if available */
1293 if ((ifa->ifa_addr != NULL) &&
1294 (ifa->ifa_addr->sa_family == AF_INET)) {
1295 struct sockaddr_in *sa;
1296 sa = (struct sockaddr_in *)ifa->ifa_addr;
1297 if ((ntohl(*(u_int32_t*)&sa->sin_addr) != INADDR_LOOPBACK) &&
1298 (cfg->g_mgmt_pattern == NULL)) {
1299 memcpy(&cfg->g_lchassis.c_mgmt,
1300 &sa->sin_addr,
1301 sizeof(struct in_addr));
1302 cfg->g_lchassis.c_mgmt_if = if_nametoindex(ifa->ifa_name);
1303 }
1304 else if (cfg->g_mgmt_pattern != NULL) {
1305 char *ip;
1306 ip = inet_ntoa(sa->sin_addr);
1307 if (fnmatch(cfg->g_mgmt_pattern,
1308 ip, 0) == 0) {
1309 memcpy(&cfg->g_lchassis.c_mgmt,
1310 &sa->sin_addr,
1311 sizeof(struct in_addr));
1312 cfg->g_lchassis.c_mgmt_if =
1313 if_nametoindex(ifa->ifa_name);
1314 }
1315 }
1316 }
1317
1318 if (ifa->ifa_addr == NULL ||
1319 ifa->ifa_addr->sa_family != PF_PACKET)
1320 continue;
1321
1322 sdl = (struct sockaddr_ll *)ifa->ifa_addr;
1323 if (sdl->sll_hatype != ARPHRD_ETHER || !sdl->sll_halen)
1324 continue;
1325
1326 if (iface_is_bridge(cfg, ifa->ifa_name)) {
1327 cfg->g_lchassis.c_cap_enabled |= LLDP_CAP_BRIDGE;
1328 continue;
1329 }
1330
1331 if ((iface_is_vlan(cfg, ifa->ifa_name)) ||
1332 (iface_is_bond(cfg, ifa->ifa_name)))
1333 continue;
1334
1335 if (!(ifa->ifa_flags & IFF_MULTICAST))
1336 continue;
1337
1338 if (iface_is_wireless(cfg, ifa->ifa_name))
1339 cfg->g_lchassis.c_cap_enabled |= LLDP_CAP_WLAN;
1340
1341 if (lldpd_port_add(cfg, ifa) == NULL)
1342 LLOG_WARNX("failed to allocate port %s, skip it",
1343 ifa->ifa_name);
1344 }
1345
1346 /* Handle VLAN */
1347 if (cfg->g_listen_vlans) {
1348 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
1349 if ((iface_is_vlan(cfg, ifa->ifa_name)) &&
1350 (lldpd_port_add_vlan(cfg, ifa) == NULL)) {
1351 LLOG_WARNX("unable to allocate vlan %s, skip it",
1352 ifa->ifa_name);
1353 }
1354 }
1355 }
1356
1357 freeifaddrs(ifap);
1358
1359 lldpd_cleanup(cfg);
1360
1361 lldpd_send_all(cfg);
1362 lldpd_recv_all(cfg);
1363 }
1364
1365 #ifdef ENABLE_LLDPMED
1366 void
1367 lldpd_parse_location(struct lldpd_chassis *chassis, const char *location)
1368 {
1369 char *l, *e, *s, *data, *n;
1370 double ll, altitude;
1371 u_int32_t intpart, floatpart;
1372 int type = 0, i;
1373
1374 if ((l = strdup(location)) == NULL)
1375 fatal(NULL);
1376 s = l;
1377 if ((e = index(s, ':')) == NULL)
1378 goto invalid_location;
1379 *e = '\0';
1380 type = atoi(s);
1381 switch (type) {
1382 case LLDPMED_LOCFORMAT_COORD:
1383 /* Coordinates */
1384 if ((chassis->c_med_location[0].data =
1385 (char *)malloc(16)) == NULL)
1386 fatal(NULL);
1387 chassis->c_med_location[0].data_len = 16;
1388 chassis->c_med_location[0].format = LLDPMED_LOCFORMAT_COORD;
1389 data = chassis->c_med_location[0].data;
1390
1391 /* Latitude and longitude */
1392 for (i = 0; i < 2; i++) {
1393 s = e+1;
1394 if ((e = index(s, ':')) == NULL)
1395 goto invalid_location;
1396 *e = '\0';
1397 ll = atof(s);
1398 s = e + 1;
1399 if ((e = index(s, ':')) == NULL)
1400 goto invalid_location;
1401 *e = '\0';
1402 intpart = (int)ll;
1403 floatpart = (ll - intpart) * (1 << 25);
1404 if (((i == 0) && (*s == 'S')) ||
1405 ((i == 1) && (*s == 'W'))) {
1406 intpart = ~intpart;
1407 intpart += 1;
1408 floatpart = ~floatpart;
1409 floatpart += 1;
1410 } else if (((i == 0) && (*s != 'N')) ||
1411 ((i == 1) && (*s != 'E')))
1412 goto invalid_location;
1413 *(u_int8_t *)data = (6 << 2) | /* Precision */
1414 ((intpart & 0x180) >> 7); /* Int part 2 bits */
1415 data++;
1416 *(u_int8_t *)data = (((intpart & 0x7f) << 1) | /* Int part 7 bits */
1417 ((floatpart & 0x1000000) >> 24)); /* Float part 1 bit */
1418 data++;
1419 *(u_int8_t *)data = (floatpart & 0xff0000) >> 16; /* 8 bits */
1420 data++;
1421 *(u_int8_t *)data = (floatpart & 0xff00) >> 8; /* 8 bits */
1422 data++;
1423 *(u_int8_t *)data = (floatpart & 0xff); /* 8 bits */
1424 data++;
1425 }
1426
1427 /* Altitude */
1428 s = e+1;
1429 if ((e = index(s, ':')) == NULL)
1430 goto invalid_location;
1431 *e = '\0';
1432 altitude = atof(s);
1433 s = e+1;
1434 if ((e = index(s, ':')) == NULL)
1435 goto invalid_location;
1436 *e = '\0';
1437 if (altitude < 0) {
1438 intpart = -(int)altitude;
1439 floatpart = (-(altitude + intpart)) * (1 << 8);
1440 intpart = ~intpart; intpart += 1;
1441 floatpart = ~floatpart; floatpart += 1;
1442 } else {
1443 intpart = (int)altitude;
1444 floatpart = (altitude - intpart) * (1 << 8);
1445 }
1446 if ((*s != 'm') && (*s != 'f'))
1447 goto invalid_location;
1448 *(u_int8_t *)data = ((((*s == 'm')?1:2) << 4) | /* Type 4 bits */
1449 0); /* Precision 4 bits */
1450 data++;
1451 *(u_int8_t *)data = ((6 << 6) | /* Precision 2 bits */
1452 ((intpart & 0x3f0000) >> 16)); /* Int 6 bits */
1453 data++;
1454 *(u_int8_t *)data = (intpart & 0xff00) >> 8; /* Int 8 bits */
1455 data++;
1456 *(u_int8_t *)data = intpart & 0xff; /* Int 8 bits */
1457 data++;
1458 *(u_int8_t *)data = floatpart & 0xff; /* Float 8 bits */
1459 data++;
1460
1461 /* Datum */
1462 s = e + 1;
1463 if (index(s, ':') != NULL)
1464 goto invalid_location;
1465 *(u_int8_t *)data = atoi(s);
1466 break;
1467 case LLDPMED_LOCFORMAT_CIVIC:
1468 /* Civic address */
1469 chassis->c_med_location[1].data_len = 4;
1470 s = e+1;
1471 if ((s = index(s, ':')) == NULL)
1472 goto invalid_location;
1473 s = s+1;
1474 do {
1475 if ((s = index(s, ':')) == NULL)
1476 break;
1477 s = s+1;
1478 /* s is the beginning of the word */
1479 if ((n = index(s, ':')) == NULL)
1480 n = s + strlen(s);
1481 /* n is the end of the word */
1482 chassis->c_med_location[1].data_len += (n - s) + 2;
1483 if ((s = index(s, ':')) == NULL)
1484 break;
1485 s = s+1;
1486 } while (1);
1487 s = e+1;
1488 if ((chassis->c_med_location[1].data =
1489 (char *)malloc(chassis->c_med_location[1].data_len)) ==
1490 NULL)
1491 fatal(NULL);
1492 chassis->c_med_location[1].format = LLDPMED_LOCFORMAT_CIVIC;
1493 data = chassis->c_med_location[1].data;
1494 *(u_int8_t *)data = chassis->c_med_location[1].data_len - 1;
1495 data++;
1496 *(u_int8_t *)data = 2; /* Client location */
1497 data++;
1498 if ((e = index(s, ':')) == NULL)
1499 goto invalid_location;
1500 if ((e - s) != 2)
1501 goto invalid_location;
1502 memcpy(data, s, 2); /* Country code */
1503 data += 2;
1504 while (*e != '\0') {
1505 s=e+1;
1506 if ((e = index(s, ':')) == NULL)
1507 goto invalid_location;
1508 *e = '\0';
1509 *(u_int8_t *)data = atoi(s);
1510 data++;
1511 s=e+1;
1512 if ((e = index(s, ':')) == NULL)
1513 e = s + strlen(s);
1514 *(u_int8_t *)data = e - s;
1515 data++;
1516 memcpy(data, s, e-s);
1517 data += e-s;
1518 }
1519 break;
1520 case LLDPMED_LOCFORMAT_ELIN:
1521 s = e+1;
1522 chassis->c_med_location[2].data_len = strlen(s);
1523 if ((chassis->c_med_location[2].data =
1524 (char *)malloc(strlen(s))) == NULL)
1525 fatal(NULL);
1526 chassis->c_med_location[2].format = LLDPMED_LOCFORMAT_ELIN;
1527 strcpy(chassis->c_med_location[2].data, s);
1528 break;
1529 default:
1530 goto invalid_location;
1531 }
1532
1533 chassis->c_med_cap_enabled |= LLDPMED_CAP_LOCATION;
1534 return;
1535 invalid_location:
1536 LLOG_WARNX("the format of the location is invalid (%s)",
1537 location);
1538 if (type) {
1539 free(chassis->c_med_location[type-1].data);
1540 memset(&chassis->c_med_location[type-1], 0,
1541 sizeof(struct lldpd_med_loc));
1542 }
1543 free(l);
1544 }
1545 #endif
1546
1547 void
1548 lldpd_shutdown(int sig)
1549 {
1550 LLOG_INFO("signal received, exiting");
1551 exit(0);
1552 }
1553
1554 /* For signal handling */
1555 struct lldpd *gcfg = NULL;
1556
1557 void
1558 lldpd_exit()
1559 {
1560 struct lldpd_hardware *hardware;
1561 struct lldpd_vif *vif;
1562 close(gcfg->g_ctl);
1563 priv_ctl_cleanup();
1564 TAILQ_FOREACH(hardware, &gcfg->g_hardware, h_entries) {
1565 if (INTERFACE_OPENED(hardware))
1566 lldpd_iface_close(gcfg, hardware);
1567 }
1568 TAILQ_FOREACH(vif, &gcfg->g_vif, vif_entries) {
1569 if (vif->vif_raw != -1)
1570 lldpd_iface_close(gcfg, (struct lldpd_hardware*)vif);
1571 }
1572 #ifdef USE_SNMP
1573 if (gcfg->g_snmp)
1574 agent_shutdown();
1575 #endif /* USE_SNMP */
1576 }
1577
1578 int
1579 main(int argc, char *argv[])
1580 {
1581 struct lldpd *cfg;
1582 int ch, debug = 0;
1583 #ifdef USE_SNMP
1584 int snmp = 0;
1585 #endif
1586 char *mgmtp = NULL;
1587 char *popt, opts[] = "vdxm:p:M:iL:P:@ ";
1588 int probe = 0, i, found, vlan = 0;
1589 #ifdef ENABLE_LLDPMED
1590 int lldpmed = 0, noinventory = 0;
1591 #endif
1592
1593 saved_argv = argv;
1594
1595 /*
1596 * Get and parse command line options
1597 */
1598 popt = index(opts, '@');
1599 for (i=0; protos[i].mode != 0; i++) {
1600 if (protos[i].enabled == 1) continue;
1601 *(popt++) = protos[i].arg;
1602 }
1603 *popt = '\0';
1604 while ((ch = getopt(argc, argv, opts)) != -1) {
1605 switch (ch) {
1606 case 'v':
1607 vlan = 1;
1608 break;
1609 case 'd':
1610 debug++;
1611 break;
1612 case 'm':
1613 mgmtp = optarg;
1614 break;
1615 #ifdef ENABLE_LLDPMED
1616 case 'M':
1617 lldpmed = atoi(optarg);
1618 if ((lldpmed < 1) || (lldpmed > 4)) {
1619 fprintf(stderr, "-M requires an argument between 1 and 4\n");
1620 usage();
1621 }
1622 break;
1623 case 'i':
1624 noinventory = 1;
1625 break;
1626 case 'L':
1627 case 'P':
1628 /* Handled later */
1629 break;
1630 #else
1631 case 'M':
1632 case 'i':
1633 case 'L':
1634 case 'P':
1635 fprintf(stderr, "LLDP-MED support is not built-in\n");
1636 usage();
1637 break;
1638 #endif
1639 case 'p':
1640 probe = atoi(optarg);
1641 break;
1642 case 'x':
1643 #ifdef USE_SNMP
1644 snmp = 1;
1645 #else
1646 fprintf(stderr, "SNMP support is not built-in\n");
1647 usage();
1648 #endif
1649 break;
1650 default:
1651 found = 0;
1652 for (i=0; protos[i].mode != 0; i++) {
1653 if (protos[i].enabled) continue;
1654 if (ch == protos[i].arg) {
1655 protos[i].enabled = 1;
1656 found = 1;
1657 }
1658 }
1659 if (!found)
1660 usage();
1661 }
1662 }
1663
1664 log_init(debug);
1665
1666 if (!debug) {
1667 int pid;
1668 char *spid;
1669 if (daemon(0, 0) != 0)
1670 fatal("failed to detach daemon");
1671 if ((pid = open(LLDPD_PID_FILE,
1672 O_TRUNC | O_CREAT | O_WRONLY, 0644)) == -1)
1673 fatal("unable to open pid file " LLDPD_PID_FILE);
1674 if (asprintf(&spid, "%d\n", getpid()) == -1)
1675 fatal("unable to create pid file " LLDPD_PID_FILE);
1676 if (write(pid, spid, strlen(spid)) == -1)
1677 fatal("unable to write pid file " LLDPD_PID_FILE);
1678 free(spid);
1679 close(pid);
1680 }
1681
1682 priv_init(PRIVSEP_CHROOT);
1683
1684 if (probe == 0) probe = LLDPD_TTL;
1685
1686 if ((cfg = (struct lldpd *)
1687 calloc(1, sizeof(struct lldpd))) == NULL)
1688 fatal(NULL);
1689
1690 cfg->g_mgmt_pattern = mgmtp;
1691 cfg->g_listen_vlans = vlan;
1692
1693 /* Get ioctl socket */
1694 if ((cfg->g_sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
1695 fatal("failed to get ioctl socket");
1696 cfg->g_delay = LLDPD_TX_DELAY;
1697
1698 /* Set system capabilities */
1699 cfg->g_lchassis.c_cap_available = LLDP_CAP_BRIDGE | LLDP_CAP_WLAN |
1700 LLDP_CAP_ROUTER;
1701 #ifdef ENABLE_LLDPMED
1702 if (lldpmed > 0) {
1703 if (lldpmed == LLDPMED_CLASS_III)
1704 cfg->g_lchassis.c_cap_available |= LLDP_CAP_TELEPHONE;
1705 cfg->g_lchassis.c_med_type = lldpmed;
1706 cfg->g_lchassis.c_med_cap_available = LLDPMED_CAP_CAP |
1707 LLDPMED_CAP_IV | LLDPMED_CAP_LOCATION;
1708 cfg->g_lchassis.c_med_cap_enabled = LLDPMED_CAP_CAP;
1709 if (!noinventory)
1710 cfg->g_lchassis.c_med_cap_enabled |= LLDPMED_CAP_IV;
1711 optind = 1;
1712 while ((ch = getopt(argc, argv, opts)) != -1) {
1713 switch (ch) {
1714 case 'L':
1715 lldpd_parse_location(&cfg->g_lchassis, optarg);
1716 break;
1717 case 'P':
1718 break;
1719 }
1720 }
1721 }
1722 #endif
1723
1724 /* Set TTL */
1725 cfg->g_lchassis.c_ttl = LLDPD_TTL;
1726
1727 cfg->g_protocols = protos;
1728 cfg->g_probe_time = probe;
1729 for (i=0; protos[i].mode != 0; i++)
1730 if (protos[i].enabled) {
1731 cfg->g_multi++;
1732 LLOG_INFO("protocol %s enabled", protos[i].name);
1733 } else
1734 LLOG_INFO("protocol %s disabled", protos[i].name);
1735 cfg->g_multi--;
1736
1737 TAILQ_INIT(&cfg->g_hardware);
1738 TAILQ_INIT(&cfg->g_vif);
1739
1740 #ifdef USE_SNMP
1741 if (snmp) {
1742 cfg->g_snmp = 1;
1743 agent_init(cfg, debug);
1744 }
1745 #endif /* USE_SNMP */
1746
1747 /* Create socket */
1748 if ((cfg->g_ctl = priv_ctl_create(cfg)) == -1)
1749 fatalx("unable to create control socket " LLDPD_CTL_SOCKET);
1750 TAILQ_INIT(&cfg->g_clients);
1751
1752 gcfg = cfg;
1753 if (atexit(lldpd_exit) != 0) {
1754 close(cfg->g_ctl);
1755 priv_ctl_cleanup();
1756 fatal("unable to set exit function");
1757 }
1758
1759 /* Signal handling */
1760 signal(SIGHUP, lldpd_shutdown);
1761 signal(SIGINT, lldpd_shutdown);
1762 signal(SIGTERM, lldpd_shutdown);
1763
1764 for (;;)
1765 lldpd_loop(cfg);
1766
1767 return (0);
1768 }