]> git.ipfire.org Git - thirdparty/lldpd.git/blob - src/daemon/interfaces-bsd.c
freebsd: make it compile and work on real FreeBSD systems
[thirdparty/lldpd.git] / src / daemon / interfaces-bsd.c
1 /* -*- mode: c; c-file-style: "openbsd" -*- */
2 /*
3 * Copyright (c) 2012 Vincent Bernat <bernat@luffy.cx>
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #include "lldpd.h"
19
20 #include <unistd.h>
21 #include <ifaddrs.h>
22 #include <sys/param.h>
23 #include <sys/sysctl.h>
24 #include <sys/ioctl.h>
25 #include <net/bpf.h>
26 #include <net/if_types.h>
27 #include <net/if_media.h>
28 #include <net/if_vlan_var.h>
29 #include <net/if_dl.h>
30 #if defined HOST_OS_FREEBSD
31 # include <net/if_bridgevar.h>
32 # include <net/if_lagg.h>
33 #elif defined HOST_OS_OPENBSD
34 # include <net/if_bridge.h>
35 # include <net/if_trunk.h>
36 #endif
37
38 #ifndef IFDESCRSIZE
39 #define IFDESCRSIZE 64
40 #endif
41
42 static int
43 ifbsd_check_wireless(struct lldpd *cfg,
44 struct ifaddrs *ifaddr,
45 struct interfaces_device *iface)
46 {
47 struct ifmediareq ifmr = {};
48 strlcpy(ifmr.ifm_name, iface->name, sizeof(ifmr.ifm_name));
49 if (ioctl(cfg->g_sock, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0 ||
50 IFM_TYPE(ifmr.ifm_current) != IFM_IEEE80211)
51 return 0; /* Not wireless either */
52 iface->type |= IFACE_WIRELESS_T | IFACE_PHYSICAL_T;
53 return 0;
54 }
55
56 static void
57 ifbsd_check_bridge(struct lldpd *cfg,
58 struct interfaces_device_list *interfaces,
59 struct interfaces_device *master)
60 {
61 struct ifbreq req[64];
62 struct ifbifconf bifc = {
63 .ifbic_len = sizeof(req),
64 .ifbic_req = req
65 };
66
67 #if defined HOST_OS_FREEBSD
68 struct ifdrv ifd = {
69 .ifd_cmd = BRDGGIFS,
70 .ifd_len = sizeof(bifc),
71 .ifd_data = &bifc
72 };
73
74 strlcpy(ifd.ifd_name, master->name, sizeof(ifd.ifd_name));
75 if (ioctl(cfg->g_sock, SIOCGDRVSPEC, (caddr_t)&ifd) < 0) {
76 log_debug("interfaces",
77 "%s is not a bridge", master->name);
78 return;
79 }
80 #elif defined HOST_OS_OPENBSD
81 strlcpy(bifc.ifbic_name, master->name, sizeof(bifc.ifbic_name));
82 if (ioctl(cfg->g_sock, SIOCBRDGIFS, (caddr_t)&bifc) < 0) {
83 log_debug("interfaces",
84 "%s is not a bridge", master->name);
85 return;
86 }
87 #else
88 # error Unsupported OS
89 #endif
90 if (bifc.ifbic_len >= sizeof(req)) {
91 log_warnx("interfaces",
92 "%s is a bridge too big. Please, report the problem",
93 master->name);
94 return;
95 }
96 for (int i = 0; i < bifc.ifbic_len / sizeof(*req); i++) {
97 struct interfaces_device *slave =
98 interfaces_nametointerface(interfaces,
99 req[i].ifbr_ifsname);
100 if (slave == NULL) {
101 log_warnx("interfaces",
102 "%s should be bridged to %s but we don't know %s",
103 req[i].ifbr_ifsname, master->name, req[i].ifbr_ifsname);
104 continue;
105 }
106 log_debug("interfaces",
107 "%s is bridged to %s",
108 slave->name, master->name);
109 slave->upper = master;
110 }
111 master->type |= IFACE_BRIDGE_T;
112 }
113
114 static void
115 ifbsd_check_bond(struct lldpd *cfg,
116 struct interfaces_device_list *interfaces,
117 struct interfaces_device *master)
118 {
119 #if defined HOST_OS_OPENBSD
120 /* OpenBSD is the same as FreeBSD, just lagg->trunk */
121 # define lagg_reqport trunk_reqport
122 # define lagg_reqall trunk_reqall
123 # define SIOCGLAGG SIOCGTRUNK
124 # define LAGG_MAX_PORTS TRUNK_MAX_PORTS
125 #endif
126 struct lagg_reqport rpbuf[LAGG_MAX_PORTS];
127 struct lagg_reqall ra = {
128 .ra_size = sizeof(rpbuf),
129 .ra_port = rpbuf
130 };
131 strlcpy(ra.ra_ifname, master->name, IFNAMSIZ);
132 if (ioctl(cfg->g_sock, SIOCGLAGG, (caddr_t)&ra) < 0) {
133 log_debug("interfaces",
134 "%s is not a bond", master->name);
135 return;
136 }
137
138 for (int i = 0; i < ra.ra_ports; i++) {
139 struct interfaces_device *slave;
140 slave = interfaces_nametointerface(interfaces,
141 rpbuf[i].rp_portname);
142 if (slave == NULL) {
143 log_warnx("interfaces",
144 "%s should be enslaved to %s but we don't know %s",
145 rpbuf[i].rp_portname, master->name,
146 rpbuf[i].rp_portname);
147 continue;
148 }
149 log_debug("interfaces",
150 "%s is enslaved to bond %s",
151 slave->name, master->name);
152 slave->upper = master;
153 }
154 master->type |= IFACE_BOND_T;
155 }
156
157 static void
158 ifbsd_check_vlan(struct lldpd *cfg,
159 struct interfaces_device_list *interfaces,
160 struct interfaces_device *vlan)
161 {
162 struct interfaces_device *lower;
163 struct vlanreq vreq = {};
164 struct ifreq ifr = {
165 .ifr_data = (caddr_t)&vreq
166 };
167 strlcpy(ifr.ifr_name, vlan->name, sizeof(ifr.ifr_name));
168 if (ioctl(cfg->g_sock, SIOCGETVLAN, (caddr_t)&ifr) < 0) {
169 log_debug("interfaces",
170 "%s is not a VLAN", vlan->name);
171 return;
172 }
173 if (strlen(vreq.vlr_parent) == 0) {
174 log_debug("interfaces",
175 "%s is a VLAN but has no lower interface",
176 vlan->name);
177 vlan->lower = NULL;
178 vlan->type |= IFACE_VLAN_T;
179 return;
180 }
181 lower = interfaces_nametointerface(interfaces,
182 vreq.vlr_parent);
183 if (lower == NULL) {
184 log_warnx("interfaces",
185 "%s should be a VLAN of %s but %s does not exist",
186 vlan->name, vreq.vlr_parent, vreq.vlr_parent);
187 return;
188 }
189 log_debug("interfaces",
190 "%s is VLAN %d of %s",
191 vlan->name, vreq.vlr_tag, lower->name);
192 vlan->lower = lower;
193 vlan->vlanid = vreq.vlr_tag;
194 vlan->type |= IFACE_VLAN_T;
195 }
196
197 static void
198 ifbsd_check_physical(struct lldpd *cfg,
199 struct interfaces_device_list *interfaces,
200 struct interfaces_device *iface)
201 {
202 if (iface->type & (IFACE_VLAN_T|
203 IFACE_BOND_T|IFACE_BRIDGE_T|IFACE_PHYSICAL_T))
204 return;
205
206 if (!(iface->flags & (IFF_MULTICAST|IFF_BROADCAST))) {
207 log_debug("interfaces", "skip %s: not able to do multicast nor broadcast",
208 iface->name);
209 return;
210 }
211 log_debug("interfaces",
212 "%s is a physical interface",
213 iface->name);
214 iface->type |= IFACE_PHYSICAL_T;
215 }
216
217 static struct interfaces_device*
218 ifbsd_extract_device(struct lldpd *cfg,
219 struct ifaddrs *ifaddr)
220 {
221 struct interfaces_device *iface = NULL;
222 struct sockaddr_dl *saddrdl = (struct sockaddr_dl*)ifaddr->ifa_addr;
223 if ((saddrdl->sdl_type != IFT_BRIDGE) &&
224 (saddrdl->sdl_type != IFT_L2VLAN) &&
225 (saddrdl->sdl_type != IFT_ETHER)) {
226 log_debug("interfaces", "skip %s: not an ethernet device (%d)",
227 ifaddr->ifa_name, saddrdl->sdl_type);
228 return NULL;
229 }
230 if ((iface = calloc(1, sizeof(struct interfaces_device))) == NULL) {
231 log_warn("interfaces", "unable to allocate memory for %s",
232 ifaddr->ifa_name);
233 return NULL;
234 }
235
236 iface->index = saddrdl->sdl_index;
237 iface->name = strdup(ifaddr->ifa_name);
238 iface->flags = ifaddr->ifa_flags;
239
240 /* MAC address */
241 iface->address = malloc(ETHER_ADDR_LEN);
242 if (iface->address)
243 memcpy(iface->address, LLADDR(saddrdl), ETHER_ADDR_LEN);
244
245 /* Grab description */
246 iface->alias = malloc(IFDESCRSIZE);
247 if (iface->alias) {
248 #ifdef HOST_OS_FREEBSD
249 struct ifreq ifr = {
250 .ifr_buffer = { .buffer = iface->alias,
251 .length = IFDESCRSIZE }
252 };
253 #else
254 struct ifreq ifr = {
255 .ifr_data = (caddr_t)iface->alias
256 };
257 #endif
258 strlcpy(ifr.ifr_name, ifaddr->ifa_name, sizeof(ifr.ifr_name));
259 if (ioctl(cfg->g_sock, SIOCGIFDESCR, (caddr_t)&ifr) < 0) {
260 free(iface->alias);
261 iface->alias = NULL;
262 }
263 }
264
265 if (ifbsd_check_wireless(cfg, ifaddr, iface) == -1) {
266 interfaces_free_device(iface);
267 return NULL;
268 }
269
270 return iface;
271 }
272
273 static void
274 ifbsd_extract(struct lldpd *cfg,
275 struct interfaces_device_list *interfaces,
276 struct interfaces_address_list *addresses,
277 struct ifaddrs *ifaddr)
278 {
279 struct interfaces_address *address = NULL;
280 struct interfaces_device *device = NULL;
281 if (!ifaddr->ifa_name) return;
282 if (!ifaddr->ifa_addr) return;
283 if (!(ifaddr->ifa_flags & IFF_UP)) {
284 log_debug("interfaces",
285 "skip %s: down", ifaddr->ifa_name);
286 return;
287 }
288 switch (ifaddr->ifa_addr->sa_family) {
289 case AF_LINK:
290 log_debug("interfaces",
291 "grabbing information on interface %s",
292 ifaddr->ifa_name);
293 device = ifbsd_extract_device(cfg, ifaddr);
294 if (device)
295 TAILQ_INSERT_TAIL(interfaces, device, next);
296 break;
297 case AF_INET:
298 case AF_INET6:
299 log_debug("interfaces",
300 "got an IP address on %s",
301 ifaddr->ifa_name);
302 address = malloc(sizeof(struct interfaces_address));
303 if (address == NULL) {
304 log_warn("interfaces",
305 "not enough memory for a new IP address on %s",
306 ifaddr->ifa_name);
307 return;
308 }
309 address->flags = ifaddr->ifa_flags;
310 address->index = if_nametoindex(ifaddr->ifa_name);
311 memcpy(&address->address,
312 ifaddr->ifa_addr,
313 (ifaddr->ifa_addr->sa_family == AF_INET)?
314 sizeof(struct sockaddr_in):
315 sizeof(struct sockaddr_in6));
316 TAILQ_INSERT_TAIL(addresses, address, next);
317 break;
318 default:
319 log_debug("interfaces", "unhandled family %d for interface %s",
320 ifaddr->ifa_addr->sa_family,
321 ifaddr->ifa_name);
322 }
323 }
324
325 static void
326 ifbsd_macphy(struct lldpd *cfg,
327 struct lldpd_hardware *hardware)
328 {
329 #ifdef ENABLE_DOT3
330 int media_list[32] = {};
331 struct ifmediareq ifmr = {
332 .ifm_ulist = media_list,
333 .ifm_count = sizeof(media_list) / sizeof(int)
334 };
335 struct lldpd_port *port = &hardware->h_lport;
336 unsigned int duplex;
337 unsigned int media;
338 int advertised_ifmedia_to_rfc3636[][3] = {
339 {IFM_10_T,
340 LLDP_DOT3_LINK_AUTONEG_10BASE_T,
341 LLDP_DOT3_LINK_AUTONEG_10BASET_FD},
342 {IFM_10_STP,
343 LLDP_DOT3_LINK_AUTONEG_10BASE_T,
344 LLDP_DOT3_LINK_AUTONEG_10BASET_FD},
345 {IFM_100_TX,
346 LLDP_DOT3_LINK_AUTONEG_100BASE_TX,
347 LLDP_DOT3_LINK_AUTONEG_100BASE_TXFD},
348 {IFM_100_T4,
349 LLDP_DOT3_LINK_AUTONEG_100BASE_T4,
350 LLDP_DOT3_LINK_AUTONEG_100BASE_T4},
351 {IFM_100_T2,
352 LLDP_DOT3_LINK_AUTONEG_100BASE_T2,
353 LLDP_DOT3_LINK_AUTONEG_100BASE_T2FD},
354 {IFM_1000_SX,
355 LLDP_DOT3_LINK_AUTONEG_1000BASE_X,
356 LLDP_DOT3_LINK_AUTONEG_1000BASE_XFD},
357 {IFM_1000_LX,
358 LLDP_DOT3_LINK_AUTONEG_1000BASE_X,
359 LLDP_DOT3_LINK_AUTONEG_1000BASE_XFD},
360 {IFM_1000_CX,
361 LLDP_DOT3_LINK_AUTONEG_1000BASE_X,
362 LLDP_DOT3_LINK_AUTONEG_1000BASE_XFD},
363 {IFM_1000_T,
364 LLDP_DOT3_LINK_AUTONEG_1000BASE_T,
365 LLDP_DOT3_LINK_AUTONEG_1000BASE_TFD},
366 {0, 0, 0}
367 };
368 int current_ifmedia_to_rfc3636[][3] = {
369 {IFM_10_T,
370 LLDP_DOT3_MAU_10BASETHD, LLDP_DOT3_MAU_10BASETFD},
371 {IFM_10_STP,
372 LLDP_DOT3_MAU_10BASETHD, LLDP_DOT3_MAU_10BASETFD},
373 {IFM_10_2,
374 LLDP_DOT3_MAU_10BASE2, LLDP_DOT3_MAU_10BASE2},
375 {IFM_10_5,
376 LLDP_DOT3_MAU_10BASE5, LLDP_DOT3_MAU_10BASE5},
377 {IFM_100_TX,
378 LLDP_DOT3_MAU_100BASETXHD, LLDP_DOT3_MAU_100BASETXFD},
379 {IFM_100_FX,
380 LLDP_DOT3_MAU_100BASEFXHD, LLDP_DOT3_MAU_100BASEFXFD},
381 {IFM_100_T2,
382 LLDP_DOT3_MAU_100BASET2HD, LLDP_DOT3_MAU_100BASET2FD},
383 {IFM_1000_SX,
384 LLDP_DOT3_MAU_1000BASESXHD, LLDP_DOT3_MAU_1000BASESXFD},
385 {IFM_10_FL,
386 LLDP_DOT3_MAU_10BASEFLHD, LLDP_DOT3_MAU_10BASEFLFD },
387 {IFM_1000_LX,
388 LLDP_DOT3_MAU_1000BASELXHD, LLDP_DOT3_MAU_1000BASELXFD},
389 {IFM_1000_CX,
390 LLDP_DOT3_MAU_1000BASECXHD, LLDP_DOT3_MAU_1000BASECXFD},
391 {IFM_1000_T,
392 LLDP_DOT3_MAU_1000BASETHD, LLDP_DOT3_MAU_1000BASETFD },
393 {IFM_10G_LR,
394 LLDP_DOT3_MAU_10GIGBASELR, LLDP_DOT3_MAU_10GIGBASELR},
395 {IFM_10G_SR,
396 LLDP_DOT3_MAU_10GIGBASESR, LLDP_DOT3_MAU_10GIGBASESR},
397 {IFM_10G_CX4,
398 LLDP_DOT3_MAU_10GIGBASELX4, LLDP_DOT3_MAU_10GIGBASELX4},
399 {0, 0, 0}
400 };
401
402 log_debug("interfaces", "get MAC/phy for %s",
403 hardware->h_ifname);
404 strlcpy(ifmr.ifm_name, hardware->h_ifname, sizeof(ifmr.ifm_name));
405 if (ioctl(cfg->g_sock, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
406 log_warn("interfaces",
407 "unable to get media information from %s",
408 hardware->h_ifname);
409 return;
410 }
411 if (IFM_TYPE(ifmr.ifm_current) != IFM_ETHER) {
412 log_warnx("interfaces",
413 "cannot get media information from %s: not an ethernet device",
414 hardware->h_ifname);
415 return;
416 }
417 if ((ifmr.ifm_status & IFM_ACTIVE) == 0) {
418 log_debug("interfaces",
419 "interface %s is now down, skip",
420 hardware->h_ifname);
421 return;
422 }
423 if (ifmr.ifm_count == 0) {
424 log_warnx("interfaces", "no media information available on %s",
425 hardware->h_ifname);
426 return;
427 }
428 port->p_macphy.autoneg_support =
429 port->p_macphy.autoneg_enabled = 0;
430 for (int m = 0; m < ifmr.ifm_count; m++) {
431 media = IFM_SUBTYPE(ifmr.ifm_ulist[m]);
432 duplex = !!(IFM_OPTIONS(ifmr.ifm_ulist[m]) &
433 IFM_FDX);
434 if (media == IFM_AUTO) {
435 port->p_macphy.autoneg_support = 1;
436 port->p_macphy.autoneg_enabled =
437 (IFM_SUBTYPE(ifmr.ifm_current) == IFM_AUTO);
438 continue;
439 }
440
441 for (int j = 0; advertised_ifmedia_to_rfc3636[j][0]; j++) {
442 if (advertised_ifmedia_to_rfc3636[j][0] == media) {
443 port->p_macphy.autoneg_advertised |=
444 advertised_ifmedia_to_rfc3636[j][1 + duplex];
445 break;
446 }
447 }
448 }
449
450 port->p_macphy.mau_type = 0;
451 media = IFM_SUBTYPE(ifmr.ifm_active);
452 duplex = !!(IFM_OPTIONS(ifmr.ifm_active) & IFM_FDX);
453 for (int j = 0; current_ifmedia_to_rfc3636[j][0]; j++) {
454 if (current_ifmedia_to_rfc3636[j][0] == media) {
455 port->p_macphy.mau_type =
456 current_ifmedia_to_rfc3636[j][1 + duplex];
457 break;
458 }
459 }
460 #endif
461 }
462
463 struct bpf_buffer {
464 size_t len; /* Total length of the buffer */
465 char data[0]; /* Data */
466 };
467
468 static int
469 ifbsd_phys_init(struct lldpd *cfg,
470 struct lldpd_hardware *hardware)
471 {
472 struct bpf_insn filter[] = { LLDPD_FILTER_F };
473 struct ifreq ifr = {};
474 struct bpf_program fprog = {
475 .bf_insns = filter,
476 .bf_len = sizeof(filter)/sizeof(struct bpf_insn)
477 };
478 struct bpf_buffer *buffer = NULL;
479 int fd = -1, enable, required;
480
481 log_debug("interfaces", "initialize ethernet device %s",
482 hardware->h_ifname);
483 if ((fd = priv_iface_init(hardware->h_ifindex)) == -1)
484 return -1;
485 /* We got a file descriptor to /dev/bpfXXX */
486
487 /* Set buffer size */
488 required = ETHER_MAX_LEN;
489 if (ioctl(fd, BIOCSBLEN, (caddr_t)&required) < 0) {
490 log_warn("interfaces",
491 "unable to set receive buffer size for BPF on %s",
492 hardware->h_ifname);
493 goto end;
494 }
495 hardware->h_data = buffer =
496 malloc(required + sizeof(struct bpf_buffer));
497 if (buffer == NULL) {
498 log_warn("interfaces",
499 "unable to allocate buffer space for BPF on %s",
500 hardware->h_ifname);
501 goto end;
502 }
503 buffer->len = required;
504
505 /* Bind the interface to BPF device */
506 strlcpy(ifr.ifr_name, hardware->h_ifname, IFNAMSIZ);
507 if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) {
508 log_warn("interfaces", "failed to bind interface %s to BPF",
509 hardware->h_ifname);
510 goto end;
511 }
512
513 /* Disable buffering */
514 enable = 1;
515 if (ioctl(fd, BIOCIMMEDIATE, (caddr_t)&enable) < 0) {
516 log_warn("interfaces", "unable to disable buffering for %s",
517 hardware->h_ifname);
518 goto end;
519 }
520
521 /* Let us write the MAC address (raw packet mode) */
522 enable = 1;
523 if (ioctl(fd, BIOCSHDRCMPLT, (caddr_t)&enable) < 0) {
524 log_warn("interfaces",
525 "unable to set the `header complete` flag for %s",
526 hardware->h_ifname);
527 goto end;
528 }
529
530 #ifdef HOST_OS_FREEBSD
531 /* We only want to receive incoming packets */
532 enable = BPF_D_IN;
533 if (ioctl(fd, BIOCSDIRECTION, (caddr_t)&enable) < 0) {
534 #else
535 enable = BPF_DIRECTION_IN;
536 if (ioctl(fd, BIOCSDIRFILT, (caddr_t)&enable) < 0) {
537 #endif
538 log_warn("interfaces",
539 "unable to set packet direction for BPF filter on %s",
540 hardware->h_ifname);
541 goto end;
542 }
543
544 /* Install read filter */
545 if (ioctl(fd, BIOCSETF, (caddr_t)&fprog) < 0) {
546 log_warn("interfaces", "unable to setup BPF filter for %s",
547 hardware->h_ifname);
548 goto end;
549 }
550 /* Install write filter (optional) */
551 if (ioctl(fd, BIOCSETWF, (caddr_t)&fprog) < 0) {
552 log_info("interfaces", "unable to setup write BPF filter for %s",
553 hardware->h_ifname);
554 }
555
556 /* Setup multicast */
557 interfaces_setup_multicast(cfg, hardware->h_ifname, 0);
558
559 hardware->h_sendfd = fd; /* Send */
560
561 levent_hardware_add_fd(hardware, fd); /* Receive */
562 log_debug("interfaces", "interface %s initialized (fd=%d)", hardware->h_ifname,
563 fd);
564 return 0;
565
566 end:
567 if (fd >= 0) close(fd);
568 free(buffer);
569 hardware->h_data = NULL;
570 return -1;
571 }
572
573 /* Ethernet send/receive through BPF */
574 static int
575 ifbsd_eth_send(struct lldpd *cfg, struct lldpd_hardware *hardware,
576 char *buffer, size_t size)
577 {
578 log_debug("interfaces", "send PDU to ethernet device %s (fd=%d)",
579 hardware->h_ifname, hardware->h_sendfd);
580 return write(hardware->h_sendfd,
581 buffer, size);
582 }
583
584 static int
585 ifbsd_eth_recv(struct lldpd *cfg,
586 struct lldpd_hardware *hardware,
587 int fd, char *buffer, size_t size)
588 {
589 int n;
590 struct bpf_buffer *bpfbuf = hardware->h_data;
591 struct bpf_hdr *bh;
592 log_debug("interfaces", "receive PDU from ethernet device %s",
593 hardware->h_ifname);
594
595 /* We assume we have only receive one packet (unbuffered mode). Dunno if
596 * this is correct. */
597 if ((n = read(fd, bpfbuf->data, bpfbuf->len)) == -1) {
598 log_warn("interfaces", "error while receiving frame on %s",
599 hardware->h_ifname);
600 hardware->h_rx_discarded_cnt++;
601 return -1;
602 }
603 bh = (struct bpf_hdr*)bpfbuf->data;
604 if (bh->bh_caplen < size)
605 size = bh->bh_caplen;
606 memcpy(buffer, bpfbuf->data + bh->bh_hdrlen, size);
607
608 return size;
609 }
610
611 static int
612 ifbsd_eth_close(struct lldpd *cfg, struct lldpd_hardware *hardware)
613 {
614 log_debug("interfaces", "close ethernet device %s",
615 hardware->h_ifname);
616 interfaces_setup_multicast(cfg, hardware->h_ifname, 1);
617 return 0;
618 }
619
620 static struct lldpd_ops eth_ops = {
621 .send = ifbsd_eth_send,
622 .recv = ifbsd_eth_recv,
623 .cleanup = ifbsd_eth_close,
624 };
625
626 void
627 interfaces_update(struct lldpd *cfg)
628 {
629 struct lldpd_hardware *hardware;
630 struct interfaces_device *iface;
631 struct interfaces_device_list *interfaces = NULL;
632 struct interfaces_address_list *addresses = NULL;
633 struct ifaddrs *ifaddrs = NULL, *ifaddr;
634
635 interfaces = malloc(sizeof(struct interfaces_device_list));
636 addresses = malloc(sizeof(struct interfaces_address_list));
637 if (interfaces == NULL || addresses == NULL) {
638 log_warnx("interfaces", "unable to allocate memory");
639 goto end;
640 }
641 TAILQ_INIT(interfaces);
642 TAILQ_INIT(addresses);
643 if (getifaddrs(&ifaddrs) < 0) {
644 log_warnx("interfaces", "unable to get list of interfaces");
645 goto end;
646 }
647
648 for (ifaddr = ifaddrs;
649 ifaddr != NULL;
650 ifaddr = ifaddr->ifa_next) {
651 ifbsd_extract(cfg, interfaces, addresses, ifaddr);
652 }
653 /* Link interfaces together if needed */
654 TAILQ_FOREACH(iface, interfaces, next) {
655 ifbsd_check_bridge(cfg, interfaces, iface);
656 ifbsd_check_bond(cfg, interfaces, iface);
657 ifbsd_check_vlan(cfg, interfaces, iface);
658 ifbsd_check_physical(cfg, interfaces, iface);
659 }
660
661 interfaces_helper_whitelist(cfg, interfaces);
662 interfaces_helper_physical(cfg, interfaces,
663 &eth_ops, ifbsd_phys_init);
664 #ifdef ENABLE_DOT1
665 interfaces_helper_vlan(cfg, interfaces);
666 #endif
667 interfaces_helper_mgmt(cfg, addresses);
668 interfaces_helper_chassis(cfg, interfaces);
669
670 /* Mac/PHY */
671 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
672 if (!hardware->h_flags) continue;
673 ifbsd_macphy(cfg, hardware);
674 }
675
676 end:
677 interfaces_free_devices(interfaces);
678 interfaces_free_addresses(addresses);
679 if (ifaddrs) freeifaddrs(ifaddrs);
680 return;
681
682 }