]> git.ipfire.org Git - thirdparty/lldpd.git/blame - src/lldpd.c
Adding missing values for MAU type, thanks to James Lingard.
[thirdparty/lldpd.git] / src / lldpd.c
CommitLineData
43c02e7b
VB
1/*
2 * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include "lldpd.h"
18
19#include <stdio.h>
20#include <unistd.h>
21#include <errno.h>
22#include <signal.h>
23#include <sys/stat.h>
24#include <fcntl.h>
25#include <fnmatch.h>
26#include <time.h>
a2993d83 27#include <libgen.h>
43c02e7b
VB
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>
43c02e7b
VB
35#include <ifaddrs.h>
36#include <net/if_arp.h>
37#include <linux/filter.h>
38#include <linux/if_vlan.h>
4de7bd54 39#include <linux/if_packet.h>
43c02e7b 40#include <linux/sockios.h>
43c02e7b
VB
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
49void usage(void);
50
51int lldpd_iface_init(struct lldpd *, struct lldpd_hardware *);
50a89ca7
VB
52int lldpd_iface_init_vlan(struct lldpd *, struct lldpd_vif *);
53void lldpd_iface_init_mtu(struct lldpd *, struct lldpd_hardware *);
43c02e7b
VB
54int lldpd_iface_close(struct lldpd *, struct lldpd_hardware *);
55void 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 },
67struct sock_filter lldpd_filter_lldp_f[] = { LLDPD_FILTER_LLDP_F };
4bad1937 68#ifdef ENABLE_FDP
031118c4
VB
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 },
77struct sock_filter lldpd_filter_fdp_f[] = { LLDPD_FILTER_FDP_F };
4bad1937
VB
78#endif /* ENABLE_FDP */
79#ifdef ENABLE_CDP
348f6df6 80/* "ether dst 01:00:0c:cc:cc:cc" */
43c02e7b 81#define LLDPD_FILTER_CDP_F \
348f6df6
VB
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 },
43c02e7b 88struct sock_filter lldpd_filter_cdp_f[] = { LLDPD_FILTER_CDP_F };
4bad1937
VB
89#endif /* ENABLE_CDP */
90#ifdef ENABLE_SONMP
43c02e7b
VB
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 },
99struct sock_filter lldpd_filter_sonmp_f[] = { LLDPD_FILTER_SONMP_F };
4bad1937
VB
100#endif /* ENABLE_SONMP */
101#ifdef ENABLE_EDP
43c02e7b
VB
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 },
110struct sock_filter lldpd_filter_edp_f[] = { LLDPD_FILTER_EDP_F };
d2012fb3 111#endif /* ENABLE_EDP */
43c02e7b
VB
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 }, \
031118c4 118 { 0x15, 11, 12, 0x00000180 }, \
43c02e7b
VB
119 { 0x20, 0, 0, 0x00000002 }, \
120 { 0x15, 0, 2, 0x2b000000 }, \
121 { 0x28, 0, 0, 0x00000000 }, \
031118c4 122 { 0x15, 7, 8, 0x000000e0 }, \
43c02e7b 123 { 0x15, 1, 0, 0x0ccccccc }, \
031118c4
VB
124 { 0x15, 0, 2, 0x81000100 }, \
125 { 0x28, 0, 0, 0x00000000 }, \
126 { 0x15, 3, 4, 0x00000100 }, \
127 { 0x15, 0, 3, 0x52cccccc }, \
43c02e7b 128 { 0x28, 0, 0, 0x00000000 }, \
031118c4 129 { 0x15, 0, 1, 0x000001e0 }, \
43c02e7b
VB
130 { 0x6, 0, 0, 0x0000ffff }, \
131 { 0x6, 0, 0, 0x00000000 },
132struct sock_filter lldpd_filter_any_f[] = { LLDPD_FILTER_ANY_F };
133
134struct 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) },
4bad1937 138#ifdef ENABLE_CDP
43c02e7b
VB
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) },
4bad1937
VB
143#endif
144#ifdef ENABLE_SONMP
43c02e7b
VB
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) },
4bad1937
VB
147#endif
148#ifdef ENABLE_EDP
43c02e7b
VB
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) },
4bad1937
VB
151#endif
152#ifdef ENABLE_FDP
031118c4
VB
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) },
4bad1937 155#endif
43c02e7b
VB
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
160int lldpd_iface_switchto(struct lldpd *, short int,
161 struct lldpd_hardware *);
162struct lldpd_hardware *lldpd_port_add(struct lldpd *, struct ifaddrs *);
163void lldpd_loop(struct lldpd *);
43c02e7b
VB
164void lldpd_shutdown(int);
165void lldpd_exit();
166void lldpd_send_all(struct lldpd *);
167void lldpd_recv_all(struct lldpd *);
168int lldpd_guess_type(struct lldpd *, char *, int);
169void lldpd_decode(struct lldpd *, char *, int,
170 struct lldpd_hardware *, int);
89840df0
VB
171#ifdef ENABLE_LLDPMED
172void lldpd_med(struct lldpd_chassis *);
173#endif
43c02e7b
VB
174
175char **saved_argv;
176
177void
178usage(void)
179{
180 extern const char *__progname;
e809a587
VB
181 fprintf(stderr, "usage: %s [options]\n", __progname);
182 fprintf(stderr, "see manual page lldpd(8) for more information\n");
43c02e7b
VB
183 exit(1);
184}
185
50a89ca7
VB
186void
187lldpd_iface_init_mtu(struct lldpd *global, struct lldpd_hardware *hardware)
43c02e7b 188{
43c02e7b 189 struct ifreq ifr;
43c02e7b
VB
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
548109b2 198 hardware->h_mtu = hardware->h_lport.p_mfs = ifr.ifr_mtu;
50a89ca7
VB
199}
200
50a89ca7
VB
201int
202lldpd_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);
a7502371 208 status = priv_iface_init((struct lldpd_hardware*)vif, -1);
50a89ca7
VB
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
230int
231lldpd_iface_init(struct lldpd *global, struct lldpd_hardware *hardware)
232{
50a89ca7
VB
233 int master; /* Bond device */
234 char if_bond[IFNAMSIZ];
50a89ca7
VB
235 int status;
236 short int filter;
237
238 lldpd_iface_init_mtu(global, hardware);
a7502371 239 status = priv_iface_init(hardware, -1);
50a89ca7
VB
240 if (status != 0)
241 return status;
242
43c02e7b
VB
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;
a7502371
VB
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 }
43c02e7b
VB
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
280void
281lldpd_iface_multicast(struct lldpd *global, const char *name, int remove)
282{
a7502371 283 int i, rc;
509861fe 284
43c02e7b
VB
285 for (i=0; global->g_protocols[i].mode != 0; i++) {
286 if (!global->g_protocols[i].enabled) continue;
a7502371
VB
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);
43c02e7b
VB
295 }
296 }
297}
298
299int
300lldpd_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
323int
324lldpd_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
a1347cd8 351#ifdef ENABLE_DOT1
43c02e7b
VB
352void
353lldpd_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}
a1347cd8 365#endif
43c02e7b
VB
366
367void
368lldpd_port_cleanup(struct lldpd_port *port)
369{
a1347cd8 370#ifdef ENABLE_DOT1
43c02e7b 371 lldpd_vlan_cleanup(port);
a1347cd8 372#endif
43c02e7b
VB
373 free(port->p_id);
374 free(port->p_descr);
375 free(port);
376}
377
378void
379lldpd_chassis_cleanup(struct lldpd_chassis *chassis)
380{
89840df0 381#ifdef ENABLE_LLDPMED
e3a44efb 382 int i;
89840df0
VB
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);
e3a44efb
VB
389 for (i=0; i < LLDPMED_LOCFORMAT_LAST; i++)
390 free(chassis->c_med_location[i].data);
89840df0 391#endif
43c02e7b
VB
392 free(chassis->c_id);
393 free(chassis->c_name);
394 free(chassis->c_descr);
395 free(chassis);
396}
397
398void
399lldpd_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
d9be8ea0
VB
420void
421lldpd_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
43c02e7b
VB
431void
432lldpd_cleanup(struct lldpd *cfg)
433{
434 struct lldpd_hardware *hardware, *hardware_next;
50a89ca7 435 struct lldpd_vif *vif, *vif_next;
43c02e7b
VB
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);
43c02e7b 443 lldpd_remote_cleanup(cfg, hardware, 1);
d9be8ea0 444 lldpd_hardware_cleanup(hardware);
43c02e7b
VB
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 }
50a89ca7
VB
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
464struct lldpd_vif *
465lldpd_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 }
b5562b23 492
50a89ca7
VB
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;
43c02e7b
VB
516}
517
518struct lldpd_hardware *
519lldpd_port_add(struct lldpd *cfg, struct ifaddrs *ifa)
520{
a1347cd8 521#if defined (ENABLE_DOT1) || defined (ENABLE_DOT3)
43c02e7b 522 struct ifaddrs *oifap, *oifa;
a1347cd8 523#endif
43c02e7b
VB
524 struct lldpd_hardware *hardware;
525 struct lldpd_port *port;
a1347cd8 526#ifdef ENABLE_DOT1
43c02e7b 527 struct lldpd_vlan *vlan;
43c02e7b 528 struct vlan_ioctl_args ifv;
a1347cd8
VB
529#endif
530#ifdef ENABLE_DOT3
43c02e7b 531 struct ethtool_cmd ethc;
a1347cd8 532#endif
43c02e7b
VB
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);
a1347cd8 548#ifdef ENABLE_DOT1
43c02e7b
VB
549 TAILQ_INIT(&hardware->h_lport.p_vlans);
550 } else {
551 lldpd_vlan_cleanup(&hardware->h_lport);
a1347cd8 552#endif
43c02e7b
VB
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));
1d291522 561 iface_get_permanent_mac(cfg, hardware);
43c02e7b 562 port->p_id_subtype = LLDP_PORTID_SUBTYPE_LLADDR;
4395f9c1
VB
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));
43c02e7b
VB
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 */
a1347cd8 580#if defined (ENABLE_DOT3) || defined (ENABLE_DOT1)
43c02e7b
VB
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) {
a1347cd8 584#ifdef ENABLE_DOT1
43c02e7b
VB
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;
a1347cd8 592#endif
43c02e7b
VB
593
594 /* Aggregation check */
a1347cd8 595#ifdef ENABLE_DOT3
beeaefa3 596 if (iface_is_bond_slave(cfg, hardware->h_ifname, oifa->ifa_name, NULL))
43c02e7b 597 port->p_aggregid = if_nametoindex(oifa->ifa_name);
a1347cd8
VB
598#endif
599
600#ifdef ENABLE_DOT1
43c02e7b
VB
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) &&
beeaefa3 606 ((iface_is_bond_slave(cfg, hardware->h_ifname, ifv.u.device2, NULL)) ||
43c02e7b
VB
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;
249644a4 611 if ((vlan->v_name = strdup(oifa->ifa_name)) == NULL) {
43c02e7b
VB
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 }
a1347cd8 627#endif
43c02e7b
VB
628 }
629 freeifaddrs(oifap);
a1347cd8 630#endif
43c02e7b 631
a1347cd8 632#ifdef ENABLE_DOT3
43c02e7b 633 /* MAC/PHY */
4afe659e 634 if (priv_ethtool(hardware->h_ifname, &ethc) == 0) {
43c02e7b
VB
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;
b5562b23 687 } else
28aca6a0 688 LLOG_DEBUG("unable to get eth info for %s", hardware->h_ifname);
a1347cd8 689#endif
43c02e7b
VB
690
691 if (!INTERFACE_OPENED(hardware)) {
692
693 if (lldpd_iface_init(cfg, hardware) != 0) {
b5562b23 694 LLOG_WARN("unable to initialize %s", hardware->h_ifname);
d9be8ea0 695 lldpd_hardware_cleanup(hardware);
43c02e7b
VB
696 return (NULL);
697 }
698
699 TAILQ_INSERT_TAIL(&cfg->g_hardware, hardware, h_entries);
700 }
701
702 return (hardware);
703}
704
705int
706lldpd_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
725void
726lldpd_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
50a89ca7
VB
737 /* Discard VLAN frames */
738 if ((s >= sizeof(struct ieee8023)) &&
739 (((struct ieee8023*)frame)->size == htons(ETHERTYPE_VLAN)))
740 return;
741
43c02e7b
VB
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
967cleanup:
968 lldpd_chassis_cleanup(chassis);
969 lldpd_port_cleanup(port);
970 return;
971}
972
43c02e7b
VB
973void
974lldpd_recv_all(struct lldpd *cfg)
975{
976 struct lldpd_hardware *hardware;
50a89ca7 977 struct lldpd_vif *vif;
43c02e7b
VB
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 }
50a89ca7
VB
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 }
43c02e7b
VB
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 */
50a89ca7
VB
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 }
43c02e7b
VB
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)
a552a72e 1166 client_handle_client(cfg, client, buffer, n);
43c02e7b
VB
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
1182void
1183lldpd_send_all(struct lldpd *cfg)
1184{
1185 struct lldpd_hardware *hardware;
f7db0dd8
VB
1186 u_int8_t saved_lladdr[ETHER_ADDR_LEN];
1187 int i, altermac;
1188
43c02e7b
VB
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
a26fc61c 1195 /* When sending on inactive slaves, just send using a 0:0:0:0:0:0 address */
f7db0dd8 1196 altermac = 0;
beeaefa3
VB
1197 if ((hardware->h_raw_real > 0) &&
1198 (!iface_is_slave_active(cfg, hardware->h_master,
1199 hardware->h_ifname))) {
f7db0dd8
VB
1200 altermac = 1;
1201 memcpy(saved_lladdr, hardware->h_lladdr, ETHER_ADDR_LEN);
a26fc61c 1202 memset(hardware->h_lladdr, 0, ETHER_ADDR_LEN);
beeaefa3 1203 }
43c02e7b
VB
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 }
f7db0dd8
VB
1212 /* Restore MAC if needed */
1213 if (altermac)
1214 memcpy(hardware->h_lladdr, saved_lladdr, ETHER_ADDR_LEN);
43c02e7b
VB
1215 }
1216}
1217
89840df0
VB
1218#ifdef ENABLE_LLDPMED
1219void
1220lldpd_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
43c02e7b
VB
1237void
1238lldpd_loop(struct lldpd *cfg)
1239{
1240 struct ifaddrs *ifap, *ifa;
1241 struct sockaddr_ll *sdl;
1242 struct lldpd_hardware *hardware;
50a89ca7 1243 struct lldpd_vif *vif;
43c02e7b
VB
1244 int f;
1245 char status;
1246 struct utsname *un;
b5562b23 1247 char *hp;
43c02e7b
VB
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");
b5562b23 1254 if ((hp = priv_gethostbyname()) == NULL)
43c02e7b
VB
1255 fatal("failed to get system name");
1256 free(cfg->g_lchassis.c_name);
1257 free(cfg->g_lchassis.c_descr);
249644a4
VB
1258 if ((cfg->g_lchassis.c_name = strdup(hp)) == NULL)
1259 fatal(NULL);
43c02e7b
VB
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");
43c02e7b
VB
1263
1264 /* Check forwarding */
1265 cfg->g_lchassis.c_cap_enabled = 0;
b5562b23 1266 if ((f = priv_open("/proc/sys/net/ipv4/ip_forward")) >= 0) {
4afe659e 1267 if ((read(f, &status, 1) == 1) && (status == '1')) {
43c02e7b 1268 cfg->g_lchassis.c_cap_enabled = LLDP_CAP_ROUTER;
4afe659e 1269 }
43c02e7b
VB
1270 close(f);
1271 }
89840df0
VB
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);
43c02e7b
VB
1280
1281 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries)
1282 hardware->h_flags = 0;
50a89ca7
VB
1283 TAILQ_FOREACH(vif, &cfg->g_vif, vif_entries)
1284 vif->vif_flags = 0;
43c02e7b
VB
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
a5e5458f
VB
1318 if (ifa->ifa_addr == NULL ||
1319 ifa->ifa_addr->sa_family != PF_PACKET)
1320 continue;
1321
99f85c00
VB
1322 sdl = (struct sockaddr_ll *)ifa->ifa_addr;
1323 if (sdl->sll_hatype != ARPHRD_ETHER || !sdl->sll_halen)
1324 continue;
1325
43c02e7b
VB
1326 if (iface_is_bridge(cfg, ifa->ifa_name)) {
1327 cfg->g_lchassis.c_cap_enabled |= LLDP_CAP_BRIDGE;
1328 continue;
1329 }
1330
50a89ca7 1331 if ((iface_is_vlan(cfg, ifa->ifa_name)) ||
43c02e7b
VB
1332 (iface_is_bond(cfg, ifa->ifa_name)))
1333 continue;
1334
43c02e7b
VB
1335 if (!(ifa->ifa_flags & IFF_MULTICAST))
1336 continue;
1337
43c02e7b
VB
1338 if (iface_is_wireless(cfg, ifa->ifa_name))
1339 cfg->g_lchassis.c_cap_enabled |= LLDP_CAP_WLAN;
1340
43c02e7b
VB
1341 if (lldpd_port_add(cfg, ifa) == NULL)
1342 LLOG_WARNX("failed to allocate port %s, skip it",
1343 ifa->ifa_name);
1344 }
1345
50a89ca7
VB
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
43c02e7b
VB
1357 freeifaddrs(ifap);
1358
1359 lldpd_cleanup(cfg);
1360
1361 lldpd_send_all(cfg);
1362 lldpd_recv_all(cfg);
1363}
1364
115ff55c
VB
1365#ifdef ENABLE_LLDPMED
1366void
1367lldpd_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;
1535invalid_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
43c02e7b
VB
1547void
1548lldpd_shutdown(int sig)
1549{
1550 LLOG_INFO("signal received, exiting");
1551 exit(0);
1552}
1553
1554/* For signal handling */
1555struct lldpd *gcfg = NULL;
1556
1557void
1558lldpd_exit()
1559{
1560 struct lldpd_hardware *hardware;
50a89ca7 1561 struct lldpd_vif *vif;
b5562b23
VB
1562 close(gcfg->g_ctl);
1563 priv_ctl_cleanup();
43c02e7b
VB
1564 TAILQ_FOREACH(hardware, &gcfg->g_hardware, h_entries) {
1565 if (INTERFACE_OPENED(hardware))
1566 lldpd_iface_close(gcfg, hardware);
1567 }
50a89ca7
VB
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 }
43c02e7b
VB
1572#ifdef USE_SNMP
1573 if (gcfg->g_snmp)
1574 agent_shutdown();
1575#endif /* USE_SNMP */
1576}
1577
1578int
1579main(int argc, char *argv[])
1580{
1581 struct lldpd *cfg;
e809a587
VB
1582 int ch, debug = 0;
1583#ifdef USE_SNMP
1584 int snmp = 0;
1585#endif
43c02e7b 1586 char *mgmtp = NULL;
7286246f 1587 char *popt, opts[] = "vdxm:p:M:iL:@ ";
766f32b3 1588 int probe = 0, i, found, vlan = 0;
89840df0 1589#ifdef ENABLE_LLDPMED
e809a587 1590 int lldpmed = 0, noinventory = 0;
89840df0 1591#endif
43c02e7b
VB
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) {
766f32b3
VB
1606 case 'v':
1607 vlan = 1;
1608 break;
43c02e7b
VB
1609 case 'd':
1610 debug++;
1611 break;
1612 case 'm':
1613 mgmtp = optarg;
1614 break;
e809a587 1615#ifdef ENABLE_LLDPMED
115ff55c 1616 case 'M':
89840df0 1617 lldpmed = atoi(optarg);
e809a587
VB
1618 if ((lldpmed < 1) || (lldpmed > 4)) {
1619 fprintf(stderr, "-M requires an argument between 1 and 4\n");
89840df0 1620 usage();
e809a587 1621 }
89840df0 1622 break;
e809a587 1623 case 'i':
e809a587 1624 noinventory = 1;
115ff55c
VB
1625 break;
1626 case 'L':
115ff55c
VB
1627 /* Handled later */
1628 break;
e809a587 1629#else
115ff55c
VB
1630 case 'M':
1631 case 'i':
1632 case 'L':
1633 case 'P':
e809a587
VB
1634 fprintf(stderr, "LLDP-MED support is not built-in\n");
1635 usage();
e809a587 1636 break;
115ff55c 1637#endif
43c02e7b
VB
1638 case 'p':
1639 probe = atoi(optarg);
1640 break;
1641 case 'x':
e809a587 1642#ifdef USE_SNMP
43c02e7b 1643 snmp = 1;
e809a587
VB
1644#else
1645 fprintf(stderr, "SNMP support is not built-in\n");
1646 usage();
1647#endif
43c02e7b
VB
1648 break;
1649 default:
1650 found = 0;
1651 for (i=0; protos[i].mode != 0; i++) {
1652 if (protos[i].enabled) continue;
1653 if (ch == protos[i].arg) {
1654 protos[i].enabled = 1;
1655 found = 1;
1656 }
1657 }
1658 if (!found)
1659 usage();
1660 }
1661 }
115ff55c 1662
43c02e7b 1663 log_init(debug);
a2993d83 1664
eac2f38a
VB
1665 if (!debug) {
1666 int pid;
1667 char *spid;
1668 if (daemon(0, 0) != 0)
1669 fatal("failed to detach daemon");
1670 if ((pid = open(LLDPD_PID_FILE,
0aa5f676 1671 O_TRUNC | O_CREAT | O_WRONLY, 0644)) == -1)
eac2f38a
VB
1672 fatal("unable to open pid file " LLDPD_PID_FILE);
1673 if (asprintf(&spid, "%d\n", getpid()) == -1)
1674 fatal("unable to create pid file " LLDPD_PID_FILE);
1675 if (write(pid, spid, strlen(spid)) == -1)
1676 fatal("unable to write pid file " LLDPD_PID_FILE);
1677 free(spid);
1678 close(pid);
1679 }
1680
a2993d83 1681 priv_init(PRIVSEP_CHROOT);
43c02e7b
VB
1682
1683 if (probe == 0) probe = LLDPD_TTL;
1684
1685 if ((cfg = (struct lldpd *)
1686 calloc(1, sizeof(struct lldpd))) == NULL)
1687 fatal(NULL);
1688
766f32b3
VB
1689 cfg->g_mgmt_pattern = mgmtp;
1690 cfg->g_listen_vlans = vlan;
43c02e7b
VB
1691
1692 /* Get ioctl socket */
1693 if ((cfg->g_sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
1694 fatal("failed to get ioctl socket");
1695 cfg->g_delay = LLDPD_TX_DELAY;
1696
1697 /* Set system capabilities */
1698 cfg->g_lchassis.c_cap_available = LLDP_CAP_BRIDGE | LLDP_CAP_WLAN |
1699 LLDP_CAP_ROUTER;
89840df0
VB
1700#ifdef ENABLE_LLDPMED
1701 if (lldpmed > 0) {
1702 if (lldpmed == LLDPMED_CLASS_III)
1703 cfg->g_lchassis.c_cap_available |= LLDP_CAP_TELEPHONE;
1704 cfg->g_lchassis.c_med_type = lldpmed;
40ecae87 1705 cfg->g_lchassis.c_med_cap_available = LLDPMED_CAP_CAP |
115ff55c 1706 LLDPMED_CAP_IV | LLDPMED_CAP_LOCATION;
40ecae87 1707 cfg->g_lchassis.c_med_cap_enabled = LLDPMED_CAP_CAP;
e809a587 1708 if (!noinventory)
40ecae87 1709 cfg->g_lchassis.c_med_cap_enabled |= LLDPMED_CAP_IV;
115ff55c
VB
1710 optind = 1;
1711 while ((ch = getopt(argc, argv, opts)) != -1) {
1712 switch (ch) {
1713 case 'L':
1714 lldpd_parse_location(&cfg->g_lchassis, optarg);
1715 break;
115ff55c
VB
1716 }
1717 }
89840df0
VB
1718 }
1719#endif
43c02e7b
VB
1720
1721 /* Set TTL */
1722 cfg->g_lchassis.c_ttl = LLDPD_TTL;
1723
1724 cfg->g_protocols = protos;
1725 cfg->g_probe_time = probe;
1726 for (i=0; protos[i].mode != 0; i++)
1727 if (protos[i].enabled) {
1728 cfg->g_multi++;
1729 LLOG_INFO("protocol %s enabled", protos[i].name);
1730 } else
1731 LLOG_INFO("protocol %s disabled", protos[i].name);
1732 cfg->g_multi--;
1733
1734 TAILQ_INIT(&cfg->g_hardware);
50a89ca7 1735 TAILQ_INIT(&cfg->g_vif);
43c02e7b
VB
1736
1737#ifdef USE_SNMP
1738 if (snmp) {
1739 cfg->g_snmp = 1;
1740 agent_init(cfg, debug);
1741 }
1742#endif /* USE_SNMP */
1743
1744 /* Create socket */
b5562b23
VB
1745 if ((cfg->g_ctl = priv_ctl_create(cfg)) == -1)
1746 fatalx("unable to create control socket " LLDPD_CTL_SOCKET);
1747 TAILQ_INIT(&cfg->g_clients);
43c02e7b 1748
43c02e7b
VB
1749 gcfg = cfg;
1750 if (atexit(lldpd_exit) != 0) {
b5562b23
VB
1751 close(cfg->g_ctl);
1752 priv_ctl_cleanup();
43c02e7b
VB
1753 fatal("unable to set exit function");
1754 }
43c02e7b
VB
1755
1756 /* Signal handling */
b5562b23 1757 signal(SIGHUP, lldpd_shutdown);
43c02e7b
VB
1758 signal(SIGINT, lldpd_shutdown);
1759 signal(SIGTERM, lldpd_shutdown);
1760
1761 for (;;)
1762 lldpd_loop(cfg);
1763
1764 return (0);
1765}