]> git.ipfire.org Git - thirdparty/lldpd.git/blob - src/lldpd.c
Use "void" instead of empty parameter list for function prototypes.
[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 <time.h>
26 #include <libgen.h>
27 #include <sys/utsname.h>
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <sys/select.h>
31 #include <sys/time.h>
32 #include <sys/ioctl.h>
33 #include <arpa/inet.h>
34 #include <net/if_arp.h>
35
36 #ifdef USE_SNMP
37 #include <net-snmp/net-snmp-config.h>
38 #include <net-snmp/net-snmp-includes.h>
39 #include <net-snmp/agent/net-snmp-agent-includes.h>
40 #include <net-snmp/agent/snmp_vars.h>
41 #endif /* USE_SNMP */
42
43 static void usage(void);
44
45 static struct protocol protos[] =
46 {
47 { LLDPD_MODE_LLDP, 1, "LLDP", ' ', lldp_send, lldp_decode, NULL,
48 LLDP_MULTICAST_ADDR },
49 #ifdef ENABLE_CDP
50 { LLDPD_MODE_CDPV1, 0, "CDPv1", 'c', cdpv1_send, cdp_decode, cdpv1_guess,
51 CDP_MULTICAST_ADDR },
52 { LLDPD_MODE_CDPV2, 0, "CDPv2", 'c', cdpv2_send, cdp_decode, cdpv2_guess,
53 CDP_MULTICAST_ADDR },
54 #endif
55 #ifdef ENABLE_SONMP
56 { LLDPD_MODE_SONMP, 0, "SONMP", 's', sonmp_send, sonmp_decode, NULL,
57 SONMP_MULTICAST_ADDR },
58 #endif
59 #ifdef ENABLE_EDP
60 { LLDPD_MODE_EDP, 0, "EDP", 'e', edp_send, edp_decode, NULL,
61 EDP_MULTICAST_ADDR },
62 #endif
63 #ifdef ENABLE_FDP
64 { LLDPD_MODE_FDP, 0, "FDP", 'f', fdp_send, cdp_decode, NULL,
65 FDP_MULTICAST_ADDR },
66 #endif
67 { 0, 0, "any", ' ', NULL, NULL, NULL,
68 {0,0,0,0,0,0} }
69 };
70
71 static void lldpd_update_localchassis(struct lldpd *);
72 static void lldpd_update_localports(struct lldpd *);
73 static void lldpd_cleanup(struct lldpd *);
74 static void lldpd_loop(struct lldpd *);
75 static void lldpd_shutdown(int);
76 static void lldpd_exit(void);
77 static void lldpd_send_all(struct lldpd *);
78 static void lldpd_recv_all(struct lldpd *);
79 static int lldpd_guess_type(struct lldpd *, char *, int);
80 static void lldpd_decode(struct lldpd *, char *, int,
81 struct lldpd_hardware *);
82 static void lldpd_update_chassis(struct lldpd_chassis *,
83 const struct lldpd_chassis *);
84 #ifdef ENABLE_LLDPMED
85 static void lldpd_med(struct lldpd_chassis *);
86 #endif
87
88 static char **saved_argv;
89
90 static void
91 usage(void)
92 {
93 extern const char *__progname;
94 fprintf(stderr, "usage: %s [options]\n", __progname);
95 fprintf(stderr, "see manual page lldpd(8) for more information\n");
96 exit(1);
97 }
98
99 struct lldpd_hardware *
100 lldpd_get_hardware(struct lldpd *cfg, char *name, int index, struct lldpd_ops *ops)
101 {
102 struct lldpd_hardware *hardware;
103 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
104 if ((strcmp(hardware->h_ifname, name) == 0) &&
105 (hardware->h_ifindex == index) &&
106 ((!ops) || (ops == hardware->h_ops)))
107 break;
108 }
109 return hardware;
110 }
111
112 struct lldpd_hardware *
113 lldpd_alloc_hardware(struct lldpd *cfg, char *name)
114 {
115 struct lldpd_hardware *hardware;
116
117 if ((hardware = (struct lldpd_hardware *)
118 calloc(1, sizeof(struct lldpd_hardware))) == NULL)
119 return NULL;
120
121 strlcpy(hardware->h_ifname, name, sizeof(hardware->h_ifname));
122 hardware->h_lport.p_chassis = LOCAL_CHASSIS(cfg);
123 TAILQ_INIT(&hardware->h_rports);
124
125 #ifdef ENABLE_LLDPMED
126 if (LOCAL_CHASSIS(cfg)->c_med_cap_available) {
127 hardware->h_lport.p_med_cap_enabled = LLDPMED_CAP_CAP;
128 if (!cfg->g_noinventory)
129 hardware->h_lport.p_med_cap_enabled |= LLDPMED_CAP_IV;
130 }
131 #endif
132 #ifdef ENABLE_DOT1
133 TAILQ_INIT(&hardware->h_lport.p_vlans);
134 #endif
135 return hardware;
136 }
137
138 #ifdef ENABLE_DOT1
139 void
140 lldpd_vlan_cleanup(struct lldpd_port *port)
141 {
142 struct lldpd_vlan *vlan, *vlan_next;
143 for (vlan = TAILQ_FIRST(&port->p_vlans);
144 vlan != NULL;
145 vlan = vlan_next) {
146 free(vlan->v_name);
147 vlan_next = TAILQ_NEXT(vlan, v_entries);
148 TAILQ_REMOVE(&port->p_vlans, vlan, v_entries);
149 free(vlan);
150 }
151 }
152 #endif
153
154 /* If `all' is true, clear all information, including information that
155 are not refreshed periodically. Port should be freed manually. */
156 void
157 lldpd_port_cleanup(struct lldpd_port *port, int all)
158 {
159 #ifdef ENABLE_LLDPMED
160 int i;
161 if (all)
162 for (i=0; i < LLDPMED_LOCFORMAT_LAST; i++)
163 free(port->p_med_location[i].data);
164 #endif
165 #ifdef ENABLE_DOT1
166 lldpd_vlan_cleanup(port);
167 #endif
168 free(port->p_id);
169 free(port->p_descr);
170 if (all) {
171 free(port->p_lastframe);
172 if (port->p_chassis) /* chassis may not have been attributed, yet */
173 port->p_chassis->c_refcount--;
174 }
175 }
176
177 void
178 lldpd_chassis_cleanup(struct lldpd_chassis *chassis, int all)
179 {
180 #ifdef ENABLE_LLDPMED
181 free(chassis->c_med_hw);
182 free(chassis->c_med_sw);
183 free(chassis->c_med_fw);
184 free(chassis->c_med_sn);
185 free(chassis->c_med_manuf);
186 free(chassis->c_med_model);
187 free(chassis->c_med_asset);
188 #endif
189 free(chassis->c_id);
190 free(chassis->c_name);
191 free(chassis->c_descr);
192 if (all)
193 free(chassis);
194 }
195
196 void
197 lldpd_remote_cleanup(struct lldpd *cfg, struct lldpd_hardware *hardware, int all)
198 {
199 struct lldpd_port *port, *port_next;
200 int del;
201 for (port = TAILQ_FIRST(&hardware->h_rports);
202 port != NULL;
203 port = port_next) {
204 port_next = TAILQ_NEXT(port, p_entries);
205 del = all;
206 if (!del &&
207 (time(NULL) - port->p_lastupdate > port->p_chassis->c_ttl)) {
208 hardware->h_rx_ageout_cnt++;
209 del = 1;
210 }
211 if (del) {
212 TAILQ_REMOVE(&hardware->h_rports, port, p_entries);
213 lldpd_port_cleanup(port, 1);
214 free(port);
215 }
216 }
217 }
218
219 void
220 lldpd_hardware_cleanup(struct lldpd *cfg, struct lldpd_hardware *hardware)
221 {
222 int i;
223 lldpd_port_cleanup(&hardware->h_lport, 1);
224 /* If we have a dedicated cleanup function, use it. Otherwise,
225 we just free the hardware-dependent data and close all FD
226 in h_recvfds and h_sendfd. */
227 if (hardware->h_ops->cleanup)
228 hardware->h_ops->cleanup(cfg, hardware);
229 else {
230 free(hardware->h_data);
231 for (i=0; i < FD_SETSIZE; i++)
232 if (FD_ISSET(i, &hardware->h_recvfds))
233 close(i);
234 if (hardware->h_sendfd) close(hardware->h_sendfd);
235 }
236 free(hardware);
237 }
238
239 static void
240 lldpd_cleanup(struct lldpd *cfg)
241 {
242 struct lldpd_hardware *hardware, *hardware_next;
243
244 for (hardware = TAILQ_FIRST(&cfg->g_hardware); hardware != NULL;
245 hardware = hardware_next) {
246 hardware_next = TAILQ_NEXT(hardware, h_entries);
247 if (!hardware->h_flags) {
248 TAILQ_REMOVE(&cfg->g_hardware, hardware, h_entries);
249 lldpd_remote_cleanup(cfg, hardware, 1);
250 lldpd_hardware_cleanup(cfg, hardware);
251 } else
252 lldpd_remote_cleanup(cfg, hardware, 0);
253 }
254 }
255
256 static int
257 lldpd_guess_type(struct lldpd *cfg, char *frame, int s)
258 {
259 int i;
260 if (s < ETH_ALEN)
261 return -1;
262 for (i=0; cfg->g_protocols[i].mode != 0; i++) {
263 if (!cfg->g_protocols[i].enabled)
264 continue;
265 if (cfg->g_protocols[i].guess == NULL) {
266 if (memcmp(frame, cfg->g_protocols[i].mac, ETH_ALEN) == 0)
267 return cfg->g_protocols[i].mode;
268 } else {
269 if (cfg->g_protocols[i].guess(frame, s))
270 return cfg->g_protocols[i].mode;
271 }
272 }
273 return -1;
274 }
275
276 static void
277 lldpd_decode(struct lldpd *cfg, char *frame, int s,
278 struct lldpd_hardware *hardware)
279 {
280 int i, result;
281 struct lldpd_chassis *chassis, *ochassis = NULL;
282 struct lldpd_port *port, *oport = NULL;
283 int guess = LLDPD_MODE_LLDP;
284
285 /* Discard VLAN frames */
286 if ((s >= sizeof(struct ethhdr)) &&
287 (((struct ethhdr*)frame)->h_proto == htons(ETHERTYPE_VLAN)))
288 return;
289
290 TAILQ_FOREACH(oport, &hardware->h_rports, p_entries) {
291 if ((oport->p_lastframe != NULL) &&
292 (oport->p_lastframe->size == s) &&
293 (memcmp(oport->p_lastframe->frame, frame, s) == 0)) {
294 /* Already received the same frame */
295 oport->p_lastupdate = time(NULL);
296 return;
297 }
298 }
299
300 guess = lldpd_guess_type(cfg, frame, s);
301 for (i=0; cfg->g_protocols[i].mode != 0; i++) {
302 if (!cfg->g_protocols[i].enabled)
303 continue;
304 if (cfg->g_protocols[i].mode == guess) {
305 if ((result = cfg->g_protocols[i].decode(cfg, frame,
306 s, hardware, &chassis, &port)) == -1)
307 return;
308 chassis->c_protocol = port->p_protocol =
309 cfg->g_protocols[i].mode;
310 break;
311 }
312 }
313 if (cfg->g_protocols[i].mode == 0) {
314 LLOG_INFO("unable to guess frame type");
315 return;
316 }
317
318 /* Do we already have the same MSAP somewhere? */
319 TAILQ_FOREACH(oport, &hardware->h_rports, p_entries) {
320 if ((port->p_protocol == oport->p_protocol) &&
321 (port->p_id_subtype == oport->p_id_subtype) &&
322 (port->p_id_len == oport->p_id_len) &&
323 (memcmp(port->p_id, oport->p_id, port->p_id_len) == 0) &&
324 (chassis->c_id_subtype == oport->p_chassis->c_id_subtype) &&
325 (chassis->c_id_len == oport->p_chassis->c_id_len) &&
326 (memcmp(chassis->c_id, oport->p_chassis->c_id,
327 chassis->c_id_len) == 0)) {
328 ochassis = oport->p_chassis;
329 break;
330 }
331 }
332 /* No, but do we already know the system? */
333 if (!oport) {
334 TAILQ_FOREACH(ochassis, &cfg->g_chassis, c_entries) {
335 if ((chassis->c_protocol == ochassis->c_protocol) &&
336 (chassis->c_id_subtype == ochassis->c_id_subtype) &&
337 (chassis->c_id_len == ochassis->c_id_len) &&
338 (memcmp(chassis->c_id, ochassis->c_id,
339 chassis->c_id_len) == 0))
340 break;
341 }
342 }
343
344 if (oport) {
345 /* The port is known, remove it before adding it back */
346 TAILQ_REMOVE(&hardware->h_rports, oport, p_entries);
347 lldpd_port_cleanup(oport, 1);
348 free(oport);
349 }
350 if (ochassis) {
351 lldpd_update_chassis(ochassis, chassis);
352 free(chassis);
353 chassis = ochassis;
354 } else {
355 /* Chassis not known, add it */
356 chassis->c_index = ++cfg->g_lastrid;
357 port->p_chassis = chassis;
358 chassis->c_refcount = 0;
359 TAILQ_INSERT_TAIL(&cfg->g_chassis, chassis, c_entries);
360 i = 0; TAILQ_FOREACH(ochassis, &cfg->g_chassis, c_entries) i++;
361 LLOG_DEBUG("Currently, we know %d different systems", i);
362 }
363 /* Add port */
364 port->p_lastchange = port->p_lastupdate = time(NULL);
365 if ((port->p_lastframe = (struct lldpd_frame *)malloc(s +
366 sizeof(int))) != NULL) {
367 port->p_lastframe->size = s;
368 memcpy(port->p_lastframe->frame, frame, s);
369 }
370 TAILQ_INSERT_TAIL(&hardware->h_rports, port, p_entries);
371 port->p_chassis = chassis;
372 port->p_chassis->c_refcount++;
373 i = 0; TAILQ_FOREACH(oport, &hardware->h_rports, p_entries) i++;
374 LLOG_DEBUG("Currently, %s known %d neighbors",
375 hardware->h_ifname, i);
376 return;
377 }
378
379 /* Update chassis `ochassis' with values from `chassis'. */
380 static void
381 lldpd_update_chassis(struct lldpd_chassis *ochassis,
382 const struct lldpd_chassis *chassis) {
383 TAILQ_ENTRY(lldpd_chassis) entries;
384 /* We want to keep refcount, index and list stuff from the current
385 * chassis */
386 int refcount = ochassis->c_refcount;
387 int index = ochassis->c_index;
388 memcpy(&entries, &ochassis->c_entries,
389 sizeof(entries));
390 /* Make the copy */
391 lldpd_chassis_cleanup(ochassis, 0);
392 memcpy(ochassis, chassis, sizeof(struct lldpd_chassis));
393 /* Restore saved values */
394 ochassis->c_refcount = refcount;
395 ochassis->c_index = index;
396 memcpy(&ochassis->c_entries, &entries, sizeof(entries));
397 }
398
399 int
400 lldpd_callback_add(struct lldpd *cfg, int fd, void(*fn)(CALLBACK_SIG), void *data)
401 {
402 struct lldpd_callback *callback;
403 if ((callback = (struct lldpd_callback *)
404 malloc(sizeof(struct lldpd_callback))) == NULL)
405 return -1;
406 callback->fd = fd;
407 callback->function = fn;
408 callback->data = data;
409 TAILQ_INSERT_TAIL(&cfg->g_callbacks, callback, next);
410 return 0;
411 }
412
413 void
414 lldpd_callback_del(struct lldpd *cfg, int fd, void(*fn)(CALLBACK_SIG))
415 {
416 struct lldpd_callback *callback, *callback_next;
417 for (callback = TAILQ_FIRST(&cfg->g_callbacks);
418 callback;
419 callback = callback_next) {
420 callback_next = TAILQ_NEXT(callback, next);
421 if ((callback->fd == fd) &&
422 (callback->function = fn)) {
423 free(callback->data);
424 TAILQ_REMOVE(&cfg->g_callbacks, callback, next);
425 free(callback);
426 }
427 }
428 }
429
430 static void
431 lldpd_recv_all(struct lldpd *cfg)
432 {
433 struct lldpd_hardware *hardware;
434 struct lldpd_callback *callback, *callback_next;
435 fd_set rfds;
436 struct timeval tv;
437 #ifdef USE_SNMP
438 int fakeblock = 0;
439 struct timeval *tvp = &tv;
440 #endif
441 int rc, nfds, n;
442 char *buffer;
443
444 do {
445 tv.tv_sec = cfg->g_delay - (time(NULL) - cfg->g_lastsent);
446 if (tv.tv_sec < 0)
447 tv.tv_sec = LLDPD_TX_DELAY;
448 if (tv.tv_sec >= cfg->g_delay)
449 tv.tv_sec = cfg->g_delay;
450 tv.tv_usec = 0;
451
452 FD_ZERO(&rfds);
453 nfds = -1;
454
455 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
456 /* Ignore if interface is down */
457 if ((hardware->h_flags & IFF_RUNNING) == 0)
458 continue;
459 /* This is quite expensive but we don't rely on internal
460 * structure of fd_set. */
461 for (n = 0; n < FD_SETSIZE; n++)
462 if (FD_ISSET(n, &hardware->h_recvfds)) {
463 FD_SET(n, &rfds);
464 if (nfds < n)
465 nfds = n;
466 }
467 }
468 TAILQ_FOREACH(callback, &cfg->g_callbacks, next) {
469 FD_SET(callback->fd, &rfds);
470 if (nfds < callback->fd)
471 nfds = callback->fd;
472 }
473
474 #ifdef USE_SNMP
475 if (cfg->g_snmp)
476 snmp_select_info(&nfds, &rfds, tvp, &fakeblock);
477 #endif /* USE_SNMP */
478 if (nfds == -1) {
479 sleep(cfg->g_delay);
480 return;
481 }
482
483 rc = select(nfds + 1, &rfds, NULL, NULL, &tv);
484 if (rc == -1) {
485 if (errno == EINTR)
486 continue;
487 LLOG_WARN("failure on select");
488 break;
489 }
490 #ifdef USE_SNMP
491 if (cfg->g_snmp) {
492 if (rc > 0)
493 snmp_read(&rfds);
494 else if (rc == 0)
495 snmp_timeout();
496 }
497 #endif /* USE_SNMP */
498 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
499 for (n = 0; n < FD_SETSIZE; n++)
500 if ((FD_ISSET(n, &hardware->h_recvfds)) &&
501 (FD_ISSET(n, &rfds))) break;
502 if (n == FD_SETSIZE) continue;
503 if ((buffer = (char *)malloc(
504 hardware->h_mtu)) == NULL) {
505 LLOG_WARN("failed to alloc reception buffer");
506 continue;
507 }
508 if ((n = hardware->h_ops->recv(cfg, hardware,
509 n, buffer, hardware->h_mtu)) == -1) {
510 free(buffer);
511 continue;
512 }
513 hardware->h_rx_cnt++;
514 lldpd_decode(cfg, buffer, n, hardware);
515 free(buffer);
516 break;
517 }
518 for (callback = TAILQ_FIRST(&cfg->g_callbacks);
519 callback;
520 callback = callback_next) {
521 /* Callback function can use TAILQ_REMOVE */
522 callback_next = TAILQ_NEXT(callback, next);
523 if (FD_ISSET(callback->fd, &rfds))
524 callback->function(cfg, callback);
525 }
526
527 #ifdef USE_SNMP
528 if (cfg->g_snmp) {
529 run_alarms();
530 netsnmp_check_outstanding_agent_requests();
531 }
532 #endif /* USE_SNMP */
533 } while ((rc != 0) || (time(NULL) - cfg->g_lastsent < cfg->g_delay));
534 }
535
536 static void
537 lldpd_send_all(struct lldpd *cfg)
538 {
539 struct lldpd_hardware *hardware;
540 struct lldpd_port *port;
541 int i, sent = 0;
542
543 cfg->g_lastsent = time(NULL);
544 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
545 /* Ignore if interface is down */
546 if ((hardware->h_flags & IFF_RUNNING) == 0)
547 continue;
548
549 for (i=0; cfg->g_protocols[i].mode != 0; i++) {
550 if (!cfg->g_protocols[i].enabled)
551 continue;
552 /* We send only if we have at least one remote system
553 * speaking this protocol */
554 TAILQ_FOREACH(port, &hardware->h_rports, p_entries) {
555 if (port->p_protocol ==
556 cfg->g_protocols[i].mode) {
557 cfg->g_protocols[i].send(cfg,
558 hardware);
559 sent = 1;
560 break;
561 }
562 }
563 }
564
565 if (!sent)
566 /* Nothing was sent for this port, let's speak LLDP */
567 cfg->g_protocols[0].send(cfg,
568 hardware);
569 }
570 }
571
572 #ifdef ENABLE_LLDPMED
573 static void
574 lldpd_med(struct lldpd_chassis *chassis)
575 {
576 free(chassis->c_med_hw);
577 free(chassis->c_med_fw);
578 free(chassis->c_med_sn);
579 free(chassis->c_med_manuf);
580 free(chassis->c_med_model);
581 free(chassis->c_med_asset);
582 chassis->c_med_hw = dmi_hw();
583 chassis->c_med_fw = dmi_fw();
584 chassis->c_med_sn = dmi_sn();
585 chassis->c_med_manuf = dmi_manuf();
586 chassis->c_med_model = dmi_model();
587 chassis->c_med_asset = dmi_asset();
588 }
589 #endif
590
591 static void
592 lldpd_update_localchassis(struct lldpd *cfg)
593 {
594 struct utsname un;
595 char *hp;
596 int f;
597 char status;
598 struct lldpd_hardware *hardware;
599
600 /* Set system name and description */
601 if (uname(&un) != 0)
602 fatal("failed to get system information");
603 if ((hp = priv_gethostbyname()) == NULL)
604 fatal("failed to get system name");
605 free(LOCAL_CHASSIS(cfg)->c_name);
606 free(LOCAL_CHASSIS(cfg)->c_descr);
607 if ((LOCAL_CHASSIS(cfg)->c_name = strdup(hp)) == NULL)
608 fatal(NULL);
609 if (asprintf(&LOCAL_CHASSIS(cfg)->c_descr, "%s %s %s %s",
610 un.sysname, un.release, un.version, un.machine) == -1)
611 fatal("failed to set system description");
612
613 /* Check forwarding */
614 if ((f = priv_open("/proc/sys/net/ipv4/ip_forward")) >= 0) {
615 if ((read(f, &status, 1) == 1) && (status == '1')) {
616 LOCAL_CHASSIS(cfg)->c_cap_enabled = LLDP_CAP_ROUTER;
617 }
618 close(f);
619 }
620 #ifdef ENABLE_LLDPMED
621 if (LOCAL_CHASSIS(cfg)->c_cap_available & LLDP_CAP_TELEPHONE)
622 LOCAL_CHASSIS(cfg)->c_cap_enabled |= LLDP_CAP_TELEPHONE;
623 lldpd_med(LOCAL_CHASSIS(cfg));
624 free(LOCAL_CHASSIS(cfg)->c_med_sw);
625 LOCAL_CHASSIS(cfg)->c_med_sw = strdup(un.release);
626 #endif
627
628 /* Set chassis ID if needed */
629 if ((LOCAL_CHASSIS(cfg)->c_id == NULL) &&
630 (hardware = TAILQ_FIRST(&cfg->g_hardware))) {
631 if ((LOCAL_CHASSIS(cfg)->c_id =
632 malloc(sizeof(hardware->h_lladdr))) == NULL)
633 fatal(NULL);
634 LOCAL_CHASSIS(cfg)->c_id_subtype = LLDP_CHASSISID_SUBTYPE_LLADDR;
635 LOCAL_CHASSIS(cfg)->c_id_len = sizeof(hardware->h_lladdr);
636 memcpy(LOCAL_CHASSIS(cfg)->c_id,
637 hardware->h_lladdr, sizeof(hardware->h_lladdr));
638 }
639 }
640
641 static void
642 lldpd_update_localports(struct lldpd *cfg)
643 {
644 struct ifaddrs *ifap;
645 struct lldpd_hardware *hardware;
646 lldpd_ifhandlers ifhs[] = {
647 lldpd_ifh_bond, /* Handle bond */
648 lldpd_ifh_eth, /* Handle classic ethernet interfaces */
649 #ifdef ENABLE_DOT1
650 lldpd_ifh_vlan, /* Handle VLAN */
651 #endif
652 lldpd_ifh_mgmt, /* Handle management address (if not already handled) */
653 NULL
654 };
655 lldpd_ifhandlers *ifh;
656
657 /* h_flags is set to 0 for each port. If the port is updated, h_flags
658 * will be set to a non-zero value. This will allow us to clean up any
659 * non up-to-date port */
660 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries)
661 hardware->h_flags = 0;
662
663 LOCAL_CHASSIS(cfg)->c_mgmt.s_addr = INADDR_ANY;
664 if (getifaddrs(&ifap) != 0)
665 fatal("lldpd_update_localports: failed to get interface list");
666
667 /* We will run the list of interfaces through a list of interface
668 * handlers. Each handler will create or update some hardware port (and
669 * will set h_flags to a non zero value. The handler can use the list of
670 * interfaces but this is not mandatory. If the interface handler
671 * handles an interface from the list, it should set ifa_flags to 0 to
672 * let know the other handlers that it took care of this interface. This
673 * means that more specific handlers should be before less specific
674 * ones. */
675 for (ifh = ifhs; *ifh != NULL; ifh++)
676 (*ifh)(cfg, ifap);
677 freeifaddrs(ifap);
678 }
679
680 static void
681 lldpd_loop(struct lldpd *cfg)
682 {
683 /* Main loop.
684
685 1. Update local ports information
686 2. Clean unwanted (removed) local ports
687 3. Update local chassis information
688 4. Send packets
689 5. Receive packets
690 */
691 LOCAL_CHASSIS(cfg)->c_cap_enabled = 0;
692 lldpd_update_localports(cfg);
693 lldpd_cleanup(cfg);
694 lldpd_update_localchassis(cfg);
695 lldpd_send_all(cfg);
696 lldpd_recv_all(cfg);
697 }
698
699 static void
700 lldpd_shutdown(int sig)
701 {
702 LLOG_INFO("signal received, exiting");
703 exit(0);
704 }
705
706 /* For signal handling */
707 static struct lldpd *gcfg = NULL;
708
709 static void
710 lldpd_exit()
711 {
712 struct lldpd_hardware *hardware, *hardware_next;
713 close(gcfg->g_ctl);
714 priv_ctl_cleanup();
715 for (hardware = TAILQ_FIRST(&gcfg->g_hardware); hardware != NULL;
716 hardware = hardware_next) {
717 hardware_next = TAILQ_NEXT(hardware, h_entries);
718 lldpd_hardware_cleanup(gcfg, hardware);
719 }
720 #ifdef USE_SNMP
721 if (gcfg->g_snmp)
722 agent_shutdown();
723 #endif /* USE_SNMP */
724 }
725
726 int
727 lldpd_main(int argc, char *argv[])
728 {
729 struct lldpd *cfg;
730 struct lldpd_chassis *lchassis;
731 int ch, debug = 0;
732 #ifdef USE_SNMP
733 int snmp = 0;
734 #endif
735 char *mgmtp = NULL;
736 char *popt, opts[] =
737 #ifdef ENABLE_LISTENVLAN
738 "v"
739 #endif
740 "dxm:p:M:i@ ";
741 int i, found;
742 #ifdef ENABLE_LISTENVLAN
743 int vlan = 0;
744 #endif
745 #ifdef ENABLE_LLDPMED
746 int lldpmed = 0, noinventory = 0;
747 #endif
748
749 saved_argv = argv;
750
751 /*
752 * Get and parse command line options
753 */
754 popt = strchr(opts, '@');
755 for (i=0; protos[i].mode != 0; i++) {
756 if (protos[i].enabled == 1) continue;
757 *(popt++) = protos[i].arg;
758 }
759 *popt = '\0';
760 while ((ch = getopt(argc, argv, opts)) != -1) {
761 switch (ch) {
762 #ifdef ENABLE_LISTENVLAN
763 case 'v':
764 vlan = 1;
765 break;
766 #endif
767 case 'd':
768 debug++;
769 break;
770 case 'm':
771 mgmtp = optarg;
772 break;
773 #ifdef ENABLE_LLDPMED
774 case 'M':
775 lldpmed = atoi(optarg);
776 if ((lldpmed < 1) || (lldpmed > 4)) {
777 fprintf(stderr, "-M requires an argument between 1 and 4\n");
778 usage();
779 }
780 break;
781 case 'i':
782 noinventory = 1;
783 break;
784 #else
785 case 'M':
786 case 'i':
787 case 'P':
788 fprintf(stderr, "LLDP-MED support is not built-in\n");
789 usage();
790 break;
791 #endif
792 case 'x':
793 #ifdef USE_SNMP
794 snmp = 1;
795 #else
796 fprintf(stderr, "SNMP support is not built-in\n");
797 usage();
798 #endif
799 break;
800 default:
801 found = 0;
802 for (i=0; protos[i].mode != 0; i++) {
803 if (protos[i].enabled) continue;
804 if (ch == protos[i].arg) {
805 protos[i].enabled = 1;
806 found = 1;
807 }
808 }
809 if (!found)
810 usage();
811 }
812 }
813
814 log_init(debug);
815
816 if (!debug) {
817 int pid;
818 char *spid;
819 if (daemon(0, 0) != 0)
820 fatal("failed to detach daemon");
821 if ((pid = open(LLDPD_PID_FILE,
822 O_TRUNC | O_CREAT | O_WRONLY, 0644)) == -1)
823 fatal("unable to open pid file " LLDPD_PID_FILE);
824 if (asprintf(&spid, "%d\n", getpid()) == -1)
825 fatal("unable to create pid file " LLDPD_PID_FILE);
826 if (write(pid, spid, strlen(spid)) == -1)
827 fatal("unable to write pid file " LLDPD_PID_FILE);
828 free(spid);
829 close(pid);
830 }
831
832 priv_init(PRIVSEP_CHROOT);
833
834 if ((cfg = (struct lldpd *)
835 calloc(1, sizeof(struct lldpd))) == NULL)
836 fatal(NULL);
837
838 cfg->g_mgmt_pattern = mgmtp;
839 #ifdef ENABLE_LISTENVLAN
840 cfg->g_listen_vlans = vlan;
841 #endif
842
843 /* Get ioctl socket */
844 if ((cfg->g_sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
845 fatal("failed to get ioctl socket");
846 cfg->g_delay = LLDPD_TX_DELAY;
847
848 /* Set system capabilities */
849 if ((lchassis = (struct lldpd_chassis*)
850 calloc(1, sizeof(struct lldpd_chassis))) == NULL)
851 fatal(NULL);
852 lchassis->c_cap_available = LLDP_CAP_BRIDGE | LLDP_CAP_WLAN |
853 LLDP_CAP_ROUTER;
854 #ifdef ENABLE_LLDPMED
855 if (lldpmed > 0) {
856 if (lldpmed == LLDPMED_CLASS_III)
857 lchassis->c_cap_available |= LLDP_CAP_TELEPHONE;
858 lchassis->c_med_type = lldpmed;
859 lchassis->c_med_cap_available = LLDPMED_CAP_CAP |
860 LLDPMED_CAP_IV | LLDPMED_CAP_LOCATION;
861 cfg->g_noinventory = noinventory;
862 } else
863 cfg->g_noinventory = 1;
864 #endif
865
866 /* Set TTL */
867 lchassis->c_ttl = LLDPD_TTL;
868
869 cfg->g_protocols = protos;
870 for (i=0; protos[i].mode != 0; i++)
871 if (protos[i].enabled) {
872 LLOG_INFO("protocol %s enabled", protos[i].name);
873 } else
874 LLOG_INFO("protocol %s disabled", protos[i].name);
875
876 TAILQ_INIT(&cfg->g_hardware);
877 TAILQ_INIT(&cfg->g_chassis);
878 TAILQ_INSERT_TAIL(&cfg->g_chassis, lchassis, c_entries);
879 lchassis->c_refcount++;
880
881 TAILQ_INIT(&cfg->g_callbacks);
882
883 #ifdef USE_SNMP
884 if (snmp) {
885 cfg->g_snmp = 1;
886 agent_init(cfg, debug);
887 }
888 #endif /* USE_SNMP */
889
890 /* Create socket */
891 if ((cfg->g_ctl = priv_ctl_create()) == -1)
892 fatalx("unable to create control socket " LLDPD_CTL_SOCKET);
893 if (lldpd_callback_add(cfg, cfg->g_ctl, ctl_accept, NULL) != 0)
894 fatalx("unable to add callback for control socket");
895
896 gcfg = cfg;
897 if (atexit(lldpd_exit) != 0) {
898 close(cfg->g_ctl);
899 priv_ctl_cleanup();
900 fatal("unable to set exit function");
901 }
902
903 /* Signal handling */
904 signal(SIGHUP, lldpd_shutdown);
905 signal(SIGINT, lldpd_shutdown);
906 signal(SIGTERM, lldpd_shutdown);
907
908 for (;;)
909 lldpd_loop(cfg);
910
911 return (0);
912 }