1 /* $NetBSD: bpf.c,v 1.5 2022/04/03 01:10:58 christos Exp $ */ 2 3 /* bpf.c 4 5 BPF socket interface code, originally contributed by Archie Cobbs. */ 6 7 /* 8 * Copyright (C) 2004-2022 Internet Systems Consortium, Inc. ("ISC") 9 * Copyright (c) 1996-2003 by Internet Software Consortium 10 * 11 * This Source Code Form is subject to the terms of the Mozilla Public 12 * License, v. 2.0. If a copy of the MPL was not distributed with this 13 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 16 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 17 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 18 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 20 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 21 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 22 * 23 * Internet Systems Consortium, Inc. 24 * PO Box 360 25 * Newmarket, NH 03857 USA 26 * <info@isc.org> 27 * https://www.isc.org/ 28 * 29 * This software was contributed to Internet Systems Consortium 30 * by Archie Cobbs. 31 * 32 * Patches for FDDI support on Digital Unix were written by Bill 33 * Stapleton, and maintained for a while by Mike Meredith before he 34 * managed to get me to integrate them. 35 */ 36 37 #include <sys/cdefs.h> 38 __RCSID("$NetBSD: bpf.c,v 1.5 2022/04/03 01:10:58 christos Exp $"); 39 40 #include "dhcpd.h" 41 #if defined (USE_BPF_SEND) || defined (USE_BPF_RECEIVE) \ 42 || defined (USE_LPF_RECEIVE) 43 # if defined (USE_LPF_RECEIVE) 44 # include <asm/types.h> 45 # include <linux/filter.h> 46 # define bpf_insn sock_filter /* Linux: dare to be gratuitously different. */ 47 # else 48 # include <sys/ioctl.h> 49 # include <sys/uio.h> 50 # include <net/bpf.h> 51 # if defined (NEED_OSF_PFILT_HACKS) 52 # include <net/pfilt.h> 53 # endif 54 # endif 55 56 #include <sys/param.h> 57 #include <netinet/in_systm.h> 58 #include "includes/netinet/ip.h" 59 #include "includes/netinet/udp.h" 60 #include "includes/netinet/if_ether.h" 61 #endif 62 63 #if defined(USE_BPF_SEND) || defined(USE_BPF_RECEIVE) || defined(USE_BPF_HWADDR) 64 #include <net/if_types.h> 65 #include <ifaddrs.h> 66 #endif 67 68 #include <errno.h> 69 70 /* Reinitializes the specified interface after an address change. This 71 is not required for packet-filter APIs. */ 72 73 #ifdef USE_BPF_SEND 74 void if_reinitialize_send (info) 75 struct interface_info *info; 76 { 77 } 78 #endif 79 80 #ifdef USE_BPF_RECEIVE 81 void if_reinitialize_receive (info) 82 struct interface_info *info; 83 { 84 } 85 #endif 86 87 /* Called by get_interface_list for each interface that's discovered. 88 Opens a packet filter for each interface and adds it to the select 89 mask. */ 90 91 #if defined (USE_BPF_SEND) || defined (USE_BPF_RECEIVE) 92 int if_register_bpf (info) 93 struct interface_info *info; 94 { 95 int sock; 96 char filename[50]; 97 int b; 98 99 /* Open a BPF device */ 100 for (b = 0; 1; b++) { 101 /* %Audit% 31 bytes max. %2004.06.17,Safe% */ 102 sprintf(filename, BPF_FORMAT, b); 103 sock = open (filename, O_RDWR, 0); 104 if (sock < 0) { 105 if (errno == EBUSY) { 106 continue; 107 } else { 108 if (!b) 109 log_fatal ("No bpf devices.%s%s%s", 110 " Please read the README", 111 " section for your operating", 112 " system."); 113 log_fatal ("Can't find free bpf: %m"); 114 } 115 } else { 116 break; 117 } 118 } 119 120 /* Set the BPF device to point at this interface. */ 121 if (ioctl (sock, BIOCSETIF, info -> ifp) < 0) 122 log_fatal ("Can't attach interface %s to bpf device %s: %m", 123 info -> name, filename); 124 125 get_hw_addr(info->name, &info->hw_address); 126 127 return sock; 128 } 129 #endif /* USE_BPF_SEND || USE_BPF_RECEIVE */ 130 131 #ifdef USE_BPF_SEND 132 void if_register_send (info) 133 struct interface_info *info; 134 { 135 /* If we're using the bpf API for sending and receiving, 136 we don't need to register this interface twice. */ 137 #ifndef USE_BPF_RECEIVE 138 info -> wfdesc = if_register_bpf (info, interface); 139 #else 140 info -> wfdesc = info -> rfdesc; 141 #endif 142 if (!quiet_interface_discovery) 143 log_info ("Sending on BPF/%s/%s%s%s", 144 info -> name, 145 print_hw_addr (info -> hw_address.hbuf [0], 146 info -> hw_address.hlen - 1, 147 &info -> hw_address.hbuf [1]), 148 (info -> shared_network ? "/" : ""), 149 (info -> shared_network ? 150 info -> shared_network -> name : "")); 151 } 152 153 void if_deregister_send (info) 154 struct interface_info *info; 155 { 156 /* If we're using the bpf API for sending and receiving, 157 we don't need to register this interface twice. */ 158 #ifndef USE_BPF_RECEIVE 159 close (info -> wfdesc); 160 #endif 161 info -> wfdesc = -1; 162 163 if (!quiet_interface_discovery) 164 log_info ("Disabling output on BPF/%s/%s%s%s", 165 info -> name, 166 print_hw_addr (info -> hw_address.hbuf [0], 167 info -> hw_address.hlen - 1, 168 &info -> hw_address.hbuf [1]), 169 (info -> shared_network ? "/" : ""), 170 (info -> shared_network ? 171 info -> shared_network -> name : "")); 172 } 173 #endif /* USE_BPF_SEND */ 174 175 #if defined (USE_BPF_RECEIVE) || defined (USE_LPF_RECEIVE) 176 /* Packet filter program... 177 XXX Changes to the filter program may require changes to the constant 178 offsets used in if_register_send to patch the BPF program! XXX */ 179 180 struct bpf_insn dhcp_bpf_filter [] = { 181 /* Make sure this is an IP packet... */ 182 BPF_STMT (BPF_LD + BPF_H + BPF_ABS, 12), 183 BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 8), 184 185 /* Make sure it's a UDP packet... */ 186 BPF_STMT (BPF_LD + BPF_B + BPF_ABS, 23), 187 BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 6), 188 189 /* Make sure this isn't a fragment... */ 190 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20), 191 BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 4, 0), 192 193 /* Get the IP header length... */ 194 BPF_STMT (BPF_LDX + BPF_B + BPF_MSH, 14), 195 196 /* Make sure it's to the right port... */ 197 BPF_STMT (BPF_LD + BPF_H + BPF_IND, 16), 198 BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, 67, 0, 1), /* patch */ 199 200 /* If we passed all the tests, ask for the whole packet. */ 201 BPF_STMT (BPF_RET + BPF_K, (u_int)-1), 202 203 /* Otherwise, drop it. */ 204 BPF_STMT (BPF_RET + BPF_K, 0), 205 }; 206 207 #if defined(RELAY_PORT) 208 /* 209 * For relay port extension 210 */ 211 struct bpf_insn dhcp_bpf_relay_filter [] = { 212 /* Make sure this is an IP packet... */ 213 BPF_STMT (BPF_LD + BPF_H + BPF_ABS, 12), 214 BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 10), 215 216 /* Make sure it's a UDP packet... */ 217 BPF_STMT (BPF_LD + BPF_B + BPF_ABS, 23), 218 BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 8), 219 220 /* Make sure this isn't a fragment... */ 221 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20), 222 BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 6, 0), 223 224 /* Get the IP header length... */ 225 BPF_STMT (BPF_LDX + BPF_B + BPF_MSH, 14), 226 227 /* Make sure it's to the right port... */ 228 BPF_STMT (BPF_LD + BPF_H + BPF_IND, 16), 229 BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, 67, 2, 0), /* patch */ 230 231 /* relay can have an alternative port... */ 232 BPF_STMT (BPF_LD + BPF_H + BPF_IND, 16), 233 BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, 67, 0, 1), /* patch */ 234 235 /* If we passed all the tests, ask for the whole packet. */ 236 BPF_STMT (BPF_RET + BPF_K, (u_int)-1), 237 238 /* Otherwise, drop it. */ 239 BPF_STMT (BPF_RET + BPF_K, 0), 240 }; 241 242 int dhcp_bpf_relay_filter_len = 243 sizeof dhcp_bpf_relay_filter / sizeof (struct bpf_insn); 244 #endif 245 246 #if defined (DEC_FDDI) 247 struct bpf_insn *bpf_fddi_filter = NULL; 248 #endif 249 250 int dhcp_bpf_filter_len = sizeof dhcp_bpf_filter / sizeof (struct bpf_insn); 251 #if defined (HAVE_TR_SUPPORT) 252 struct bpf_insn dhcp_bpf_tr_filter [] = { 253 /* accept all token ring packets due to variable length header */ 254 /* if we want to get clever, insert the program here */ 255 256 /* If we passed all the tests, ask for the whole packet. */ 257 BPF_STMT(BPF_RET+BPF_K, (u_int)-1), 258 259 /* Otherwise, drop it. */ 260 BPF_STMT(BPF_RET+BPF_K, 0), 261 }; 262 263 int dhcp_bpf_tr_filter_len = (sizeof dhcp_bpf_tr_filter / 264 sizeof (struct bpf_insn)); 265 #endif /* HAVE_TR_SUPPORT */ 266 #endif /* USE_LPF_RECEIVE || USE_BPF_RECEIVE */ 267 268 #if defined (USE_BPF_RECEIVE) 269 void if_register_receive (info) 270 struct interface_info *info; 271 { 272 int flag = 1; 273 struct bpf_version v; 274 struct bpf_program p; 275 #ifdef NEED_OSF_PFILT_HACKS 276 u_int32_t bits; 277 #endif 278 #ifdef DEC_FDDI 279 int link_layer; 280 #endif /* DEC_FDDI */ 281 282 /* Open a BPF device and hang it on this interface... */ 283 info -> rfdesc = if_register_bpf (info); 284 285 /* Make sure the BPF version is in range... */ 286 if (ioctl (info -> rfdesc, BIOCVERSION, &v) < 0) 287 log_fatal ("Can't get BPF version: %m"); 288 289 if (v.bv_major != BPF_MAJOR_VERSION || 290 v.bv_minor < BPF_MINOR_VERSION) 291 log_fatal ("BPF version mismatch - recompile DHCP!"); 292 293 /* Set immediate mode so that reads return as soon as a packet 294 comes in, rather than waiting for the input buffer to fill with 295 packets. */ 296 if (ioctl (info -> rfdesc, BIOCIMMEDIATE, &flag) < 0) 297 log_fatal ("Can't set immediate mode on bpf device: %m"); 298 299 #ifdef NEED_OSF_PFILT_HACKS 300 /* Allow the copyall flag to be set... */ 301 if (ioctl(info -> rfdesc, EIOCALLOWCOPYALL, &flag) < 0) 302 log_fatal ("Can't set ALLOWCOPYALL: %m"); 303 304 /* Clear all the packet filter mode bits first... */ 305 bits = 0; 306 if (ioctl (info -> rfdesc, EIOCMBIS, &bits) < 0) 307 log_fatal ("Can't clear pfilt bits: %m"); 308 309 /* Set the ENBATCH, ENCOPYALL, ENBPFHDR bits... */ 310 bits = ENBATCH | ENCOPYALL | ENBPFHDR; 311 if (ioctl (info -> rfdesc, EIOCMBIS, &bits) < 0) 312 log_fatal ("Can't set ENBATCH|ENCOPYALL|ENBPFHDR: %m"); 313 #endif 314 /* Get the required BPF buffer length from the kernel. */ 315 if (ioctl (info -> rfdesc, BIOCGBLEN, &info -> rbuf_max) < 0) 316 log_fatal ("Can't get bpf buffer length: %m"); 317 info -> rbuf = dmalloc (info -> rbuf_max, MDL); 318 if (!info -> rbuf) 319 log_fatal ("Can't allocate %ld bytes for bpf input buffer.", 320 (long)(info -> rbuf_max)); 321 info -> rbuf_offset = 0; 322 info -> rbuf_len = 0; 323 324 /* Set up the bpf filter program structure. */ 325 p.bf_len = dhcp_bpf_filter_len; 326 327 #ifdef DEC_FDDI 328 /* See if this is an FDDI interface, flag it for later. */ 329 if (ioctl(info -> rfdesc, BIOCGDLT, &link_layer) >= 0 && 330 link_layer == DLT_FDDI) { 331 if (!bpf_fddi_filter) { 332 bpf_fddi_filter = dmalloc (sizeof dhcp_bpf_filter, 333 MDL); 334 if (!bpf_fddi_filter) 335 log_fatal ("No memory for FDDI filter."); 336 memcpy (bpf_fddi_filter, 337 dhcp_bpf_filter, sizeof dhcp_bpf_filter); 338 /* Patch the BPF program to account for the difference 339 in length between ethernet headers (14), FDDI and 340 802.2 headers (16 +8=24, +10). 341 XXX changes to filter program may require changes to 342 XXX the insn number(s) used below! */ 343 bpf_fddi_filter[0].k += 10; 344 bpf_fddi_filter[2].k += 10; 345 bpf_fddi_filter[4].k += 10; 346 bpf_fddi_filter[6].k += 10; 347 bpf_fddi_filter[7].k += 10; 348 } 349 p.bf_insns = bpf_fddi_filter; 350 } else 351 #endif /* DEC_FDDI */ 352 p.bf_insns = dhcp_bpf_filter; 353 354 /* Patch the server port into the BPF program... 355 XXX changes to filter program may require changes 356 to the insn number(s) used below! XXX */ 357 #if defined(RELAY_PORT) 358 if (relay_port) { 359 /* 360 * If user defined relay UDP port, we need to filter 361 * also on the user UDP port. 362 */ 363 p.bf_len = dhcp_bpf_relay_filter_len; 364 p.bf_insns = dhcp_bpf_relay_filter; 365 366 dhcp_bpf_relay_filter [10].k = ntohs (relay_port); 367 } 368 #endif 369 p.bf_insns [8].k = ntohs (*libdhcp_callbacks.local_port); 370 371 if (ioctl (info -> rfdesc, BIOCSETF, &p) < 0) 372 log_fatal ("Can't install packet filter program: %m"); 373 if (!quiet_interface_discovery) 374 log_info ("Listening on BPF/%s/%s%s%s", 375 info -> name, 376 print_hw_addr (info -> hw_address.hbuf [0], 377 info -> hw_address.hlen - 1, 378 &info -> hw_address.hbuf [1]), 379 (info -> shared_network ? "/" : ""), 380 (info -> shared_network ? 381 info -> shared_network -> name : "")); 382 } 383 384 void if_deregister_receive (info) 385 struct interface_info *info; 386 { 387 close (info -> rfdesc); 388 info -> rfdesc = -1; 389 390 if (!quiet_interface_discovery) 391 log_info ("Disabling input on BPF/%s/%s%s%s", 392 info -> name, 393 print_hw_addr (info -> hw_address.hbuf [0], 394 info -> hw_address.hlen - 1, 395 &info -> hw_address.hbuf [1]), 396 (info -> shared_network ? "/" : ""), 397 (info -> shared_network ? 398 info -> shared_network -> name : "")); 399 } 400 #endif /* USE_BPF_RECEIVE */ 401 402 #ifdef USE_BPF_SEND 403 ssize_t send_packet (interface, packet, raw, len, from, to, hto) 404 struct interface_info *interface; 405 struct packet *packet; 406 struct dhcp_packet *raw; 407 size_t len; 408 struct in_addr from; 409 struct sockaddr_in *to; 410 struct hardware *hto; 411 { 412 unsigned hbufp = 0, ibufp = 0; 413 double hw [4]; 414 double ip [32]; 415 struct iovec iov [3]; 416 int result; 417 418 if (!strcmp (interface -> name, "fallback")) 419 return send_fallback (interface, packet, raw, 420 len, from, to, hto); 421 422 if (hto == NULL && interface->anycast_mac_addr.hlen) 423 hto = &interface->anycast_mac_addr; 424 425 /* Assemble the headers... */ 426 assemble_hw_header (interface, (unsigned char *)hw, &hbufp, hto); 427 assemble_udp_ip_header (interface, 428 (unsigned char *)ip, &ibufp, from.s_addr, 429 to -> sin_addr.s_addr, to -> sin_port, 430 (unsigned char *)raw, len); 431 432 /* Fire it off */ 433 iov [0].iov_base = ((char *)hw); 434 iov [0].iov_len = hbufp; 435 iov [1].iov_base = ((char *)ip); 436 iov [1].iov_len = ibufp; 437 iov [2].iov_base = (char *)raw; 438 iov [2].iov_len = len; 439 440 result = writev(interface -> wfdesc, iov, 3); 441 if (result < 0) 442 log_error ("send_packet: %m"); 443 return result; 444 } 445 #endif /* USE_BPF_SEND */ 446 447 #ifdef USE_BPF_RECEIVE 448 ssize_t receive_packet (interface, buf, len, from, hfrom) 449 struct interface_info *interface; 450 unsigned char *buf; 451 size_t len; 452 struct sockaddr_in *from; 453 struct hardware *hfrom; 454 { 455 int length = 0; 456 int offset = 0; 457 struct bpf_hdr hdr; 458 unsigned paylen; 459 460 /* All this complexity is because BPF doesn't guarantee 461 that only one packet will be returned at a time. We're 462 getting what we deserve, though - this is a terrible abuse 463 of the BPF interface. Sigh. */ 464 465 /* Process packets until we get one we can return or until we've 466 done a read and gotten nothing we can return... */ 467 468 /* If the buffer is empty, fill it. */ 469 if (interface->rbuf_offset >= interface->rbuf_len) { 470 length = read(interface->rfdesc, interface->rbuf, 471 (size_t)interface->rbuf_max); 472 if (length <= 0) { 473 #ifdef __FreeBSD__ 474 if (errno == ENXIO) { 475 #else 476 if (errno == EIO) { 477 #endif 478 dhcp_interface_remove 479 ((omapi_object_t *)interface, NULL); 480 } 481 return (length); 482 } 483 interface->rbuf_offset = 0; 484 interface->rbuf_len = BPF_WORDALIGN(length); 485 } 486 487 do { 488 /* If there isn't room for a whole bpf header, something went 489 wrong, but we'll ignore it and hope it goes away... XXX */ 490 if (interface->rbuf_len - 491 interface->rbuf_offset < sizeof hdr) { 492 interface->rbuf_offset = interface->rbuf_len; 493 continue; 494 } 495 496 /* Copy out a bpf header... */ 497 memcpy(&hdr, &interface->rbuf[interface->rbuf_offset], 498 sizeof hdr); 499 500 /* If the bpf header plus data doesn't fit in what's left 501 of the buffer, stick head in sand yet again... */ 502 if (interface->rbuf_offset + 503 hdr.bh_hdrlen + hdr.bh_caplen > interface->rbuf_len) { 504 interface->rbuf_offset = interface->rbuf_len; 505 continue; 506 } 507 508 /* If the captured data wasn't the whole packet, or if 509 the packet won't fit in the input buffer, all we 510 can do is drop it. */ 511 if (hdr.bh_caplen != hdr.bh_datalen) { 512 interface->rbuf_offset = 513 BPF_WORDALIGN(interface->rbuf_offset + 514 hdr.bh_hdrlen + hdr.bh_caplen); 515 continue; 516 } 517 518 /* Skip over the BPF header... */ 519 interface->rbuf_offset += hdr.bh_hdrlen; 520 521 /* Decode the physical header... */ 522 offset = decode_hw_header(interface, interface->rbuf, 523 interface->rbuf_offset, hfrom); 524 525 /* If a physical layer checksum failed (dunno of any 526 physical layer that supports this, but WTH), skip this 527 packet. */ 528 if (offset < 0) { 529 interface->rbuf_offset = 530 BPF_WORDALIGN(interface->rbuf_offset + 531 hdr.bh_caplen); 532 continue; 533 } 534 interface->rbuf_offset += offset; 535 hdr.bh_caplen -= offset; 536 537 /* Decode the IP and UDP headers... */ 538 offset = decode_udp_ip_header(interface, interface->rbuf, 539 interface->rbuf_offset, 540 from, hdr.bh_caplen, &paylen, 1); 541 542 /* If the IP or UDP checksum was bad, skip the packet... */ 543 if (offset < 0) { 544 interface->rbuf_offset = 545 BPF_WORDALIGN(interface->rbuf_offset + 546 hdr.bh_caplen); 547 continue; 548 } 549 interface->rbuf_offset = interface->rbuf_offset + offset; 550 hdr.bh_caplen -= offset; 551 552 /* If there's not enough room to stash the packet data, 553 we have to skip it (this shouldn't happen in real 554 life, though). */ 555 if (hdr.bh_caplen > len) { 556 interface->rbuf_offset = 557 BPF_WORDALIGN(interface->rbuf_offset + 558 hdr.bh_caplen); 559 continue; 560 } 561 562 /* Copy out the data in the packet... */ 563 memcpy(buf, interface->rbuf + interface->rbuf_offset, paylen); 564 interface->rbuf_offset = 565 BPF_WORDALIGN(interface->rbuf_offset + hdr.bh_caplen); 566 return paylen; 567 } while (interface->rbuf_offset < interface->rbuf_len); 568 569 return (0); 570 } 571 572 int can_unicast_without_arp (ip) 573 struct interface_info *ip; 574 { 575 return 1; 576 } 577 578 int can_receive_unicast_unconfigured (ip) 579 struct interface_info *ip; 580 { 581 return 1; 582 } 583 584 int supports_multiple_interfaces (ip) 585 struct interface_info *ip; 586 { 587 return 1; 588 } 589 590 void maybe_setup_fallback () 591 { 592 isc_result_t status; 593 struct interface_info *fbi = (struct interface_info *)0; 594 if (setup_fallback (&fbi, MDL)) { 595 if_register_fallback (fbi); 596 status = omapi_register_io_object ((omapi_object_t *)fbi, 597 if_readsocket, 0, 598 fallback_discard, 0, 0); 599 if (status != ISC_R_SUCCESS) 600 log_fatal ("Can't register I/O handle for %s: %s", 601 fbi -> name, isc_result_totext (status)); 602 interface_dereference (&fbi, MDL); 603 } 604 } 605 606 #endif 607 608 #if defined(USE_BPF_RECEIVE) || defined(USE_BPF_HWADDR) 609 static int 610 lladdr_active(int s, const char *name, const struct ifaddrs *ifa) 611 { 612 if (ifa->ifa_addr->sa_family != AF_LINK) 613 return 0; 614 if (strcmp(ifa->ifa_name, name) != 0) 615 return 0; 616 617 #ifdef SIOCGLIFADDR 618 { 619 struct if_laddrreq iflr; 620 const struct sockaddr_dl *sdl; 621 622 sdl = satocsdl(ifa->ifa_addr); 623 memset(&iflr, 0, sizeof(iflr)); 624 625 strlcpy(iflr.iflr_name, ifa->ifa_name, sizeof(iflr.iflr_name)); 626 memcpy(&iflr.addr, ifa->ifa_addr, MIN(ifa->ifa_addr->sa_len, 627 sizeof(iflr.addr))); 628 iflr.flags = IFLR_PREFIX; 629 iflr.prefixlen = sdl->sdl_alen * NBBY; 630 631 if (ioctl(s, SIOCGLIFADDR, &iflr) == -1) { 632 log_fatal("ioctl(SIOCGLIFADDR): %m"); 633 } 634 635 if ((iflr.flags & IFLR_ACTIVE) == 0) 636 return 0; 637 } 638 #endif 639 return 1; 640 } 641 642 void 643 get_hw_addr(const char *name, struct hardware *hw) { 644 struct ifaddrs *ifa; 645 struct ifaddrs *p; 646 struct sockaddr_dl *sa; 647 int s; 648 649 if ((s = socket(AF_LINK, SOCK_DGRAM, 0)) == -1) { 650 log_fatal("socket AF_LINK: %m"); 651 } 652 653 if (getifaddrs(&ifa) != 0) { 654 log_fatal("Error getting interface information; %m"); 655 } 656 657 /* 658 * Loop through our interfaces finding a match. 659 */ 660 sa = NULL; 661 for (p=ifa; (p != NULL) && (sa == NULL); p = p->ifa_next) { 662 if (lladdr_active(s, name, p)) { 663 sa = (struct sockaddr_dl *)p->ifa_addr; 664 break; 665 } 666 } 667 if (sa == NULL) { 668 log_fatal("No interface called '%s'", name); 669 } 670 close(s); 671 672 /* 673 * Pull out the appropriate information. 674 */ 675 switch (sa->sdl_type) { 676 case IFT_ETHER: 677 #ifdef IFT_CARP 678 case IFT_CARP: 679 #endif 680 #if defined (IFT_L2VLAN) 681 case IFT_L2VLAN: 682 #endif 683 hw->hlen = sa->sdl_alen + 1; 684 hw->hbuf[0] = HTYPE_ETHER; 685 memcpy(&hw->hbuf[1], LLADDR(sa), sa->sdl_alen); 686 break; 687 case IFT_ISO88023: 688 case IFT_ISO88024: /* "token ring" */ 689 case IFT_ISO88025: 690 case IFT_ISO88026: 691 hw->hlen = sa->sdl_alen + 1; 692 hw->hbuf[0] = HTYPE_IEEE802; 693 memcpy(&hw->hbuf[1], LLADDR(sa), sa->sdl_alen); 694 break; 695 #ifdef IFT_FDDI 696 case IFT_FDDI: 697 hw->hlen = sa->sdl_alen + 1; 698 hw->hbuf[0] = HTYPE_FDDI; 699 memcpy(&hw->hbuf[1], LLADDR(sa), sa->sdl_alen); 700 break; 701 #endif /* IFT_FDDI */ 702 default: 703 log_fatal("Unsupported device type %d for \"%s\"", 704 sa->sdl_type, name); 705 } 706 707 freeifaddrs(ifa); 708 } 709 #endif 710