]> git.ipfire.org Git - thirdparty/lldpd.git/blob - src/lldpd.c
Move chassis update to a function.
[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 static void usage(void);
50
51 static int lldpd_iface_init(struct lldpd *, struct lldpd_hardware *);
52 static void lldpd_iface_init_mtu(struct lldpd *, struct lldpd_hardware *);
53 static int lldpd_iface_close(struct lldpd *, struct lldpd_hardware *);
54 static void lldpd_iface_multicast(struct lldpd *, const char *, int);
55
56 /* LLDP: "ether proto 0x88cc and ether dst 01:80:c2:00:00:0e" */
57 /* FDP: "ether dst 01:e0:52:cc:cc:cc" */
58 /* CDP: "ether dst 01:00:0c:cc:cc:cc" */
59 /* SONMP: "ether dst 01:00:81:00:01:00" */
60 /* EDP: "ether dst 00:e0:2b:00:00:00" */
61 #define LLDPD_FILTER_F \
62 { 0x28, 0, 0, 0x0000000c }, \
63 { 0x15, 0, 4, 0x000088cc }, \
64 { 0x20, 0, 0, 0x00000002 }, \
65 { 0x15, 0, 2, 0xc200000e }, \
66 { 0x28, 0, 0, 0x00000000 }, \
67 { 0x15, 11, 12, 0x00000180 }, \
68 { 0x20, 0, 0, 0x00000002 }, \
69 { 0x15, 0, 2, 0x2b000000 }, \
70 { 0x28, 0, 0, 0x00000000 }, \
71 { 0x15, 7, 8, 0x000000e0 }, \
72 { 0x15, 1, 0, 0x0ccccccc }, \
73 { 0x15, 0, 2, 0x81000100 }, \
74 { 0x28, 0, 0, 0x00000000 }, \
75 { 0x15, 3, 4, 0x00000100 }, \
76 { 0x15, 0, 3, 0x52cccccc }, \
77 { 0x28, 0, 0, 0x00000000 }, \
78 { 0x15, 0, 1, 0x000001e0 }, \
79 { 0x6, 0, 0, 0x0000ffff }, \
80 { 0x6, 0, 0, 0x00000000 },
81 static struct sock_filter lldpd_filter_f[] = { LLDPD_FILTER_F };
82
83 static struct protocol protos[] =
84 {
85 { LLDPD_MODE_LLDP, 1, "LLDP", ' ', lldp_send, lldp_decode, NULL,
86 LLDP_MULTICAST_ADDR },
87 #ifdef ENABLE_CDP
88 { LLDPD_MODE_CDPV1, 0, "CDPv1", 'c', cdpv1_send, cdp_decode, cdpv1_guess,
89 CDP_MULTICAST_ADDR },
90 { LLDPD_MODE_CDPV2, 0, "CDPv2", 'c', cdpv2_send, cdp_decode, cdpv2_guess,
91 CDP_MULTICAST_ADDR },
92 #endif
93 #ifdef ENABLE_SONMP
94 { LLDPD_MODE_SONMP, 0, "SONMP", 's', sonmp_send, sonmp_decode, NULL,
95 SONMP_MULTICAST_ADDR },
96 #endif
97 #ifdef ENABLE_EDP
98 { LLDPD_MODE_EDP, 0, "EDP", 'e', edp_send, edp_decode, NULL,
99 EDP_MULTICAST_ADDR },
100 #endif
101 #ifdef ENABLE_FDP
102 { LLDPD_MODE_FDP, 0, "FDP", 'f', fdp_send, cdp_decode, NULL,
103 FDP_MULTICAST_ADDR },
104 #endif
105 { 0, 0, "any", ' ', NULL, NULL, NULL,
106 {0,0,0,0,0,0} }
107 };
108
109 static
110 struct lldpd_hardware *lldpd_hardware_add(struct lldpd *, struct ifaddrs *);
111 static void lldpd_loop(struct lldpd *);
112 static void lldpd_shutdown(int);
113 static void lldpd_exit();
114 static void lldpd_send_all(struct lldpd *);
115 static void lldpd_recv_all(struct lldpd *);
116 static int lldpd_guess_type(struct lldpd *, char *, int);
117 static void lldpd_decode(struct lldpd *, char *, int,
118 struct lldpd_hardware *);
119 static void lldpd_update_chassis(struct lldpd_chassis *,
120 const struct lldpd_chassis *);
121 #ifdef ENABLE_LLDPMED
122 static void lldpd_med(struct lldpd_chassis *);
123 #endif
124
125 static char **saved_argv;
126
127 static void
128 usage(void)
129 {
130 extern const char *__progname;
131 fprintf(stderr, "usage: %s [options]\n", __progname);
132 fprintf(stderr, "see manual page lldpd(8) for more information\n");
133 exit(1);
134 }
135
136 static void
137 lldpd_iface_init_mtu(struct lldpd *global, struct lldpd_hardware *hardware)
138 {
139 struct ifreq ifr;
140
141 /* get MTU */
142 memset(&ifr, 0, sizeof(ifr));
143 strlcpy(ifr.ifr_name, hardware->h_ifname, sizeof(ifr.ifr_name));
144 if (ioctl(global->g_sock, SIOCGIFMTU, (char*)&ifr) == -1) {
145 LLOG_WARN("unable to get MTU of %s, using 1500", hardware->h_ifname);
146 hardware->h_mtu = 1500;
147 } else
148 hardware->h_mtu = hardware->h_lport.p_mfs = ifr.ifr_mtu;
149 }
150
151 static int
152 lldpd_iface_init(struct lldpd *global, struct lldpd_hardware *hardware)
153 {
154 int status;
155 struct sock_fprog prog;
156
157 lldpd_iface_init_mtu(global, hardware);
158 status = priv_iface_init(hardware, -1);
159 if (status != 0)
160 return status;
161
162 /* Set filter */
163 prog.filter = lldpd_filter_f;
164 prog.len = sizeof(lldpd_filter_f) / sizeof(struct sock_filter);
165 if (setsockopt(hardware->h_raw, SOL_SOCKET, SO_ATTACH_FILTER,
166 &prog, sizeof(prog)) < 0) {
167 LLOG_WARN("unable to change filter for %s", hardware->h_ifname);
168 return ENETDOWN;
169 }
170
171 lldpd_iface_multicast(global, hardware->h_ifname, 0);
172
173 LLOG_DEBUG("interface %s initialized (fd=%d)", hardware->h_ifname,
174 hardware->h_raw);
175 return 0;
176 }
177
178 static void
179 lldpd_iface_multicast(struct lldpd *global, const char *name, int remove)
180 {
181 int i, rc;
182
183 for (i=0; global->g_protocols[i].mode != 0; i++) {
184 if (!global->g_protocols[i].enabled) continue;
185 if ((rc = priv_iface_multicast(name,
186 global->g_protocols[i].mac, !remove)) != 0) {
187 errno = rc;
188 if (errno != ENOENT)
189 LLOG_INFO("unable to %s %s address to multicast filter for %s",
190 (remove)?"delete":"add",
191 global->g_protocols[i].name,
192 name);
193 }
194 }
195 }
196
197 static int
198 lldpd_iface_close(struct lldpd *global, struct lldpd_hardware *hardware)
199 {
200 char listen[IFNAMSIZ];
201
202 close(hardware->h_raw);
203 hardware->h_raw = -1;
204
205 memcpy(listen, hardware->h_ifname, IFNAMSIZ);
206 lldpd_iface_multicast(global, listen, 1);
207
208 return 0;
209 }
210
211 #ifdef ENABLE_DOT1
212 void
213 lldpd_vlan_cleanup(struct lldpd_port *port)
214 {
215 struct lldpd_vlan *vlan, *vlan_next;
216 for (vlan = TAILQ_FIRST(&port->p_vlans);
217 vlan != NULL;
218 vlan = vlan_next) {
219 free(vlan->v_name);
220 vlan_next = TAILQ_NEXT(vlan, v_entries);
221 TAILQ_REMOVE(&port->p_vlans, vlan, v_entries);
222 free(vlan);
223 }
224 }
225 #endif
226
227 /* If `all' is true, clear all information, including information that
228 are not refreshed periodically. If `all' is true, also free the
229 port. */
230 void
231 lldpd_port_cleanup(struct lldpd_port *port, int all)
232 {
233 #ifdef ENABLE_LLDPMED
234 int i;
235 if (all)
236 for (i=0; i < LLDPMED_LOCFORMAT_LAST; i++)
237 free(port->p_med_location[i].data);
238 #endif
239 #ifdef ENABLE_DOT1
240 lldpd_vlan_cleanup(port);
241 #endif
242 free(port->p_id);
243 free(port->p_descr);
244 if (all) {
245 free(port->p_lastframe);
246 if (port->p_chassis) /* chassis may not have been attributed, yet */
247 port->p_chassis->c_refcount--;
248 free(port);
249 }
250 }
251
252 void
253 lldpd_chassis_cleanup(struct lldpd_chassis *chassis, int all)
254 {
255 #ifdef ENABLE_LLDPMED
256 free(chassis->c_med_hw);
257 free(chassis->c_med_sw);
258 free(chassis->c_med_fw);
259 free(chassis->c_med_sn);
260 free(chassis->c_med_manuf);
261 free(chassis->c_med_model);
262 free(chassis->c_med_asset);
263 #endif
264 free(chassis->c_id);
265 free(chassis->c_name);
266 free(chassis->c_descr);
267 if (all)
268 free(chassis);
269 }
270
271 void
272 lldpd_remote_cleanup(struct lldpd *cfg, struct lldpd_hardware *hardware, int all)
273 {
274 struct lldpd_port *port, *port_next;
275 int del;
276 for (port = TAILQ_FIRST(&hardware->h_rports);
277 port != NULL;
278 port = port_next) {
279 port_next = TAILQ_NEXT(port, p_entries);
280 del = all;
281 if (!del &&
282 (time(NULL) - port->p_lastupdate > port->p_chassis->c_ttl)) {
283 hardware->h_rx_ageout_cnt++;
284 del = 1;
285 }
286 if (del) {
287 TAILQ_REMOVE(&hardware->h_rports, port, p_entries);
288 lldpd_port_cleanup(port, 1);
289 }
290 }
291 }
292
293 void
294 lldpd_hardware_cleanup(struct lldpd_hardware *hardware)
295 {
296 lldpd_port_cleanup(&hardware->h_lport, 1);
297 free(hardware);
298 }
299
300 void
301 lldpd_cleanup(struct lldpd *cfg)
302 {
303 struct lldpd_hardware *hardware, *hardware_next;
304
305 for (hardware = TAILQ_FIRST(&cfg->g_hardware); hardware != NULL;
306 hardware = hardware_next) {
307 hardware_next = TAILQ_NEXT(hardware, h_entries);
308 if (hardware->h_flags == 0) {
309 TAILQ_REMOVE(&cfg->g_hardware, hardware, h_entries);
310 lldpd_iface_close(cfg, hardware);
311 lldpd_remote_cleanup(cfg, hardware, 1);
312 lldpd_hardware_cleanup(hardware);
313 } else
314 lldpd_remote_cleanup(cfg, hardware, 0);
315 }
316 }
317
318 static struct lldpd_hardware *
319 lldpd_hardware_add(struct lldpd *cfg, struct ifaddrs *ifa)
320 {
321 #if defined (ENABLE_DOT1) || defined (ENABLE_DOT3)
322 struct ifaddrs *oifap, *oifa;
323 #endif
324 struct lldpd_hardware *hardware;
325 struct lldpd_port *port;
326 #ifdef ENABLE_DOT1
327 struct lldpd_vlan *vlan;
328 struct vlan_ioctl_args ifv;
329 #endif
330 #ifdef ENABLE_DOT3
331 struct ethtool_cmd ethc;
332 #endif
333 u_int8_t *lladdr;
334
335 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
336 if (strcmp(hardware->h_ifname, ifa->ifa_name) == 0)
337 break;
338 }
339
340 if (hardware == NULL) {
341 if ((hardware = (struct lldpd_hardware *)
342 calloc(1, sizeof(struct lldpd_hardware))) == NULL)
343 return (NULL);
344 hardware->h_raw = -1;
345 hardware->h_lport.p_chassis = LOCAL_CHASSIS(cfg);
346 TAILQ_INIT(&hardware->h_rports);
347 #ifdef ENABLE_LLDPMED
348 if (LOCAL_CHASSIS(cfg)->c_med_cap_available) {
349 hardware->h_lport.p_med_cap_enabled = LLDPMED_CAP_CAP;
350 if (!cfg->g_noinventory)
351 hardware->h_lport.p_med_cap_enabled |= LLDPMED_CAP_IV;
352 }
353 #endif
354 #ifdef ENABLE_DOT1
355 TAILQ_INIT(&hardware->h_lport.p_vlans);
356 } else {
357 lldpd_port_cleanup(&hardware->h_lport, 0);
358 #endif
359 }
360
361 port = &hardware->h_lport;
362 hardware->h_flags = ifa->ifa_flags;
363
364 strlcpy(hardware->h_ifname, ifa->ifa_name, sizeof(hardware->h_ifname));
365 lladdr = (u_int8_t*)(((struct sockaddr_ll *)ifa->ifa_addr)->sll_addr);
366 memcpy(&hardware->h_lladdr, lladdr, sizeof(hardware->h_lladdr));
367 iface_get_permanent_mac(cfg, hardware);
368 port->p_id_subtype = LLDP_PORTID_SUBTYPE_LLADDR;
369 if ((port->p_id = calloc(1, sizeof(hardware->h_lladdr))) == NULL)
370 fatal(NULL);
371 memcpy(port->p_id, hardware->h_lladdr, sizeof(hardware->h_lladdr));
372 port->p_id_len = sizeof(hardware->h_lladdr);
373 port->p_descr = strdup(hardware->h_ifname);
374
375 if (LOCAL_CHASSIS(cfg)->c_id == NULL) {
376 /* Use the first port's l2 addr as the chassis ID */
377 if ((LOCAL_CHASSIS(cfg)->c_id =
378 malloc(sizeof(hardware->h_lladdr))) == NULL)
379 fatal(NULL);
380 LOCAL_CHASSIS(cfg)->c_id_subtype = LLDP_CHASSISID_SUBTYPE_LLADDR;
381 LOCAL_CHASSIS(cfg)->c_id_len = sizeof(hardware->h_lladdr);
382 memcpy(LOCAL_CHASSIS(cfg)->c_id,
383 hardware->h_lladdr, sizeof(hardware->h_lladdr));
384 }
385
386 /* Get VLANS and aggregation status */
387 #if defined (ENABLE_DOT3) || defined (ENABLE_DOT1)
388 if (getifaddrs(&oifap) != 0)
389 fatal("lldpd_hardware_add: failed to get interface list");
390 for (oifa = oifap; oifa != NULL; oifa = oifa->ifa_next) {
391 #ifdef ENABLE_DOT1
392 /* Check if we already have checked this one */
393 int skip = 0;
394 TAILQ_FOREACH(vlan, &port->p_vlans, v_entries) {
395 if (strcmp(vlan->v_name, oifa->ifa_name) == 0) {
396 skip = 1;
397 break;
398 }
399 }
400 if (skip) continue;
401 #endif
402
403 /* Aggregation check */
404 #ifdef ENABLE_DOT3
405 if (iface_is_bond_slave(cfg, hardware->h_ifname, oifa->ifa_name, NULL))
406 port->p_aggregid = if_nametoindex(oifa->ifa_name);
407 #endif
408
409 #ifdef ENABLE_DOT1
410 /* VLAN check */
411 memset(&ifv, 0, sizeof(ifv));
412 ifv.cmd = GET_VLAN_REALDEV_NAME_CMD;
413 strlcpy(ifv.device1, oifa->ifa_name, sizeof(ifv.device1));
414 if ((ioctl(cfg->g_sock, SIOCGIFVLAN, &ifv) >= 0) &&
415 ((iface_is_bond_slave(cfg, hardware->h_ifname, ifv.u.device2, NULL)) ||
416 (iface_is_bridged_to(cfg, hardware->h_ifname, ifv.u.device2)) ||
417 (strncmp(hardware->h_ifname, ifv.u.device2, sizeof(ifv.u.device2)) == 0))) {
418 if ((vlan = (struct lldpd_vlan *)
419 calloc(1, sizeof(struct lldpd_vlan))) == NULL)
420 continue;
421 if ((vlan->v_name = strdup(oifa->ifa_name)) == NULL) {
422 free(vlan);
423 continue;
424 }
425 memset(&ifv, 0, sizeof(ifv));
426 ifv.cmd = GET_VLAN_VID_CMD;
427 strlcpy(ifv.device1, oifa->ifa_name, sizeof(ifv.device1));
428 if (ioctl(cfg->g_sock, SIOCGIFVLAN, &ifv) < 0) {
429 /* Dunno what happened */
430 free(vlan->v_name);
431 free(vlan);
432 } else {
433 vlan->v_vid = ifv.u.VID;
434 TAILQ_INSERT_TAIL(&port->p_vlans, vlan, v_entries);
435 }
436 }
437 #endif
438 }
439 freeifaddrs(oifap);
440 #endif
441
442 #ifdef ENABLE_DOT3
443 /* MAC/PHY */
444 if (priv_ethtool(hardware->h_ifname, &ethc) == 0) {
445 int j;
446 int advertised_ethtool_to_rfc3636[][2] = {
447 {ADVERTISED_10baseT_Half, LLDP_DOT3_LINK_AUTONEG_10BASE_T},
448 {ADVERTISED_10baseT_Full, LLDP_DOT3_LINK_AUTONEG_10BASET_FD},
449 {ADVERTISED_100baseT_Half, LLDP_DOT3_LINK_AUTONEG_100BASE_TX},
450 {ADVERTISED_100baseT_Full, LLDP_DOT3_LINK_AUTONEG_100BASE_TXFD},
451 {ADVERTISED_1000baseT_Half, LLDP_DOT3_LINK_AUTONEG_1000BASE_T},
452 {ADVERTISED_1000baseT_Full, LLDP_DOT3_LINK_AUTONEG_1000BASE_TFD},
453 {ADVERTISED_10000baseT_Full, LLDP_DOT3_LINK_AUTONEG_OTHER},
454 {ADVERTISED_Pause, LLDP_DOT3_LINK_AUTONEG_FDX_PAUSE},
455 {ADVERTISED_Asym_Pause, LLDP_DOT3_LINK_AUTONEG_FDX_APAUSE},
456 {ADVERTISED_2500baseX_Full, LLDP_DOT3_LINK_AUTONEG_OTHER},
457 {0,0}};
458
459 port->p_autoneg_support = (ethc.supported & SUPPORTED_Autoneg) ? 1 : 0;
460 port->p_autoneg_enabled = (ethc.autoneg == AUTONEG_DISABLE) ? 0 : 1;
461 for (j=0; advertised_ethtool_to_rfc3636[j][0]; j++) {
462 if (ethc.advertising & advertised_ethtool_to_rfc3636[j][0])
463 port->p_autoneg_advertised |= advertised_ethtool_to_rfc3636[j][1];
464 }
465 switch (ethc.speed) {
466 case SPEED_10:
467 port->p_mau_type = (ethc.duplex == DUPLEX_FULL) ? \
468 LLDP_DOT3_MAU_10BASETFD : LLDP_DOT3_MAU_10BASETHD;
469 if (ethc.port == PORT_BNC) port->p_mau_type = LLDP_DOT3_MAU_10BASE2;
470 if (ethc.port == PORT_FIBRE)
471 port->p_mau_type = (ethc.duplex == DUPLEX_FULL) ? \
472 LLDP_DOT3_MAU_10BASEFLDF : LLDP_DOT3_MAU_10BASEFLHD;
473 break;
474 case SPEED_100:
475 port->p_mau_type = (ethc.duplex == DUPLEX_FULL) ? \
476 LLDP_DOT3_MAU_100BASETXFD : LLDP_DOT3_MAU_100BASETXHD;
477 if (ethc.port == PORT_BNC)
478 port->p_mau_type = (ethc.duplex == DUPLEX_FULL) ? \
479 LLDP_DOT3_MAU_100BASET2DF : LLDP_DOT3_MAU_100BASET2HD;
480 if (ethc.port == PORT_FIBRE)
481 port->p_mau_type = (ethc.duplex == DUPLEX_FULL) ? \
482 LLDP_DOT3_MAU_100BASEFXFD : LLDP_DOT3_MAU_100BASEFXHD;
483 break;
484 case SPEED_1000:
485 port->p_mau_type = (ethc.duplex == DUPLEX_FULL) ? \
486 LLDP_DOT3_MAU_1000BASETFD : LLDP_DOT3_MAU_1000BASETHD;
487 if (ethc.port == PORT_FIBRE)
488 port->p_mau_type = (ethc.duplex == DUPLEX_FULL) ? \
489 LLDP_DOT3_MAU_1000BASEXFD : LLDP_DOT3_MAU_1000BASEXHD;
490 break;
491 case SPEED_10000:
492 port->p_mau_type = (ethc.port == PORT_FIBRE) ? \
493 LLDP_DOT3_MAU_10GIGBASEX : LLDP_DOT3_MAU_10GIGBASER;
494 break;
495 }
496 if (ethc.port == PORT_AUI) port->p_mau_type = LLDP_DOT3_MAU_AUI;
497 } else
498 LLOG_DEBUG("unable to get eth info for %s", hardware->h_ifname);
499 #endif
500
501 if (!INTERFACE_OPENED(hardware)) {
502
503 if (lldpd_iface_init(cfg, hardware) != 0) {
504 LLOG_WARN("unable to initialize %s", hardware->h_ifname);
505 lldpd_hardware_cleanup(hardware);
506 return (NULL);
507 }
508
509 TAILQ_INSERT_TAIL(&cfg->g_hardware, hardware, h_entries);
510 }
511
512 return (hardware);
513 }
514
515 static int
516 lldpd_guess_type(struct lldpd *cfg, char *frame, int s)
517 {
518 int i;
519 if (s < ETH_ALEN)
520 return -1;
521 for (i=0; cfg->g_protocols[i].mode != 0; i++) {
522 if (!cfg->g_protocols[i].enabled)
523 continue;
524 if (cfg->g_protocols[i].guess == NULL) {
525 if (memcmp(frame, cfg->g_protocols[i].mac, ETH_ALEN) == 0)
526 return cfg->g_protocols[i].mode;
527 } else {
528 if (cfg->g_protocols[i].guess(frame, s))
529 return cfg->g_protocols[i].mode;
530 }
531 }
532 return -1;
533 }
534
535 static void
536 lldpd_decode(struct lldpd *cfg, char *frame, int s,
537 struct lldpd_hardware *hardware)
538 {
539 int i, result;
540 struct lldpd_chassis *chassis, *ochassis = NULL;
541 struct lldpd_port *port, *oport = NULL;
542 int guess = LLDPD_MODE_LLDP;
543
544 /* Discard VLAN frames */
545 if ((s >= sizeof(struct ethhdr)) &&
546 (((struct ethhdr*)frame)->h_proto == htons(ETHERTYPE_VLAN)))
547 return;
548
549 TAILQ_FOREACH(oport, &hardware->h_rports, p_entries) {
550 if ((oport->p_lastframe != NULL) &&
551 (oport->p_lastframe->size == s) &&
552 (memcmp(oport->p_lastframe->frame, frame, s) == 0)) {
553 /* Already received the same frame */
554 oport->p_lastupdate = time(NULL);
555 return;
556 }
557 }
558
559 guess = lldpd_guess_type(cfg, frame, s);
560 for (i=0; cfg->g_protocols[i].mode != 0; i++) {
561 if (!cfg->g_protocols[i].enabled)
562 continue;
563 if (cfg->g_protocols[i].mode == guess) {
564 if ((result = cfg->g_protocols[i].decode(cfg, frame,
565 s, hardware, &chassis, &port)) == -1)
566 return;
567 chassis->c_protocol = port->p_protocol =
568 cfg->g_protocols[i].mode;
569 break;
570 }
571 }
572 if (cfg->g_protocols[i].mode == 0) {
573 LLOG_INFO("unable to guess frame type");
574 return;
575 }
576
577 /* Do we already have the same MSAP somewhere? */
578 TAILQ_FOREACH(oport, &hardware->h_rports, p_entries) {
579 if ((port->p_protocol == oport->p_protocol) &&
580 (port->p_id_subtype == oport->p_id_subtype) &&
581 (port->p_id_len == oport->p_id_len) &&
582 (memcmp(port->p_id, oport->p_id, port->p_id_len) == 0) &&
583 (chassis->c_id_subtype == oport->p_chassis->c_id_subtype) &&
584 (chassis->c_id_len == oport->p_chassis->c_id_len) &&
585 (memcmp(chassis->c_id, oport->p_chassis->c_id,
586 chassis->c_id_len) == 0)) {
587 ochassis = oport->p_chassis;
588 break;
589 }
590 }
591 /* No, but do we already know the system? */
592 if (!oport) {
593 TAILQ_FOREACH(ochassis, &cfg->g_chassis, c_entries) {
594 if ((chassis->c_protocol == ochassis->c_protocol) &&
595 (chassis->c_id_subtype == ochassis->c_id_subtype) &&
596 (chassis->c_id_len == ochassis->c_id_len) &&
597 (memcmp(chassis->c_id, ochassis->c_id,
598 chassis->c_id_len) == 0))
599 break;
600 }
601 }
602
603 if (oport) {
604 /* The port is known, remove it before adding it back */
605 TAILQ_REMOVE(&hardware->h_rports, oport, p_entries);
606 lldpd_port_cleanup(oport, 1);
607 }
608 if (ochassis) {
609 lldpd_update_chassis(ochassis, chassis);
610 free(chassis);
611 chassis = ochassis;
612 } else {
613 /* Chassis not known, add it */
614 chassis->c_index = ++cfg->g_lastrid;
615 port->p_chassis = chassis;
616 chassis->c_refcount = 0;
617 TAILQ_INSERT_TAIL(&cfg->g_chassis, chassis, c_entries);
618 i = 0; TAILQ_FOREACH(ochassis, &cfg->g_chassis, c_entries) i++;
619 LLOG_DEBUG("Currently, we know %d different systems", i);
620 }
621 /* Add port */
622 port->p_lastchange = port->p_lastupdate = time(NULL);
623 if ((port->p_lastframe = (struct lldpd_frame *)malloc(s +
624 sizeof(int))) != NULL) {
625 port->p_lastframe->size = s;
626 memcpy(port->p_lastframe->frame, frame, s);
627 }
628 TAILQ_INSERT_TAIL(&hardware->h_rports, port, p_entries);
629 port->p_chassis = chassis;
630 port->p_chassis->c_refcount++;
631 i = 0; TAILQ_FOREACH(oport, &hardware->h_rports, p_entries) i++;
632 LLOG_DEBUG("Currently, %s known %d neighbors",
633 hardware->h_ifname, i);
634 return;
635 }
636
637 /* Update chassis `ochassis' with values from `chassis'. */
638 static void
639 lldpd_update_chassis(struct lldpd_chassis *ochassis,
640 const struct lldpd_chassis *chassis) {
641 TAILQ_ENTRY(lldpd_chassis) entries;
642 /* We want to keep refcount, index and list stuff from the current
643 * chassis */
644 int refcount = ochassis->c_refcount;
645 int index = ochassis->c_index;
646 memcpy(&entries, &ochassis->c_entries,
647 sizeof(entries));
648 /* Make the copy */
649 lldpd_chassis_cleanup(ochassis, 0);
650 memcpy(ochassis, chassis, sizeof(struct lldpd_chassis));
651 /* Restore saved values */
652 ochassis->c_refcount = refcount;
653 ochassis->c_index = index;
654 memcpy(&ochassis->c_entries, &entries, sizeof(entries));
655 }
656
657
658 static void
659 lldpd_recv_all(struct lldpd *cfg)
660 {
661 struct lldpd_hardware *hardware;
662 struct lldpd_client *client, *client_next;
663 fd_set rfds;
664 struct timeval tv;
665 struct sockaddr_ll from;
666 socklen_t fromlen;
667 #ifdef USE_SNMP
668 int fakeblock = 0;
669 struct timeval *tvp = &tv;
670 #endif
671 int rc, nfds, n;
672 char *buffer;
673
674 do {
675 tv.tv_sec = cfg->g_delay - (time(NULL) - cfg->g_lastsent);
676 if (tv.tv_sec < 0)
677 tv.tv_sec = LLDPD_TX_DELAY;
678 if (tv.tv_sec >= cfg->g_delay)
679 tv.tv_sec = cfg->g_delay;
680 tv.tv_usec = 0;
681
682 FD_ZERO(&rfds);
683 nfds = -1;
684
685 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
686 /* Ignore if interface is down */
687 if (((hardware->h_flags & IFF_UP) == 0) ||
688 ((hardware->h_flags & IFF_RUNNING) == 0))
689 continue;
690 FD_SET(hardware->h_raw, &rfds);
691 if (nfds < hardware->h_raw)
692 nfds = hardware->h_raw;
693 }
694 TAILQ_FOREACH(client, &cfg->g_clients, next) {
695 FD_SET(client->fd, &rfds);
696 if (nfds < client->fd)
697 nfds = client->fd;
698 }
699 FD_SET(cfg->g_ctl, &rfds);
700 if (nfds < cfg->g_ctl)
701 nfds = cfg->g_ctl;
702
703 #ifdef USE_SNMP
704 if (cfg->g_snmp)
705 snmp_select_info(&nfds, &rfds, tvp, &fakeblock);
706 #endif /* USE_SNMP */
707 if (nfds == -1) {
708 sleep(cfg->g_delay);
709 return;
710 }
711
712 rc = select(nfds + 1, &rfds, NULL, NULL, &tv);
713 if (rc == -1) {
714 if (errno == EINTR)
715 continue;
716 LLOG_WARN("failure on select");
717 break;
718 }
719 #ifdef USE_SNMP
720 if (cfg->g_snmp) {
721 if (rc > 0)
722 snmp_read(&rfds);
723 else if (rc == 0)
724 snmp_timeout();
725 }
726 #endif /* USE_SNMP */
727 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
728 /* We could have received something on _real_
729 * interface. However, even in this case, this could be
730 * just an outgoing packet. We will try to handle both
731 * cases, but maybe not in the same select. */
732 if (FD_ISSET(hardware->h_raw, &rfds)) {
733 if ((buffer = (char *)malloc(
734 hardware->h_mtu)) == NULL) {
735 LLOG_WARN("failed to alloc reception buffer");
736 continue;
737 }
738 fromlen = sizeof(from);
739 if ((n = recvfrom(
740 hardware->h_raw,
741 buffer,
742 hardware->h_mtu, 0,
743 (struct sockaddr *)&from,
744 &fromlen)) == -1) {
745 LLOG_WARN("error while receiving frame on %s",
746 hardware->h_ifname);
747 hardware->h_rx_discarded_cnt++;
748 free(buffer);
749 continue;
750 }
751 if (from.sll_pkttype == PACKET_OUTGOING) {
752 free(buffer);
753 continue;
754 }
755 hardware->h_rx_cnt++;
756 lldpd_decode(cfg, buffer, n, hardware);
757 free(buffer);
758 }
759
760 }
761 if (FD_ISSET(cfg->g_ctl, &rfds)) {
762 if (ctl_accept(cfg, cfg->g_ctl) == -1)
763 LLOG_WARN("unable to accept new client");
764 }
765 for (client = TAILQ_FIRST(&cfg->g_clients);
766 client != NULL;
767 client = client_next) {
768 client_next = TAILQ_NEXT(client, next);
769 if (FD_ISSET(client->fd, &rfds)) {
770 /* Got a message */
771 if ((buffer = (char *)malloc(MAX_HMSGSIZE)) ==
772 NULL) {
773 LLOG_WARN("failed to alloc reception buffer");
774 continue;
775 }
776 if ((n = recv(client->fd, buffer,
777 MAX_HMSGSIZE, 0)) == -1) {
778 LLOG_WARN("error while receiving message");
779 free(buffer);
780 continue;
781 }
782 if (n > 0)
783 client_handle_client(cfg, client, buffer, n);
784 else
785 ctl_close(cfg, client->fd); /* Will use TAILQ_REMOVE ! */
786 free(buffer);
787 }
788 }
789
790 #ifdef USE_SNMP
791 if (cfg->g_snmp) {
792 run_alarms();
793 netsnmp_check_outstanding_agent_requests();
794 }
795 #endif /* USE_SNMP */
796 } while ((rc != 0) || (time(NULL) - cfg->g_lastsent < cfg->g_delay));
797 }
798
799 static void
800 lldpd_send_all(struct lldpd *cfg)
801 {
802 struct lldpd_hardware *hardware;
803 struct lldpd_port *port;
804 int i, sent = 0;
805
806 cfg->g_lastsent = time(NULL);
807 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
808 /* Ignore if interface is down */
809 if (((hardware->h_flags & IFF_UP) == 0) ||
810 ((hardware->h_flags & IFF_RUNNING) == 0))
811 continue;
812
813 for (i=0; cfg->g_protocols[i].mode != 0; i++) {
814 if (!cfg->g_protocols[i].enabled)
815 continue;
816 /* We send only if we have at least one remote system
817 * speaking this protocol */
818 TAILQ_FOREACH(port, &hardware->h_rports, p_entries) {
819 if (port->p_protocol ==
820 cfg->g_protocols[i].mode) {
821 cfg->g_protocols[i].send(cfg,
822 hardware);
823 sent = 1;
824 break;
825 }
826 }
827 }
828
829 if (!sent)
830 /* Nothing was sent for this port, let's speak LLDP */
831 cfg->g_protocols[0].send(cfg,
832 hardware);
833 }
834 }
835
836 #ifdef ENABLE_LLDPMED
837 static void
838 lldpd_med(struct lldpd_chassis *chassis)
839 {
840 free(chassis->c_med_hw);
841 free(chassis->c_med_fw);
842 free(chassis->c_med_sn);
843 free(chassis->c_med_manuf);
844 free(chassis->c_med_model);
845 free(chassis->c_med_asset);
846 chassis->c_med_hw = dmi_hw();
847 chassis->c_med_fw = dmi_fw();
848 chassis->c_med_sn = dmi_sn();
849 chassis->c_med_manuf = dmi_manuf();
850 chassis->c_med_model = dmi_model();
851 chassis->c_med_asset = dmi_asset();
852 }
853 #endif
854
855 static void
856 lldpd_loop(struct lldpd *cfg)
857 {
858 struct ifaddrs *ifap, *ifa;
859 struct sockaddr_ll *sdl;
860 struct lldpd_hardware *hardware;
861 int f;
862 char status;
863 struct utsname *un;
864 char *hp;
865
866 /* Set system name and description */
867 if ((un = (struct utsname*)malloc(sizeof(struct utsname))) == NULL)
868 fatal(NULL);
869 if (uname(un) != 0)
870 fatal("failed to get system information");
871 if ((hp = priv_gethostbyname()) == NULL)
872 fatal("failed to get system name");
873 free(LOCAL_CHASSIS(cfg)->c_name);
874 free(LOCAL_CHASSIS(cfg)->c_descr);
875 if ((LOCAL_CHASSIS(cfg)->c_name = strdup(hp)) == NULL)
876 fatal(NULL);
877 if (asprintf(&LOCAL_CHASSIS(cfg)->c_descr, "%s %s %s %s",
878 un->sysname, un->release, un->version, un->machine) == -1)
879 fatal("failed to set system description");
880
881 /* Check forwarding */
882 LOCAL_CHASSIS(cfg)->c_cap_enabled = 0;
883 if ((f = priv_open("/proc/sys/net/ipv4/ip_forward")) >= 0) {
884 if ((read(f, &status, 1) == 1) && (status == '1')) {
885 LOCAL_CHASSIS(cfg)->c_cap_enabled = LLDP_CAP_ROUTER;
886 }
887 close(f);
888 }
889 #ifdef ENABLE_LLDPMED
890 if (LOCAL_CHASSIS(cfg)->c_cap_available & LLDP_CAP_TELEPHONE)
891 LOCAL_CHASSIS(cfg)->c_cap_enabled |= LLDP_CAP_TELEPHONE;
892 lldpd_med(LOCAL_CHASSIS(cfg));
893 free(LOCAL_CHASSIS(cfg)->c_med_sw);
894 LOCAL_CHASSIS(cfg)->c_med_sw = strdup(un->release);
895 #endif
896 free(un);
897
898 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries)
899 hardware->h_flags = 0;
900
901 if (getifaddrs(&ifap) != 0)
902 fatal("lldpd_loop: failed to get interface list");
903
904 LOCAL_CHASSIS(cfg)->c_mgmt.s_addr = INADDR_ANY;
905 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
906 if (LOCAL_CHASSIS(cfg)->c_mgmt.s_addr == INADDR_ANY)
907 /* Get management address, if available */
908 if ((ifa->ifa_addr != NULL) &&
909 (ifa->ifa_addr->sa_family == AF_INET)) {
910 struct sockaddr_in *sa;
911 sa = (struct sockaddr_in *)ifa->ifa_addr;
912 if ((ntohl(*(u_int32_t*)&sa->sin_addr) != INADDR_LOOPBACK) &&
913 (cfg->g_mgmt_pattern == NULL)) {
914 memcpy(&LOCAL_CHASSIS(cfg)->c_mgmt,
915 &sa->sin_addr,
916 sizeof(struct in_addr));
917 LOCAL_CHASSIS(cfg)->c_mgmt_if = if_nametoindex(ifa->ifa_name);
918 }
919 else if (cfg->g_mgmt_pattern != NULL) {
920 char *ip;
921 ip = inet_ntoa(sa->sin_addr);
922 if (fnmatch(cfg->g_mgmt_pattern,
923 ip, 0) == 0) {
924 memcpy(&LOCAL_CHASSIS(cfg)->c_mgmt,
925 &sa->sin_addr,
926 sizeof(struct in_addr));
927 LOCAL_CHASSIS(cfg)->c_mgmt_if =
928 if_nametoindex(ifa->ifa_name);
929 }
930 }
931 }
932
933 if (ifa->ifa_addr == NULL ||
934 ifa->ifa_addr->sa_family != PF_PACKET)
935 continue;
936
937 sdl = (struct sockaddr_ll *)ifa->ifa_addr;
938 if (sdl->sll_hatype != ARPHRD_ETHER || !sdl->sll_halen)
939 continue;
940
941 if (iface_is_bridge(cfg, ifa->ifa_name)) {
942 LOCAL_CHASSIS(cfg)->c_cap_enabled |= LLDP_CAP_BRIDGE;
943 continue;
944 }
945
946 if ((iface_is_vlan(cfg, ifa->ifa_name)) ||
947 (iface_is_bond(cfg, ifa->ifa_name)))
948 continue;
949
950 if (!(ifa->ifa_flags & (IFF_MULTICAST|IFF_BROADCAST)))
951 continue;
952
953 if (iface_is_wireless(cfg, ifa->ifa_name))
954 LOCAL_CHASSIS(cfg)->c_cap_enabled |= LLDP_CAP_WLAN;
955
956 if (lldpd_hardware_add(cfg, ifa) == NULL)
957 LLOG_WARNX("failed to allocate port %s, skip it",
958 ifa->ifa_name);
959 }
960
961 freeifaddrs(ifap);
962
963 lldpd_cleanup(cfg);
964
965 lldpd_send_all(cfg);
966 lldpd_recv_all(cfg);
967 }
968
969 static void
970 lldpd_shutdown(int sig)
971 {
972 LLOG_INFO("signal received, exiting");
973 exit(0);
974 }
975
976 /* For signal handling */
977 static struct lldpd *gcfg = NULL;
978
979 static void
980 lldpd_exit()
981 {
982 struct lldpd_hardware *hardware;
983 close(gcfg->g_ctl);
984 priv_ctl_cleanup();
985 TAILQ_FOREACH(hardware, &gcfg->g_hardware, h_entries) {
986 if (INTERFACE_OPENED(hardware))
987 lldpd_iface_close(gcfg, hardware);
988 }
989 #ifdef USE_SNMP
990 if (gcfg->g_snmp)
991 agent_shutdown();
992 #endif /* USE_SNMP */
993 }
994
995 int
996 main(int argc, char *argv[])
997 {
998 struct lldpd *cfg;
999 struct lldpd_chassis *lchassis;
1000 int ch, debug = 0;
1001 #ifdef USE_SNMP
1002 int snmp = 0;
1003 #endif
1004 char *mgmtp = NULL;
1005 char *popt, opts[] = "dxm:p:M:i@ ";
1006 int i, found;
1007 #ifdef ENABLE_LLDPMED
1008 int lldpmed = 0, noinventory = 0;
1009 #endif
1010
1011 saved_argv = argv;
1012
1013 /*
1014 * Get and parse command line options
1015 */
1016 popt = index(opts, '@');
1017 for (i=0; protos[i].mode != 0; i++) {
1018 if (protos[i].enabled == 1) continue;
1019 *(popt++) = protos[i].arg;
1020 }
1021 *popt = '\0';
1022 while ((ch = getopt(argc, argv, opts)) != -1) {
1023 switch (ch) {
1024 case 'd':
1025 debug++;
1026 break;
1027 case 'm':
1028 mgmtp = optarg;
1029 break;
1030 #ifdef ENABLE_LLDPMED
1031 case 'M':
1032 lldpmed = atoi(optarg);
1033 if ((lldpmed < 1) || (lldpmed > 4)) {
1034 fprintf(stderr, "-M requires an argument between 1 and 4\n");
1035 usage();
1036 }
1037 break;
1038 case 'i':
1039 noinventory = 1;
1040 break;
1041 #else
1042 case 'M':
1043 case 'i':
1044 case 'P':
1045 fprintf(stderr, "LLDP-MED support is not built-in\n");
1046 usage();
1047 break;
1048 #endif
1049 case 'x':
1050 #ifdef USE_SNMP
1051 snmp = 1;
1052 #else
1053 fprintf(stderr, "SNMP support is not built-in\n");
1054 usage();
1055 #endif
1056 break;
1057 default:
1058 found = 0;
1059 for (i=0; protos[i].mode != 0; i++) {
1060 if (protos[i].enabled) continue;
1061 if (ch == protos[i].arg) {
1062 protos[i].enabled = 1;
1063 found = 1;
1064 }
1065 }
1066 if (!found)
1067 usage();
1068 }
1069 }
1070
1071 log_init(debug);
1072
1073 if (!debug) {
1074 int pid;
1075 char *spid;
1076 if (daemon(0, 0) != 0)
1077 fatal("failed to detach daemon");
1078 if ((pid = open(LLDPD_PID_FILE,
1079 O_TRUNC | O_CREAT | O_WRONLY, 0644)) == -1)
1080 fatal("unable to open pid file " LLDPD_PID_FILE);
1081 if (asprintf(&spid, "%d\n", getpid()) == -1)
1082 fatal("unable to create pid file " LLDPD_PID_FILE);
1083 if (write(pid, spid, strlen(spid)) == -1)
1084 fatal("unable to write pid file " LLDPD_PID_FILE);
1085 free(spid);
1086 close(pid);
1087 }
1088
1089 priv_init(PRIVSEP_CHROOT);
1090
1091 if ((cfg = (struct lldpd *)
1092 calloc(1, sizeof(struct lldpd))) == NULL)
1093 fatal(NULL);
1094
1095 cfg->g_mgmt_pattern = mgmtp;
1096
1097 /* Get ioctl socket */
1098 if ((cfg->g_sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
1099 fatal("failed to get ioctl socket");
1100 cfg->g_delay = LLDPD_TX_DELAY;
1101
1102 /* Set system capabilities */
1103 if ((lchassis = (struct lldpd_chassis*)
1104 calloc(1, sizeof(struct lldpd_chassis))) == NULL)
1105 fatal(NULL);
1106 lchassis->c_cap_available = LLDP_CAP_BRIDGE | LLDP_CAP_WLAN |
1107 LLDP_CAP_ROUTER;
1108 #ifdef ENABLE_LLDPMED
1109 if (lldpmed > 0) {
1110 if (lldpmed == LLDPMED_CLASS_III)
1111 lchassis->c_cap_available |= LLDP_CAP_TELEPHONE;
1112 lchassis->c_med_type = lldpmed;
1113 lchassis->c_med_cap_available = LLDPMED_CAP_CAP |
1114 LLDPMED_CAP_IV | LLDPMED_CAP_LOCATION;
1115 cfg->g_noinventory = noinventory;
1116 } else
1117 cfg->g_noinventory = 1;
1118 #endif
1119
1120 /* Set TTL */
1121 lchassis->c_ttl = LLDPD_TTL;
1122
1123 cfg->g_protocols = protos;
1124 for (i=0; protos[i].mode != 0; i++)
1125 if (protos[i].enabled) {
1126 LLOG_INFO("protocol %s enabled", protos[i].name);
1127 } else
1128 LLOG_INFO("protocol %s disabled", protos[i].name);
1129
1130 TAILQ_INIT(&cfg->g_hardware);
1131 TAILQ_INIT(&cfg->g_chassis);
1132 TAILQ_INSERT_TAIL(&cfg->g_chassis, lchassis, c_entries);
1133 lchassis->c_refcount++;
1134
1135 #ifdef USE_SNMP
1136 if (snmp) {
1137 cfg->g_snmp = 1;
1138 agent_init(cfg, debug);
1139 }
1140 #endif /* USE_SNMP */
1141
1142 /* Create socket */
1143 if ((cfg->g_ctl = priv_ctl_create(cfg)) == -1)
1144 fatalx("unable to create control socket " LLDPD_CTL_SOCKET);
1145 TAILQ_INIT(&cfg->g_clients);
1146
1147 gcfg = cfg;
1148 if (atexit(lldpd_exit) != 0) {
1149 close(cfg->g_ctl);
1150 priv_ctl_cleanup();
1151 fatal("unable to set exit function");
1152 }
1153
1154 /* Signal handling */
1155 signal(SIGHUP, lldpd_shutdown);
1156 signal(SIGINT, lldpd_shutdown);
1157 signal(SIGTERM, lldpd_shutdown);
1158
1159 for (;;)
1160 lldpd_loop(cfg);
1161
1162 return (0);
1163 }