]> git.ipfire.org Git - thirdparty/lldpd.git/blob - src/daemon/interfaces-bsd.c
ee35fc2630f5397874140e510e51b38e1ac103fa
[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 <errno.h>
23 #include <ctype.h>
24 #include <sys/param.h>
25 #include <sys/sysctl.h>
26 #include <sys/ioctl.h>
27 #include <net/bpf.h>
28 #include <net/if_types.h>
29 #include <net/if_media.h>
30 #include <net/if_dl.h>
31 #if defined HOST_OS_FREEBSD
32 # include <net/if_vlan_var.h>
33 # include <net/if_bridgevar.h>
34 # include <net/if_lagg.h>
35 #elif defined HOST_OS_DRAGONFLY
36 # include <net/vlan/if_vlan_var.h>
37 # include <net/bridge/if_bridgevar.h>
38 #elif defined HOST_OS_OPENBSD
39 # include <net/if_vlan_var.h>
40 # include <net/if_bridge.h>
41 # include <net/if_trunk.h>
42 #elif defined HOST_OS_NETBSD
43 # include <net/if_vlanvar.h>
44 # include <net/if_bridgevar.h>
45 # include <net/agr/if_agrioctl.h>
46 #elif defined HOST_OS_OSX
47 # include <osx/if_vlan_var.h>
48 # include <osx/if_bridgevar.h>
49 # include <osx/if_bond_var.h>
50 #endif
51
52 #ifndef IFDESCRSIZE
53 #define IFDESCRSIZE 64
54 #endif
55
56 static int
57 ifbsd_check_wireless(struct lldpd *cfg,
58 struct ifaddrs *ifaddr,
59 struct interfaces_device *iface)
60 {
61 struct ifmediareq ifmr = {};
62 strlcpy(ifmr.ifm_name, iface->name, sizeof(ifmr.ifm_name));
63 if (ioctl(cfg->g_sock, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0 ||
64 IFM_TYPE(ifmr.ifm_current) != IFM_IEEE80211)
65 return 0; /* Not wireless either */
66 iface->type |= IFACE_WIRELESS_T | IFACE_PHYSICAL_T;
67 return 0;
68 }
69
70 static void
71 ifbsd_check_bridge(struct lldpd *cfg,
72 struct interfaces_device_list *interfaces,
73 struct interfaces_device *master)
74 {
75 struct ifbreq req[64];
76 struct ifbifconf bifc = {
77 .ifbic_len = sizeof(req),
78 .ifbic_req = req
79 };
80
81 #if defined HOST_OS_FREEBSD || defined HOST_OS_NETBSD || defined HOST_OS_OSX || HOST_OS_DRAGONFLY
82 struct ifdrv ifd = {
83 .ifd_cmd = BRDGGIFS,
84 .ifd_len = sizeof(bifc),
85 .ifd_data = &bifc
86 };
87
88 strlcpy(ifd.ifd_name, master->name, sizeof(ifd.ifd_name));
89 if (ioctl(cfg->g_sock, SIOCGDRVSPEC, (caddr_t)&ifd) < 0) {
90 log_debug("interfaces",
91 "%s is not a bridge", master->name);
92 return;
93 }
94 #elif defined HOST_OS_OPENBSD
95 strlcpy(bifc.ifbic_name, master->name, sizeof(bifc.ifbic_name));
96 if (ioctl(cfg->g_sock, SIOCBRDGIFS, (caddr_t)&bifc) < 0) {
97 log_debug("interfaces",
98 "%s is not a bridge", master->name);
99 return;
100 }
101 #else
102 # error Unsupported OS
103 #endif
104 if (bifc.ifbic_len >= sizeof(req)) {
105 log_warnx("interfaces",
106 "%s is a bridge too big. Please, report the problem",
107 master->name);
108 return;
109 }
110 for (int i = 0; i < bifc.ifbic_len / sizeof(*req); i++) {
111 struct interfaces_device *slave =
112 interfaces_nametointerface(interfaces,
113 req[i].ifbr_ifsname);
114 if (slave == NULL) {
115 log_warnx("interfaces",
116 "%s should be bridged to %s but we don't know %s",
117 req[i].ifbr_ifsname, master->name, req[i].ifbr_ifsname);
118 continue;
119 }
120 log_debug("interfaces",
121 "%s is bridged to %s",
122 slave->name, master->name);
123 slave->upper = master;
124 }
125 master->type |= IFACE_BRIDGE_T;
126 }
127
128 static void
129 ifbsd_check_bond(struct lldpd *cfg,
130 struct interfaces_device_list *interfaces,
131 struct interfaces_device *master)
132 {
133 #if defined HOST_OS_OPENBSD
134 /* OpenBSD is the same as FreeBSD, just lagg->trunk */
135 # define lagg_reqport trunk_reqport
136 # define lagg_reqall trunk_reqall
137 # define SIOCGLAGG SIOCGTRUNK
138 # define LAGG_MAX_PORTS TRUNK_MAX_PORTS
139 #endif
140 #if defined HOST_OS_OPENBSD || defined HOST_OS_FREEBSD
141 struct lagg_reqport rpbuf[LAGG_MAX_PORTS];
142 struct lagg_reqall ra = {
143 .ra_size = sizeof(rpbuf),
144 .ra_port = rpbuf
145 };
146 strlcpy(ra.ra_ifname, master->name, IFNAMSIZ);
147 if (ioctl(cfg->g_sock, SIOCGLAGG, (caddr_t)&ra) < 0) {
148 log_debug("interfaces",
149 "%s is not a bond", master->name);
150 return;
151 }
152
153 for (int i = 0; i < ra.ra_ports; i++) {
154 struct interfaces_device *slave;
155 slave = interfaces_nametointerface(interfaces,
156 rpbuf[i].rp_portname);
157 if (slave == NULL) {
158 log_warnx("interfaces",
159 "%s should be enslaved to %s but we don't know %s",
160 rpbuf[i].rp_portname, master->name,
161 rpbuf[i].rp_portname);
162 continue;
163 }
164 log_debug("interfaces",
165 "%s is enslaved to bond %s",
166 slave->name, master->name);
167 slave->upper = master;
168 }
169 master->type |= IFACE_BOND_T;
170 #elif defined HOST_OS_NETBSD
171 /* No max, we consider a maximum of 24 ports */
172 char buf[sizeof(struct agrportinfo)*24] = {};
173 size_t buflen = sizeof(buf);
174 struct agrreq ar = {
175 .ar_version = AGRREQ_VERSION,
176 .ar_cmd = AGRCMD_PORTLIST,
177 .ar_buf = buf,
178 .ar_buflen = buflen
179 };
180 struct ifreq ifr = {
181 .ifr_data = &ar
182 };
183 struct agrportlist *apl = (void *)buf;
184 struct agrportinfo *api = (void *)(apl + 1);
185 strlcpy(ifr.ifr_name, master->name, sizeof(ifr.ifr_name));
186 if (ioctl(cfg->g_sock, SIOCGETAGR, &ifr) == -1) {
187 if (errno == E2BIG) {
188 log_warnx("interfaces",
189 "%s is a too big aggregate. Please, report the problem",
190 master->name);
191 } else {
192 log_debug("interfaces",
193 "%s is not an aggregate", master->name);
194 }
195 return;
196 }
197 for (int i = 0; i < apl->apl_nports; i++, api++) {
198 struct interfaces_device *slave;
199 slave = interfaces_nametointerface(interfaces,
200 api->api_ifname);
201 if (slave == NULL) {
202 log_warnx("interfaces",
203 "%s should be enslaved to %s but we don't know %s",
204 api->api_ifname, master->name, api->api_ifname);
205 continue;
206 }
207 log_debug("interfaces",
208 "%s is enslaved to bond %s",
209 slave->name, master->name);
210 slave->upper = master;
211 }
212 master->type |= IFACE_BOND_T;
213 #elif defined HOST_OS_OSX
214 struct if_bond_req ibr = {
215 .ibr_op = IF_BOND_OP_GET_STATUS,
216 .ibr_ibru = {
217 .ibru_status = { .ibsr_version = IF_BOND_STATUS_REQ_VERSION }
218 }
219 };
220 struct ifreq ifr = {
221 .ifr_data = (caddr_t)&ibr
222 };
223 strlcpy(ifr.ifr_name, master->name, sizeof(ifr.ifr_name));
224 if (ioctl(cfg->g_sock, SIOCGIFBOND, (caddr_t)&ifr) < 0) {
225 log_debug("interfaces",
226 "%s is not an aggregate", master->name);
227 return;
228 }
229 master->type |= IFACE_BOND_T;
230 if (ibr.ibr_ibru.ibru_status.ibsr_total == 0) {
231 log_debug("interfaces", "no members for bond %s",
232 master->name);
233 return;
234 }
235
236 struct if_bond_status_req *ibsr_p = &ibr.ibr_ibru.ibru_status;
237 ibsr_p->ibsr_buffer =
238 malloc(sizeof(struct if_bond_status)*ibsr_p->ibsr_total);
239 if (ibsr_p->ibsr_buffer == NULL) {
240 log_warnx("interfaces", "not enough memory to check bond members");
241 return;
242 }
243 ibsr_p->ibsr_count = ibsr_p->ibsr_total;
244 if (ioctl(cfg->g_sock, SIOCGIFBOND, (caddr_t)&ifr) < 0) {
245 log_warn("interfaces",
246 "unable to get members for bond %s", master->name);
247 goto end;
248 }
249
250 struct if_bond_status *ibs_p = (struct if_bond_status *)ibsr_p->ibsr_buffer;
251 for (int i = 0; i < ibsr_p->ibsr_total; i++, ibs_p++) {
252 struct interfaces_device *slave;
253 slave = interfaces_nametointerface(interfaces,
254 ibs_p->ibs_if_name);
255 if (slave == NULL) {
256 log_warnx("interfaces",
257 "%s should be enslaved to %s but we don't know %s",
258 ibs_p->ibs_if_name, master->name, ibs_p->ibs_if_name);
259 continue;
260 }
261 log_debug("interfaces", "%s is enslaved to bond %s",
262 slave->name, master->name);
263 slave->upper = master;
264 }
265 end:
266 free(ibsr_p->ibsr_buffer);
267 #elif defined HOST_OS_DRAGONFLY
268 log_debug("interfaces", "DragonFly BSD does not support link aggregation");
269 #else
270 # error Unsupported OS
271 #endif
272 }
273
274 static void
275 ifbsd_check_vlan(struct lldpd *cfg,
276 struct interfaces_device_list *interfaces,
277 struct interfaces_device *vlan)
278 {
279 struct interfaces_device *lower;
280 struct vlanreq vreq = {};
281 struct ifreq ifr = {
282 .ifr_data = (caddr_t)&vreq
283 };
284 strlcpy(ifr.ifr_name, vlan->name, sizeof(ifr.ifr_name));
285 if (ioctl(cfg->g_sock, SIOCGETVLAN, (caddr_t)&ifr) < 0) {
286 log_debug("interfaces",
287 "%s is not a VLAN", vlan->name);
288 return;
289 }
290 if (strlen(vreq.vlr_parent) == 0) {
291 log_debug("interfaces",
292 "%s is a VLAN but has no lower interface",
293 vlan->name);
294 vlan->lower = NULL;
295 vlan->type |= IFACE_VLAN_T;
296 return;
297 }
298 lower = interfaces_nametointerface(interfaces,
299 vreq.vlr_parent);
300 if (lower == NULL) {
301 log_warnx("interfaces",
302 "%s should be a VLAN of %s but %s does not exist",
303 vlan->name, vreq.vlr_parent, vreq.vlr_parent);
304 return;
305 }
306 log_debug("interfaces",
307 "%s is VLAN %d of %s",
308 vlan->name, vreq.vlr_tag, lower->name);
309 vlan->lower = lower;
310 bitmap_set(vlan->vlan_bmap, vreq.vlr_tag);
311 vlan->type |= IFACE_VLAN_T;
312 }
313
314 static void
315 ifbsd_check_physical(struct lldpd *cfg,
316 struct interfaces_device_list *interfaces,
317 struct interfaces_device *iface)
318 {
319 if (iface->type & (IFACE_VLAN_T|
320 IFACE_BOND_T|IFACE_BRIDGE_T|IFACE_PHYSICAL_T))
321 return;
322
323 if (!(iface->flags & (IFF_MULTICAST|IFF_BROADCAST))) {
324 log_debug("interfaces", "skip %s: not able to do multicast nor broadcast",
325 iface->name);
326 return;
327 }
328 log_debug("interfaces",
329 "%s is a physical interface",
330 iface->name);
331 iface->type |= IFACE_PHYSICAL_T;
332 }
333
334 /* Blacklist any dangerous interface. Currently, only p2p0 is blacklisted as it
335 * triggers some AirDrop functionality when we send something on it.
336 * See: https://github.com/vincentbernat/lldpd/issues/61
337 */
338 static void
339 ifbsd_blacklist(struct lldpd *cfg,
340 struct interfaces_device_list *interfaces)
341 {
342 #ifdef HOST_OS_OSX
343 struct interfaces_device *iface = NULL;
344 TAILQ_FOREACH(iface, interfaces, next) {
345 int i;
346 if (strncmp(iface->name, "p2p", 3)) continue;
347 if (strlen(iface->name) < 4) continue;
348 for (i = 3;
349 iface->name[i] != '\0' && isdigit(iface->name[i]);
350 i++);
351 if (iface->name[i] == '\0') {
352 log_debug("interfaces", "skip %s: AirDrop interface",
353 iface->name);
354 iface->ignore = 1;
355 }
356 }
357 #endif
358 }
359
360 static struct interfaces_device*
361 ifbsd_extract_device(struct lldpd *cfg,
362 struct ifaddrs *ifaddr)
363 {
364 struct interfaces_device *iface = NULL;
365 struct sockaddr_dl *saddrdl = ALIGNED_CAST(struct sockaddr_dl*, ifaddr->ifa_addr);
366 if ((saddrdl->sdl_type != IFT_BRIDGE) &&
367 (saddrdl->sdl_type != IFT_L2VLAN) &&
368 (saddrdl->sdl_type != IFT_ETHER)) {
369 log_debug("interfaces", "skip %s: not an ethernet device (%d)",
370 ifaddr->ifa_name, saddrdl->sdl_type);
371 return NULL;
372 }
373 if ((iface = calloc(1, sizeof(struct interfaces_device))) == NULL) {
374 log_warn("interfaces", "unable to allocate memory for %s",
375 ifaddr->ifa_name);
376 return NULL;
377 }
378
379 iface->index = saddrdl->sdl_index;
380 iface->name = strdup(ifaddr->ifa_name);
381 iface->flags = ifaddr->ifa_flags;
382
383 /* MAC address */
384 iface->address = malloc(ETHER_ADDR_LEN);
385 if (iface->address)
386 memcpy(iface->address, LLADDR(saddrdl), ETHER_ADDR_LEN);
387
388 /* Grab description */
389 #ifdef SIOCGIFDESCR
390 #if defined HOST_OS_FREEBSD || defined HOST_OS_OPENBSD
391 iface->alias = malloc(IFDESCRSIZE);
392 if (iface->alias) {
393 #if defined HOST_OS_FREEBSD
394 struct ifreq ifr = {
395 .ifr_buffer = { .buffer = iface->alias,
396 .length = IFDESCRSIZE }
397 };
398 #else
399 struct ifreq ifr = {
400 .ifr_data = (caddr_t)iface->alias
401 };
402 #endif
403 strlcpy(ifr.ifr_name, ifaddr->ifa_name, sizeof(ifr.ifr_name));
404 if (ioctl(cfg->g_sock, SIOCGIFDESCR, (caddr_t)&ifr) < 0) {
405 free(iface->alias);
406 iface->alias = NULL;
407 }
408 }
409 #endif
410 #endif /* SIOCGIFDESCR */
411
412 if (ifbsd_check_wireless(cfg, ifaddr, iface) == -1) {
413 interfaces_free_device(iface);
414 return NULL;
415 }
416
417 return iface;
418 }
419
420 static void
421 ifbsd_extract(struct lldpd *cfg,
422 struct interfaces_device_list *interfaces,
423 struct interfaces_address_list *addresses,
424 struct ifaddrs *ifaddr)
425 {
426 struct interfaces_address *address = NULL;
427 struct interfaces_device *device = NULL;
428 if (!ifaddr->ifa_name) return;
429 if (!ifaddr->ifa_addr) return;
430 switch (ifaddr->ifa_addr->sa_family) {
431 case AF_LINK:
432 log_debug("interfaces",
433 "grabbing information on interface %s",
434 ifaddr->ifa_name);
435 device = ifbsd_extract_device(cfg, ifaddr);
436 if (device)
437 TAILQ_INSERT_TAIL(interfaces, device, next);
438 break;
439 case AF_INET:
440 case AF_INET6:
441 log_debug("interfaces",
442 "got an IP address on %s",
443 ifaddr->ifa_name);
444 address = malloc(sizeof(struct interfaces_address));
445 if (address == NULL) {
446 log_warn("interfaces",
447 "not enough memory for a new IP address on %s",
448 ifaddr->ifa_name);
449 return;
450 }
451 address->flags = ifaddr->ifa_flags;
452 address->index = if_nametoindex(ifaddr->ifa_name);
453 memcpy(&address->address,
454 ifaddr->ifa_addr,
455 (ifaddr->ifa_addr->sa_family == AF_INET)?
456 sizeof(struct sockaddr_in):
457 sizeof(struct sockaddr_in6));
458 TAILQ_INSERT_TAIL(addresses, address, next);
459 break;
460 default:
461 log_debug("interfaces", "unhandled family %d for interface %s",
462 ifaddr->ifa_addr->sa_family,
463 ifaddr->ifa_name);
464 }
465 }
466
467 static void
468 ifbsd_macphy(struct lldpd *cfg,
469 struct lldpd_hardware *hardware)
470 {
471 #ifdef ENABLE_DOT3
472 struct ifmediareq ifmr = {};
473 #ifdef HAVE_TYPEOF
474 typeof(ifmr.ifm_ulist[0]) media_list[32] = {};
475 #else
476 int media_list[32] = {};
477 #endif
478 ifmr.ifm_ulist = media_list;
479 ifmr.ifm_count = 32;
480 struct lldpd_port *port = &hardware->h_lport;
481 unsigned int duplex;
482 unsigned int media;
483 int advertised_ifmedia_to_rfc3636[][3] = {
484 {IFM_10_T,
485 LLDP_DOT3_LINK_AUTONEG_10BASE_T,
486 LLDP_DOT3_LINK_AUTONEG_10BASET_FD},
487 {IFM_10_STP,
488 LLDP_DOT3_LINK_AUTONEG_10BASE_T,
489 LLDP_DOT3_LINK_AUTONEG_10BASET_FD},
490 {IFM_100_TX,
491 LLDP_DOT3_LINK_AUTONEG_100BASE_TX,
492 LLDP_DOT3_LINK_AUTONEG_100BASE_TXFD},
493 {IFM_100_T4,
494 LLDP_DOT3_LINK_AUTONEG_100BASE_T4,
495 LLDP_DOT3_LINK_AUTONEG_100BASE_T4},
496 {IFM_100_T2,
497 LLDP_DOT3_LINK_AUTONEG_100BASE_T2,
498 LLDP_DOT3_LINK_AUTONEG_100BASE_T2FD},
499 {IFM_1000_SX,
500 LLDP_DOT3_LINK_AUTONEG_1000BASE_X,
501 LLDP_DOT3_LINK_AUTONEG_1000BASE_XFD},
502 {IFM_1000_LX,
503 LLDP_DOT3_LINK_AUTONEG_1000BASE_X,
504 LLDP_DOT3_LINK_AUTONEG_1000BASE_XFD},
505 {IFM_1000_CX,
506 LLDP_DOT3_LINK_AUTONEG_1000BASE_X,
507 LLDP_DOT3_LINK_AUTONEG_1000BASE_XFD},
508 {IFM_1000_T,
509 LLDP_DOT3_LINK_AUTONEG_1000BASE_T,
510 LLDP_DOT3_LINK_AUTONEG_1000BASE_TFD},
511 {0, 0, 0}
512 };
513 int current_ifmedia_to_rfc3636[][3] = {
514 {IFM_10_T,
515 LLDP_DOT3_MAU_10BASETHD, LLDP_DOT3_MAU_10BASETFD},
516 {IFM_10_STP,
517 LLDP_DOT3_MAU_10BASETHD, LLDP_DOT3_MAU_10BASETFD},
518 {IFM_10_2,
519 LLDP_DOT3_MAU_10BASE2, LLDP_DOT3_MAU_10BASE2},
520 {IFM_10_5,
521 LLDP_DOT3_MAU_10BASE5, LLDP_DOT3_MAU_10BASE5},
522 {IFM_100_TX,
523 LLDP_DOT3_MAU_100BASETXHD, LLDP_DOT3_MAU_100BASETXFD},
524 {IFM_100_FX,
525 LLDP_DOT3_MAU_100BASEFXHD, LLDP_DOT3_MAU_100BASEFXFD},
526 {IFM_100_T2,
527 LLDP_DOT3_MAU_100BASET2HD, LLDP_DOT3_MAU_100BASET2FD},
528 {IFM_1000_SX,
529 LLDP_DOT3_MAU_1000BASESXHD, LLDP_DOT3_MAU_1000BASESXFD},
530 {IFM_10_FL,
531 LLDP_DOT3_MAU_10BASEFLHD, LLDP_DOT3_MAU_10BASEFLFD },
532 {IFM_1000_LX,
533 LLDP_DOT3_MAU_1000BASELXHD, LLDP_DOT3_MAU_1000BASELXFD},
534 {IFM_1000_CX,
535 LLDP_DOT3_MAU_1000BASECXHD, LLDP_DOT3_MAU_1000BASECXFD},
536 {IFM_1000_T,
537 LLDP_DOT3_MAU_1000BASETHD, LLDP_DOT3_MAU_1000BASETFD },
538 {IFM_10G_LR,
539 LLDP_DOT3_MAU_10GIGBASELR, LLDP_DOT3_MAU_10GIGBASELR},
540 {IFM_10G_SR,
541 LLDP_DOT3_MAU_10GIGBASESR, LLDP_DOT3_MAU_10GIGBASESR},
542 {IFM_10G_CX4,
543 LLDP_DOT3_MAU_10GIGBASELX4, LLDP_DOT3_MAU_10GIGBASELX4},
544 #ifdef IFM_10G_T
545 {IFM_10G_T,
546 LLDP_DOT3_MAU_10GIGBASECX4, LLDP_DOT3_MAU_10GIGBASECX4},
547 #endif
548 #ifdef IFM_10G_TWINAX
549 {IFM_10G_TWINAX,
550 LLDP_DOT3_MAU_10GIGBASECX4, LLDP_DOT3_MAU_10GIGBASECX4},
551 #endif
552 #ifdef IFM_10G_TWINAX_LONG
553 {IFM_10G_TWINAX_LONG,
554 LLDP_DOT3_MAU_10GIGBASECX4, LLDP_DOT3_MAU_10GIGBASECX4},
555 #endif
556 #ifdef IFM_10G_LRM
557 {IFM_10G_LRM,
558 LLDP_DOT3_MAU_10GIGBASELR, LLDP_DOT3_MAU_10GIGBASELR},
559 #endif
560 #ifdef IFM_10G_SFP_CU
561 {IFM_10G_SFP_CU,
562 LLDP_DOT3_MAU_10GIGBASECX4, LLDP_DOT3_MAU_10GIGBASECX4},
563 #endif
564 {0, 0, 0}
565 };
566
567 log_debug("interfaces", "get MAC/phy for %s",
568 hardware->h_ifname);
569 strlcpy(ifmr.ifm_name, hardware->h_ifname, sizeof(ifmr.ifm_name));
570 if (ioctl(cfg->g_sock, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
571 log_debug("interfaces",
572 "unable to get media information from %s",
573 hardware->h_ifname);
574 return;
575 }
576 if (IFM_TYPE(ifmr.ifm_current) != IFM_ETHER) {
577 log_warnx("interfaces",
578 "cannot get media information from %s: not an ethernet device",
579 hardware->h_ifname);
580 return;
581 }
582 if ((ifmr.ifm_status & IFM_ACTIVE) == 0) {
583 log_debug("interfaces",
584 "interface %s is now down, skip",
585 hardware->h_ifname);
586 return;
587 }
588 if (ifmr.ifm_count == 0) {
589 log_warnx("interfaces", "no media information available on %s",
590 hardware->h_ifname);
591 return;
592 }
593 port->p_macphy.autoneg_support =
594 port->p_macphy.autoneg_enabled = 0;
595 for (int m = 0; m < ifmr.ifm_count; m++) {
596 media = IFM_SUBTYPE(ifmr.ifm_ulist[m]);
597 duplex = !!(IFM_OPTIONS(ifmr.ifm_ulist[m]) &
598 IFM_FDX);
599 if (media == IFM_AUTO) {
600 port->p_macphy.autoneg_support = 1;
601 port->p_macphy.autoneg_enabled =
602 (IFM_SUBTYPE(ifmr.ifm_current) == IFM_AUTO);
603 continue;
604 }
605
606 int found = 0;
607 for (int j = 0; advertised_ifmedia_to_rfc3636[j][0]; j++) {
608 if (advertised_ifmedia_to_rfc3636[j][0] == media) {
609 port->p_macphy.autoneg_advertised |=
610 advertised_ifmedia_to_rfc3636[j][1 + duplex];
611 found = 1;
612 break;
613 }
614 }
615 if (!found) port->p_macphy.autoneg_advertised |= \
616 LLDP_DOT3_LINK_AUTONEG_OTHER;
617 }
618
619 port->p_macphy.mau_type = 0;
620 media = IFM_SUBTYPE(ifmr.ifm_active);
621 duplex = !!(IFM_OPTIONS(ifmr.ifm_active) & IFM_FDX);
622 for (int j = 0; current_ifmedia_to_rfc3636[j][0]; j++) {
623 if (current_ifmedia_to_rfc3636[j][0] == media) {
624 port->p_macphy.mau_type =
625 current_ifmedia_to_rfc3636[j][1 + duplex];
626 break;
627 }
628 }
629 #endif
630 }
631
632 extern struct lldpd_ops bpf_ops;
633 void
634 interfaces_update(struct lldpd *cfg)
635 {
636 struct lldpd_hardware *hardware;
637 struct interfaces_device *iface;
638 struct interfaces_device_list *interfaces;
639 struct interfaces_address_list *addresses;
640 struct ifaddrs *ifaddrs = NULL, *ifaddr;
641
642 interfaces = malloc(sizeof(struct interfaces_device_list));
643 addresses = malloc(sizeof(struct interfaces_address_list));
644 if (interfaces == NULL || addresses == NULL) {
645 log_warnx("interfaces", "unable to allocate memory");
646 goto end;
647 }
648 TAILQ_INIT(interfaces);
649 TAILQ_INIT(addresses);
650 if (getifaddrs(&ifaddrs) < 0) {
651 log_warnx("interfaces", "unable to get list of interfaces");
652 goto end;
653 }
654
655 for (ifaddr = ifaddrs;
656 ifaddr != NULL;
657 ifaddr = ifaddr->ifa_next) {
658 ifbsd_extract(cfg, interfaces, addresses, ifaddr);
659 }
660 /* Link interfaces together if needed */
661 TAILQ_FOREACH(iface, interfaces, next) {
662 ifbsd_check_bridge(cfg, interfaces, iface);
663 ifbsd_check_bond(cfg, interfaces, iface);
664 ifbsd_check_vlan(cfg, interfaces, iface);
665 ifbsd_check_physical(cfg, interfaces, iface);
666 }
667
668 ifbsd_blacklist(cfg, interfaces);
669 interfaces_helper_whitelist(cfg, interfaces);
670 interfaces_helper_physical(cfg, interfaces,
671 &bpf_ops, ifbpf_phys_init);
672 #ifdef ENABLE_DOT1
673 interfaces_helper_vlan(cfg, interfaces);
674 #endif
675 interfaces_helper_mgmt(cfg, addresses, interfaces);
676 interfaces_helper_chassis(cfg, interfaces);
677
678 /* Mac/PHY */
679 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
680 if (!hardware->h_flags) continue;
681 ifbsd_macphy(cfg, hardware);
682 interfaces_helper_promisc(cfg, hardware);
683 }
684
685 if (cfg->g_iface_event == NULL) {
686 int s;
687 log_debug("interfaces", "subscribe to route socket notifications");
688 if ((s = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) {
689 log_warn("interfaces", "unable to open route socket");
690 goto end;
691 }
692
693 #ifdef ROUTE_MSGFILTER
694 unsigned int rtfilter;
695 rtfilter = ROUTE_FILTER(RTM_IFINFO);
696 if (setsockopt(s, PF_ROUTE, ROUTE_MSGFILTER,
697 &rtfilter, sizeof(rtfilter)) == -1)
698 log_warn("interfaces", "unable to set filter for interface updates");
699 #endif
700
701 if (levent_iface_subscribe(cfg, s) == -1)
702 close(s);
703 }
704
705 end:
706 interfaces_free_devices(interfaces);
707 interfaces_free_addresses(addresses);
708 if (ifaddrs) freeifaddrs(ifaddrs);
709 }
710
711 void
712 interfaces_cleanup(struct lldpd *cfg)
713 {
714 }