1 /* 2 * Copyright (c) 1990 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that: (1) source code distributions 7 * retain the above copyright notice and this paragraph in its entirety, (2) 8 * distributions including binary code include the above copyright notice and 9 * this paragraph in its entirety in the documentation or other materials 10 * provided with the distribution, and (3) all advertising materials mentioning 11 * features or use of this software display the following acknowledgement: 12 * ``This product includes software developed by the University of California, 13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 14 * the University nor the names of its contributors may be used to endorse 15 * or promote products derived from this software without specific prior 16 * written permission. 17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 20 */ 21 #ifndef lint 22 char copyright[] = 23 "@(#) Copyright (c) 1990 The Regents of the University of California.\n\ 24 All rights reserved.\n"; 25 #endif /* not lint */ 26 27 #ifndef lint 28 static char rcsid[] = 29 "@(#) $Header: /home/ncvs/src/usr.sbin/rarpd/rarpd.c,v 1.3 1995/04/02 01:35:54 wpaul Exp $ (LBL)"; 30 #endif 31 32 33 /* 34 * rarpd - Reverse ARP Daemon 35 * 36 * Usage: rarpd -a [ -f ] [ hostname ] 37 * rarpd [ -f ] interface [ hostname ] 38 * 39 * 'hostname' is optional solely for backwards compatibility with Sun's rarpd. 40 * Currently, the argument is ignored. 41 */ 42 43 #include <stdio.h> 44 #include <syslog.h> 45 #include <string.h> 46 #include <strings.h> 47 #include <sys/types.h> 48 /* SunOS 4.x defines this while 3.x does not. */ 49 #ifdef __sys_types_h 50 #define SUNOS4 51 #endif 52 #include <sys/time.h> 53 #include <net/bpf.h> 54 #include <sys/socket.h> 55 #include <sys/ioctl.h> 56 #include <net/if.h> 57 #include <netinet/in.h> 58 #include <netinet/if_ether.h> 59 #include <sys/errno.h> 60 #include <sys/file.h> 61 #include <netdb.h> 62 63 #ifdef SUNOS4 64 #include <dirent.h> 65 #else 66 #include <sys/dir.h> 67 #endif 68 69 /* 70 * Map field names in ether_arp struct. What a pain in the neck. 71 */ 72 #if !defined(SUNOS4) && !defined(__FreeBSD__) 73 #undef arp_sha 74 #undef arp_spa 75 #undef arp_tha 76 #undef arp_tpa 77 #define arp_sha arp_xsha 78 #define arp_spa arp_xspa 79 #define arp_tha arp_xtha 80 #define arp_tpa arp_xtpa 81 #endif 82 83 #ifndef __GNUC__ 84 #define inline 85 #endif 86 87 extern int errno; 88 extern int ether_ntohost __P((char *, struct ether_addr *)); 89 90 /* 91 * The structure for each interface. 92 */ 93 struct if_info { 94 int ii_fd; /* BPF file descriptor */ 95 u_char ii_eaddr[6]; /* Ethernet address of this interface */ 96 u_long ii_ipaddr; /* IP address of this interface */ 97 u_long ii_netmask; /* subnet or net mask */ 98 struct if_info *ii_next; 99 }; 100 101 /* 102 * The list of all interfaces that are being listened to. rarp_loop() 103 * "selects" on the descriptors in this list. 104 */ 105 struct if_info *iflist; 106 107 extern char *malloc(); 108 extern void exit(); 109 110 u_long ipaddrtonetmask(); 111 void init_one(); 112 void init_all(); 113 void rarp_loop(); 114 void lookup_eaddr(); 115 void lookup_ipaddr(); 116 117 void 118 main(argc, argv) 119 int argc; 120 char **argv; 121 { 122 int op, pid; 123 char *ifname, *hostname, *name; 124 125 int aflag = 0; /* listen on "all" interfaces */ 126 int fflag = 0; /* don't fork */ 127 128 extern char *optarg; 129 extern int optind, opterr; 130 131 if (name = strrchr(argv[0], '/')) 132 ++name; 133 else 134 name = argv[0]; 135 if (*name == '-') 136 ++name; 137 138 /* 139 * All error reporting is done through syslogs. 140 */ 141 openlog(name, LOG_PID, LOG_DAEMON); 142 143 opterr = 0; 144 while ((op = getopt(argc, argv, "af")) != EOF) { 145 switch (op) { 146 case 'a': 147 ++aflag; 148 break; 149 150 case 'f': 151 ++fflag; 152 break; 153 154 default: 155 usage(); 156 /* NOTREACHED */ 157 } 158 } 159 ifname = argv[optind++]; 160 hostname = ifname ? argv[optind] : 0; 161 if ((aflag && ifname) || (!aflag && ifname == 0)) 162 usage(); 163 164 if (aflag) 165 init_all(); 166 else 167 init_one(ifname); 168 169 if (!fflag) { 170 pid = fork(); 171 if (pid > 0) 172 /* Parent exits, leaving child in background. */ 173 exit(0); 174 else if (pid == -1) { 175 syslog(LOG_ERR, "cannot fork"); 176 exit(1); 177 } 178 } 179 rarp_loop(); 180 } 181 182 /* 183 * Add 'ifname' to the interface list. Lookup its IP address and network 184 * mask and Ethernet address, and open a BPF file for it. 185 */ 186 void 187 init_one(ifname) 188 char *ifname; 189 { 190 struct if_info *p; 191 192 193 p = (struct if_info *)malloc(sizeof(*p)); 194 p->ii_next = iflist; 195 iflist = p; 196 197 p->ii_fd = rarp_open(ifname); 198 lookup_eaddr(p->ii_fd, p->ii_eaddr); 199 lookup_ipaddr(ifname, &p->ii_ipaddr, &p->ii_netmask); 200 } 201 202 /* 203 * Initialize all "candidate" interfaces that are in the system 204 * configuration list. A "candidate" is up, not loopback and not 205 * point to point. 206 */ 207 void 208 init_all() 209 { 210 int fd; 211 int ifflags; 212 struct ifreq ibuf[8], tmp_ibuf, *ifptr, *n; 213 struct ifconf ifc; 214 215 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 216 syslog(LOG_ERR, "socket: %m"); 217 exit(1); 218 } 219 ifc.ifc_len = sizeof ibuf; 220 ifc.ifc_buf = (caddr_t)ibuf; 221 if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 || 222 ifc.ifc_len < sizeof(struct ifreq)) { 223 syslog(LOG_ERR, "SIOCGIFCONF: %m"); 224 exit(1); 225 } 226 ifptr = ifc.ifc_req; 227 ifflags = ifptr->ifr_flags; 228 n = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len); 229 while (ifptr < n) { 230 bcopy((char *)ifptr, (char *)&tmp_ibuf, sizeof(struct ifreq)); 231 if (ioctl(fd, SIOCGIFFLAGS, (char *)&tmp_ibuf) < 0) { 232 syslog(LOG_ERR, "SIOCGIFFLAGS: %m"); 233 exit(1); 234 } 235 if (ifptr->ifr_flags == ifflags && (tmp_ibuf.ifr_flags & 236 (IFF_UP | IFF_LOOPBACK | IFF_POINTOPOINT)) == IFF_UP) 237 init_one(ifptr->ifr_name); 238 if(ifptr->ifr_addr.sa_len) /* Dohw! */ 239 ifptr = (struct ifreq *) ((caddr_t) ifptr + 240 ifptr->ifr_addr.sa_len - 241 sizeof(struct sockaddr)); 242 ifptr++; 243 } 244 (void)close(fd); 245 } 246 247 usage() 248 { 249 (void)fprintf(stderr, "usage: rarpd [ -af ] [ interface ]\n"); 250 exit(1); 251 } 252 253 static int 254 bpf_open() 255 { 256 int fd; 257 int n = 0; 258 char device[sizeof "/dev/bpf000"]; 259 260 /* 261 * Go through all the minors and find one that isn't in use. 262 */ 263 do { 264 (void)sprintf(device, "/dev/bpf%d", n++); 265 fd = open(device, O_RDWR); 266 } while (fd < 0 && errno == EBUSY); 267 268 if (fd < 0) { 269 syslog(LOG_ERR, "%s: %m", device); 270 exit(-1); 271 } 272 return fd; 273 } 274 275 /* 276 * Open a BPF file and attach it to the interface named 'device'. 277 * Set immediate mode, and set a filter that accepts only RARP requests. 278 */ 279 int 280 rarp_open(device) 281 char *device; 282 { 283 int fd; 284 struct ifreq ifr; 285 int immediate, link_type; 286 287 static struct bpf_insn insns[] = { 288 BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12), 289 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETHERTYPE_REVARP, 0, 3), 290 BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 20), 291 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ARPOP_REVREQUEST, 0, 1), 292 BPF_STMT(BPF_RET+BPF_K, sizeof(struct ether_arp) + 293 sizeof(struct ether_header)), 294 BPF_STMT(BPF_RET+BPF_K, 0), 295 }; 296 297 static struct bpf_program filter = { 298 sizeof insns / sizeof(insns[0]), 299 (struct bpf_insn *)&insns 300 }; 301 302 fd = bpf_open(); 303 /* 304 * Set immediate mode so packets are processed as they arrive. 305 */ 306 immediate = 1; 307 if (ioctl(fd, BIOCIMMEDIATE, &immediate) < 0) { 308 syslog(LOG_ERR, "BIOCIMMEDIATE: %m"); 309 exit(1); 310 } 311 (void)strncpy(ifr.ifr_name, device, sizeof ifr.ifr_name); 312 if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) { 313 syslog(LOG_ERR, "BIOCSETIF: %m"); 314 exit(1); 315 } 316 /* 317 * Check that the data link layer is an Ethernet; this code won't 318 * work with anything else. 319 */ 320 if (ioctl(fd, BIOCGDLT, &link_type) < 0) { 321 syslog(LOG_ERR, "BIOCGDLP: %m"); 322 exit(1); 323 } 324 if (link_type != DLT_EN10MB) { 325 syslog(LOG_ERR, "%s not on ethernet", device); 326 exit(1); 327 } 328 /* 329 * Set filter program. 330 */ 331 if (ioctl(fd, BIOCSETF, (caddr_t)&filter) < 0) { 332 syslog(LOG_ERR, "BIOCSETF: %m"); 333 exit(1); 334 } 335 return fd; 336 } 337 338 /* 339 * Perform various sanity checks on the RARP request packet. Return 340 * false on failure and log the reason. 341 */ 342 static int 343 rarp_check(p, len) 344 u_char *p; 345 int len; 346 { 347 struct ether_header *ep = (struct ether_header *)p; 348 struct ether_arp *ap = (struct ether_arp *)(p + sizeof(*ep)); 349 350 if (len < sizeof(*ep) + sizeof(*ap)) { 351 syslog(LOG_ERR, "truncated request"); 352 return 0; 353 } 354 /* 355 * XXX This test might be better off broken out... 356 */ 357 if (ep->ether_type != htons(ETHERTYPE_REVARP) || 358 ap->arp_hrd != htons(ARPHRD_ETHER) || 359 ap->arp_op != htons(ARPOP_REVREQUEST) || 360 ap->arp_pro != htons(ETHERTYPE_IP) || 361 ap->arp_hln != 6 || ap->arp_pln != 4) { 362 syslog(LOG_DEBUG, "request fails sanity check"); 363 return 0; 364 } 365 if (bcmp((char *)&ep->ether_shost, (char *)&ap->arp_sha, 6) != 0) { 366 syslog(LOG_DEBUG, "ether/arp sender address mismatch"); 367 return 0; 368 } 369 if (bcmp((char *)&ap->arp_sha, (char *)&ap->arp_tha, 6) != 0) { 370 syslog(LOG_DEBUG, "ether/arp target address mismatch"); 371 return 0; 372 } 373 return 1; 374 } 375 376 #ifndef FD_SETSIZE 377 #define FD_SET(n, fdp) ((fdp)->fds_bits[0] |= (1 << (n))) 378 #define FD_ISSET(n, fdp) ((fdp)->fds_bits[0] & (1 << (n))) 379 #define FD_ZERO(fdp) ((fdp)->fds_bits[0] = 0) 380 #endif 381 382 /* 383 * Loop indefinitely listening for RARP requests on the 384 * interfaces in 'iflist'. 385 */ 386 void 387 rarp_loop() 388 { 389 struct bpf_hdr *bhp; 390 u_char *pkt; 391 int cc, fd; 392 fd_set fds, listeners; 393 int bufsize, maxfd = 0; 394 struct if_info *ii; 395 396 if (iflist == 0) { 397 syslog(LOG_ERR, "no interfaces"); 398 exit(1); 399 } 400 if (ioctl(iflist->ii_fd, BIOCGBLEN, (caddr_t)&bufsize) < 0) { 401 syslog(LOG_ERR, "BIOCGBLEN: %m"); 402 exit(1); 403 } 404 bhp = (struct bpf_hdr *)malloc((unsigned)bufsize); 405 406 /* 407 * Find the highest numbered file descriptor for select(). 408 * Initialize the set of descriptors to listen to. 409 */ 410 FD_ZERO(&fds); 411 for (ii = iflist; ii; ii = ii->ii_next) { 412 FD_SET(ii->ii_fd, &fds); 413 if (ii->ii_fd > maxfd) 414 maxfd = ii->ii_fd; 415 } 416 while (1) { 417 listeners = fds; 418 if (select(maxfd + 1, &listeners, (struct fd_set *)0, 419 (struct fd_set *)0, (struct timeval *)0) < 0) { 420 syslog(LOG_ERR, "select: %m"); 421 exit(1); 422 } 423 for (ii = iflist; ii; ii = ii->ii_next) { 424 fd = ii->ii_fd; 425 if (FD_ISSET(fd, &listeners)) { 426 again: 427 cc = read(fd, (char *)bhp, bufsize); 428 /* 429 * Due to a SunOS bug, after 2^31 bytes, the 430 * file offset overflows and read fails with 431 * EINVAL. The lseek() to 0 will fix things. 432 */ 433 if (cc < 0) { 434 if (errno == EINVAL && 435 (long)(lseek(fd, 0L, SEEK_CUR) + bufsize) < 0) { 436 (void)lseek(fd, 0, 0); 437 goto again; 438 } 439 syslog(LOG_ERR, "read: %m"); 440 exit(1); 441 } 442 pkt = (u_char *)bhp + bhp->bh_hdrlen; 443 444 if (rarp_check(pkt, (int)bhp->bh_datalen)) 445 rarp_process(ii, pkt); 446 } 447 } 448 } 449 } 450 451 #ifndef TFTP_DIR 452 #define TFTP_DIR "/tftpboot" 453 #endif 454 455 /* 456 * True if this server can boot the host whose IP address is 'addr'. 457 * This check is made by looking in the tftp directory for the 458 * configuration file. 459 */ 460 rarp_bootable(addr) 461 u_long addr; 462 { 463 464 #ifdef SUNOS4 465 register struct dirent *dent; 466 #else 467 register struct direct *dent; 468 #endif 469 register DIR *d; 470 char ipname[9]; 471 static DIR *dd = 0; 472 473 /* 474 * XXX Need to htonl() the IP address or it'll 475 * come out backwards. 476 */ 477 (void)sprintf(ipname, "%08X", htonl(addr)); 478 /* 479 * If directory is already open, rewind it. Otherwise, open it. 480 */ 481 if (d = dd) 482 rewinddir(d); 483 else { 484 if (chdir(TFTP_DIR) == -1) { 485 syslog(LOG_ERR, "chdir: %m"); 486 exit(1); 487 } 488 d = opendir("."); 489 if (d == 0) { 490 syslog(LOG_ERR, "opendir: %m"); 491 exit(1); 492 } 493 dd = d; 494 } 495 while (dent = readdir(d)) 496 if (strncmp(dent->d_name, ipname, 8) == 0) 497 return 1; 498 return 0; 499 500 } 501 502 /* 503 * Given a list of IP addresses, 'alist', return the first address that 504 * is on network 'net'; 'netmask' is a mask indicating the network portion 505 * of the address. 506 */ 507 u_long 508 choose_ipaddr(alist, net, netmask) 509 u_long **alist; 510 u_long net; 511 u_long netmask; 512 { 513 for (; *alist; ++alist) { 514 if ((**alist & netmask) == net) 515 return **alist; 516 } 517 return 0; 518 } 519 520 /* 521 * A one entry ip/ethernet address cache. 522 */ 523 static u_long cache_ipaddr; 524 static u_char cache_eaddr[6]; 525 526 /* 527 * Answer the RARP request in 'pkt', on the interface 'ii'. 'pkt' has 528 * already been checked for validity. The reply is overlaid on the request. 529 */ 530 rarp_process(ii, pkt) 531 struct if_info *ii; 532 u_char *pkt; 533 { 534 struct ether_header *ep; 535 struct hostent *hp; 536 u_long target_ipaddr; 537 char ename[256]; 538 539 ep = (struct ether_header *)pkt; 540 /* 541 * If the address in the one element cache, don't bother 542 * looking up names. 543 */ 544 if (bcmp((char *)cache_eaddr, (char *)&ep->ether_shost, 6) == 0) 545 target_ipaddr = cache_ipaddr; 546 else { 547 if (ether_ntohost(ename, (struct ether_addr *)&ep->ether_shost) != 0 || 548 (hp = gethostbyname(ename)) == 0) 549 return; 550 /* 551 * Choose correct address from list. 552 */ 553 if (hp->h_addrtype != AF_INET) { 554 syslog(LOG_ERR, "cannot handle non IP addresses"); 555 exit(1); 556 } 557 target_ipaddr = choose_ipaddr((u_long **)hp->h_addr_list, 558 ii->ii_ipaddr & ii->ii_netmask, 559 ii->ii_netmask); 560 if (target_ipaddr == 0) { 561 syslog(LOG_ERR, "cannot find %s on %08x", 562 ename, ii->ii_ipaddr & ii->ii_netmask); 563 return; 564 } 565 bcopy((char *)&ep->ether_shost, (char *)cache_eaddr, 6); 566 cache_ipaddr = target_ipaddr; 567 } 568 if (rarp_bootable(target_ipaddr)) 569 rarp_reply(ii, ep, target_ipaddr); 570 } 571 572 /* 573 * Lookup the ethernet address of the interface attached to the BPF 574 * file descriptor 'fd'; return it in 'eaddr'. 575 */ 576 void 577 lookup_eaddr(fd, eaddr) 578 int fd; 579 u_char *eaddr; 580 { 581 struct ifreq ifr; 582 583 /* Use BPF descriptor to get ethernet address. */ 584 if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) { 585 syslog(LOG_ERR, "SIOCGIFADDR: %m"); 586 exit(1); 587 } 588 bcopy((char *)&ifr.ifr_addr.sa_data[0], (char *)eaddr, 6); 589 } 590 591 /* 592 * Lookup the IP address and network mask of the interface named 'ifname'. 593 */ 594 void 595 lookup_ipaddr(ifname, addrp, netmaskp) 596 char *ifname; 597 u_long *addrp; 598 u_long *netmaskp; 599 { 600 int fd; 601 struct ifreq ifr; 602 603 /* Use data gram socket to get IP address. */ 604 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 605 syslog(LOG_ERR, "socket: %m"); 606 exit(1); 607 } 608 (void)strncpy(ifr.ifr_name, ifname, sizeof ifr.ifr_name); 609 if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) { 610 syslog(LOG_ERR, "SIOCGIFADDR: %m"); 611 exit(1); 612 } 613 *addrp = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr; 614 if (ioctl(fd, SIOCGIFNETMASK, (char *)&ifr) < 0) { 615 perror("SIOCGIFNETMASK"); 616 exit(1); 617 } 618 *netmaskp = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr; 619 /* 620 * If SIOCGIFNETMASK didn't work, figure out a mask from 621 * the IP address class. 622 */ 623 if (*netmaskp == 0) 624 *netmaskp = ipaddrtonetmask(*addrp); 625 626 (void)close(fd); 627 } 628 629 /* 630 * Poke the kernel arp tables with the ethernet/ip address combinataion 631 * given. When processing a reply, we must do this so that the booting 632 * host (i.e. the guy running rarpd), won't try to ARP for the hardware 633 * address of the guy being booted (he cannot answer the ARP). 634 */ 635 update_arptab(ep, ipaddr) 636 u_char *ep; 637 u_long ipaddr; 638 { 639 #ifdef SIOCSARP 640 int s; 641 struct arpreq request; 642 struct sockaddr_in *sin; 643 644 request.arp_flags = 0; 645 sin = (struct sockaddr_in *)&request.arp_pa; 646 sin->sin_family = AF_INET; 647 sin->sin_addr.s_addr = ipaddr; 648 request.arp_ha.sa_family = AF_UNSPEC; 649 bcopy((char *)ep, (char *)request.arp_ha.sa_data, 6); 650 651 s = socket(AF_INET, SOCK_DGRAM, 0); 652 if (ioctl(s, SIOCSARP, (caddr_t)&request) < 0) 653 syslog(LOG_ERR, "SIOCSARP: %m"); 654 (void)close(s); 655 #else 656 if (arptab_set(ep, ipaddr) > 0) 657 syslog(LOG_ERR, "couldn't update arp table"); 658 #endif 659 } 660 661 /* 662 * Build a reverse ARP packet and sent it out on the interface. 663 * 'ep' points to a valid ARPOP_REVREQUEST. The ARPOP_REVREPLY is built 664 * on top of the request, then written to the network. 665 * 666 * RFC 903 defines the ether_arp fields as follows. The following comments 667 * are taken (more or less) straight from this document. 668 * 669 * ARPOP_REVREQUEST 670 * 671 * arp_sha is the hardware address of the sender of the packet. 672 * arp_spa is undefined. 673 * arp_tha is the 'target' hardware address. 674 * In the case where the sender wishes to determine his own 675 * protocol address, this, like arp_sha, will be the hardware 676 * address of the sender. 677 * arp_tpa is undefined. 678 * 679 * ARPOP_REVREPLY 680 * 681 * arp_sha is the hardware address of the responder (the sender of the 682 * reply packet). 683 * arp_spa is the protocol address of the responder (see the note below). 684 * arp_tha is the hardware address of the target, and should be the same as 685 * that which was given in the request. 686 * arp_tpa is the protocol address of the target, that is, the desired address. 687 * 688 * Note that the requirement that arp_spa be filled in with the responder's 689 * protocol is purely for convenience. For instance, if a system were to use 690 * both ARP and RARP, then the inclusion of the valid protocol-hardware 691 * address pair (arp_spa, arp_sha) may eliminate the need for a subsequent 692 * ARP request. 693 */ 694 rarp_reply(ii, ep, ipaddr) 695 struct if_info *ii; 696 struct ether_header *ep; 697 u_long ipaddr; 698 { 699 int n; 700 struct ether_arp *ap = (struct ether_arp *)(ep + 1); 701 int len, raw_sock; 702 703 update_arptab((u_char *)&ap->arp_sha, ipaddr); 704 705 /* 706 * Build the rarp reply by modifying the rarp request in place. 707 */ 708 ap->arp_op = htons(ARPOP_REVREPLY); 709 710 /* 711 * XXX Using htons(ETHERTYPE_REVARP) doesn't work: you wind 712 * up transmitting 0x3580 instead of the correct value of 713 * 0x8035. What makes no sense is that the NetBSD people 714 * do in fact use htons(ETHERTYPE_REVARP) in their rarpd. 715 * (Thank god for tcpdump or I would never have figured this 716 * out.) 717 */ 718 ep->ether_type = ETHERTYPE_REVARP; 719 720 bcopy((char *)&ap->arp_sha, (char *)&ep->ether_dhost, 6); 721 bcopy((char *)ii->ii_eaddr, (char *)&ep->ether_shost, 6); 722 bcopy((char *)ii->ii_eaddr, (char *)&ap->arp_sha, 6); 723 724 bcopy((char *)&ipaddr, (char *)ap->arp_tpa, 4); 725 /* Target hardware is unchanged. */ 726 bcopy((char *)&ii->ii_ipaddr, (char *)ap->arp_spa, 4); 727 728 len = sizeof(*ep) + sizeof(*ap); 729 n = write(ii->ii_fd, (char *)ep, len); 730 if (n != len) { 731 syslog(LOG_ERR, "write: only %d of %d bytes written", n, len); 732 } 733 } 734 735 /* 736 * Get the netmask of an IP address. This routine is used if 737 * SIOCGIFNETMASK doesn't work. 738 */ 739 u_long 740 ipaddrtonetmask(addr) 741 u_long addr; 742 { 743 if (IN_CLASSA(addr)) 744 return IN_CLASSA_NET; 745 if (IN_CLASSB(addr)) 746 return IN_CLASSB_NET; 747 if (IN_CLASSC(addr)) 748 return IN_CLASSC_NET; 749 syslog(LOG_DEBUG, "unknown IP address class: %08X", addr); 750 exit(1); 751 /* NOTREACHED */ 752 } 753