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