/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* * Portions of this source code were derived from Berkeley 4.3 BSD * under license from the Regents of the University of California. */ #pragma ident "%Z%%M% %I% %E% SMI" /* * rarpd.c Reverse-ARP server. * Refer to RFC 903 "A Reverse Address Resolution Protocol". */ #define _REENTRANT #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define BOOTDIR "/tftpboot" /* boot files directory */ #define DEVIP "/dev/ip" /* path to ip driver */ #define DEVARP "/dev/arp" /* path to arp driver */ #define BUFSIZE 2048 /* max receive frame length */ #define MAXPATHL 128 /* max path length */ #define MAXHOSTL 128 /* max host name length */ #define MAXIFS 256 /* * Logical network devices */ struct ifdev { char ldevice[IFNAMSIZ]; int lunit; ipaddr_t ipaddr; /* network order */ ipaddr_t if_netmask; /* host order */ ipaddr_t if_ipaddr; /* host order */ ipaddr_t if_netnum; /* host order, with subnet */ struct ifdev *next; }; /* * Physical network device */ struct rarpdev { char device[DLPI_LINKNAME_MAX]; uint_t unit; dlpi_handle_t dh_rarp; uchar_t physaddr[DLPI_PHYSADDR_MAX]; /* mac address of interface */ uint_t physaddrlen; /* mac address length */ int ifrarplen; /* size of rarp data packet */ struct ifdev *ifdev; /* private interface info */ struct rarpdev *next; /* list of managed devices */ }; struct rarpreply { struct rarpdev *rdev; /* which device reply for */ struct timeval tv; /* send RARP reply by when */ uchar_t *lldest; /* target mac to send reply */ uchar_t *arprep; /* [R]ARP response */ struct rarpreply *next; }; static struct rarpreply *delay_list; static sema_t delay_sema; static mutex_t delay_mutex; static mutex_t debug_mutex; static struct rarpdev *rarpdev_head; /* * Globals initialized before multi-threading */ static char *cmdname; /* command name from argv[0] */ static int dflag = 0; /* enable diagnostics */ static int aflag = 0; /* start rarpd on all interfaces */ static void getintf(void); static struct rarpdev *find_device(ifspec_t *); static void init_rarpdev(struct rarpdev *); static void do_rarp(void *); static void rarp_request(struct rarpdev *, struct arphdr *, uchar_t *); static void add_arp(struct rarpdev *, uchar_t *, uchar_t *); static void arp_request(struct rarpdev *, struct arphdr *, uchar_t *); static void do_delay_write(void *); static void delay_write(struct rarpdev *, struct rarpreply *); static int mightboot(ipaddr_t); static void get_ifdata(char *, int, ipaddr_t *, ipaddr_t *); static int get_ipaddr(struct rarpdev *, uchar_t *, uchar_t *, ipaddr_t *); static int strioctl(int, int, int, int, char *); static void usage(); static void syserr(const char *); /*PRINTFLIKE1*/ static void error(const char *, ...); static void debug(char *, ...); extern int optind; extern char *optarg; int main(int argc, char *argv[]) { int c; struct rlimit rl; struct rarpdev *rdev; int i; cmdname = argv[0]; while ((c = getopt(argc, argv, "ad")) != -1) { switch (c) { case 'a': aflag = 1; break; case 'd': dflag = 1; break; default: usage(); } } if ((!aflag && (argc - optind) != 2) || (aflag && (argc - optind) != 0)) { usage(); /* NOTREACHED */ } if (!dflag) { /* * Background */ switch (fork()) { case -1: /* error */ syserr("fork"); /*NOTREACHED*/ case 0: /* child */ break; default: /* parent */ return (0); } for (i = 0; i < 3; i++) { (void) close(i); } (void) open("/", O_RDONLY, 0); (void) dup2(0, 1); (void) dup2(0, 2); /* * Detach terminal */ if (setsid() < 0) syserr("setsid"); } rl.rlim_cur = RLIM_INFINITY; rl.rlim_max = RLIM_INFINITY; if (setrlimit(RLIMIT_NOFILE, &rl) == -1) syserr("setrlimit"); (void) enable_extended_FILE_stdio(-1, -1); (void) openlog(cmdname, LOG_PID, LOG_DAEMON); if (aflag) { /* * Get each interface name and load rarpdev list. */ getintf(); } else { ifspec_t ifsp; struct ifdev *ifdev; char buf[IFNAMSIZ + 1]; /* * Load specified device as only element of the list. */ rarpdev_head = (struct rarpdev *)calloc(1, sizeof (struct rarpdev)); if (rarpdev_head == NULL) { error("out of memory"); } (void) strncpy(buf, argv[optind], IFNAMSIZ); (void) strncat(buf, argv[optind + 1], IFNAMSIZ - strlen(buf)); if ((ifdev = calloc(1, sizeof (struct ifdev))) == NULL) { error("out of memory"); } if (!ifparse_ifspec(buf, &ifsp) || ifsp.ifsp_modcnt != 0) { error("invalid interface specification"); } if (ifsp.ifsp_lunvalid) { (void) snprintf(ifdev->ldevice, sizeof (ifdev->ldevice), "%s%d:", ifsp.ifsp_devnm, ifsp.ifsp_ppa); ifdev->lunit = ifsp.ifsp_lun; } else { ifdev->lunit = -1; /* no logical unit */ } (void) strlcpy(rarpdev_head->device, ifsp.ifsp_devnm, sizeof (rarpdev_head->device)); rarpdev_head->unit = ifsp.ifsp_ppa; ifdev->next = rarpdev_head->ifdev; rarpdev_head->ifdev = ifdev; } /* * Initialize each rarpdev. */ for (rdev = rarpdev_head; rdev != NULL; rdev = rdev->next) { init_rarpdev(rdev); } (void) sema_init(&delay_sema, 0, USYNC_THREAD, NULL); (void) mutex_init(&delay_mutex, USYNC_THREAD, NULL); (void) mutex_init(&debug_mutex, USYNC_THREAD, NULL); /* * Start delayed processing thread. */ (void) thr_create(NULL, NULL, (void *(*)(void *))do_delay_write, NULL, THR_NEW_LWP, NULL); /* * Start RARP processing for each device. */ for (rdev = rarpdev_head; rdev != NULL; rdev = rdev->next) { if (rdev->dh_rarp != NULL) { (void) thr_create(NULL, NULL, (void *(*)(void *))do_rarp, (void *)rdev, THR_NEW_LWP, NULL); } } /* * Exit main() thread */ thr_exit(NULL); return (0); } static void getintf(void) { int fd; int numifs; unsigned bufsize; struct ifreq *reqbuf; struct ifconf ifconf; struct ifreq *ifr; struct rarpdev *rdev; struct ifdev *ifdev; /* * Open the IP provider. */ if ((fd = open(DEVIP, 0)) < 0) syserr(DEVIP); /* * Ask IP for the list of configured interfaces. */ if (ioctl(fd, SIOCGIFNUM, (char *)&numifs) < 0) { numifs = MAXIFS; } bufsize = numifs * sizeof (struct ifreq); reqbuf = (struct ifreq *)malloc(bufsize); if (reqbuf == NULL) { error("out of memory"); } ifconf.ifc_len = bufsize; ifconf.ifc_buf = (caddr_t)reqbuf; if (ioctl(fd, SIOCGIFCONF, (char *)&ifconf) < 0) syserr("SIOCGIFCONF"); /* * Initialize a rarpdev for each interface. */ for (ifr = ifconf.ifc_req; ifconf.ifc_len > 0; ifr++, ifconf.ifc_len -= sizeof (struct ifreq)) { ifspec_t ifsp; if (ioctl(fd, SIOCGIFFLAGS, (char *)ifr) < 0) { syserr("ioctl SIOCGIFFLAGS"); exit(1); } if ((ifr->ifr_flags & IFF_LOOPBACK) || !(ifr->ifr_flags & IFF_UP) || !(ifr->ifr_flags & IFF_BROADCAST) || (ifr->ifr_flags & IFF_NOARP) || (ifr->ifr_flags & IFF_POINTOPOINT)) continue; if (!ifparse_ifspec(ifr->ifr_name, &ifsp)) error("ifparse_ifspec failed"); /* * Look for an existing device for logical interfaces. */ if ((rdev = find_device(&ifsp)) == NULL) { rdev = calloc(1, sizeof (struct rarpdev)); if (rdev == NULL) error("out of memory"); (void) strlcpy(rdev->device, ifsp.ifsp_devnm, sizeof (rdev->device)); rdev->unit = ifsp.ifsp_ppa; rdev->next = rarpdev_head; rarpdev_head = rdev; } if ((ifdev = calloc(1, sizeof (struct ifdev))) == NULL) error("out of memory"); if (ifsp.ifsp_lunvalid) { (void) snprintf(ifdev->ldevice, sizeof (ifdev->ldevice), "%s%d:", ifsp.ifsp_devnm, ifsp.ifsp_ppa); ifdev->lunit = ifsp.ifsp_lun; } else ifdev->lunit = -1; /* no logical unit */ ifdev->next = rdev->ifdev; rdev->ifdev = ifdev; } (void) free((char *)reqbuf); } static struct rarpdev * find_device(ifspec_t *specp) { struct rarpdev *rdev; for (rdev = rarpdev_head; rdev != NULL; rdev = rdev->next) { if (specp->ifsp_ppa == rdev->unit && strcmp(specp->ifsp_devnm, rdev->device) == 0) return (rdev); } return (NULL); } static void init_rarpdev(struct rarpdev *rdev) { char *dev; int unit; struct ifdev *ifdev; int retval; char *str = NULL; uint_t physaddrlen = DLPI_PHYSADDR_MAX; char linkname[DLPI_LINKNAME_MAX]; dlpi_handle_t dh; (void) snprintf(linkname, DLPI_LINKNAME_MAX, "%s%d", rdev->device, rdev->unit); /* * Open datalink provider and get our mac address. */ if ((retval = dlpi_open(linkname, &dh, 0)) != DLPI_SUCCESS) { error("cannot open link %s: %s", linkname, dlpi_strerror(retval)); } if ((retval = dlpi_bind(dh, ETHERTYPE_REVARP, NULL)) != DLPI_SUCCESS) { dlpi_close(dh); error("dlpi_bind failed: %s", dlpi_strerror(retval)); } /* * Save our mac address. */ if ((retval = dlpi_get_physaddr(dh, DL_CURR_PHYS_ADDR, rdev->physaddr, &physaddrlen)) != DLPI_SUCCESS) { dlpi_close(dh); error("dlpi_get_physaddr failed: %s", dlpi_strerror(retval)); } rdev->physaddrlen = physaddrlen; rdev->ifrarplen = sizeof (struct arphdr) + (2 * sizeof (ipaddr_t)) + (2 * physaddrlen); if (dflag) { str = _link_ntoa(rdev->physaddr, str, rdev->physaddrlen, IFT_OTHER); if (str != NULL) { debug("device %s physical address %s", linkname, str); free(str); } } /* * Assign dlpi handle to rdev. */ rdev->dh_rarp = dh; /* * Get the IP address and netmask from directory service for * each logical interface. */ for (ifdev = rdev->ifdev; ifdev != NULL; ifdev = ifdev->next) { /* * If lunit == -1 then this is the primary interface name. */ if (ifdev->lunit == -1) { dev = rdev->device; unit = rdev->unit; } else { dev = ifdev->ldevice; unit = ifdev->lunit; } get_ifdata(dev, unit, &ifdev->if_ipaddr, &ifdev->if_netmask); /* * Use IP address of the interface. */ ifdev->if_netnum = ifdev->if_ipaddr & ifdev->if_netmask; ifdev->ipaddr = (ipaddr_t)htonl(ifdev->if_ipaddr); } } static void do_rarp(void *buf) { struct rarpdev *rdev = buf; char *cause; struct arphdr *ans; uchar_t *shost; uint_t saddrlen; size_t anslen = rdev->ifrarplen; char *str = NULL; int retval; if (((shost = malloc(rdev->physaddrlen)) == NULL) || ((ans = malloc(rdev->ifrarplen)) == NULL)) syserr("malloc"); if (dflag) { str = _link_ntoa(rdev->physaddr, str, rdev->physaddrlen, IFT_OTHER); if (str != NULL) { debug("starting rarp service on device %s%d physical" " address %s", rdev->device, rdev->unit, str); free(str); } } /* * Read RARP packets and respond to them. */ for (;;) { saddrlen = DLPI_PHYSADDR_MAX; retval = dlpi_recv(rdev->dh_rarp, shost, &saddrlen, ans, &anslen, -1, NULL); if (retval == DLPI_ETIMEDOUT) { continue; } else if (retval != DLPI_SUCCESS) { error("error in dlpi_recv %s: %s", rdev->dh_rarp, dlpi_strerror(retval)); } cause = NULL; if (anslen < rdev->ifrarplen) cause = "short packet"; else if (ans->ar_hrd != htons(ARPHRD_ETHER)) cause = "hardware type not Ethernet"; else if (ans->ar_pro != htons(ETHERTYPE_IP)) cause = "protocol type not IP"; else if (ans->ar_hln != rdev->physaddrlen) cause = "unexpected hardware address length"; else if (ans->ar_pln != sizeof (ipaddr_t)) cause = "unexpected protocol address length"; if (cause != NULL) { if (dflag) debug("RARP packet received but " "discarded: %s", cause); continue; } /* * Handle the request. */ switch (ntohs(ans->ar_op)) { case REVARP_REQUEST: rarp_request(rdev, ans, shost); break; case ARPOP_REQUEST: arp_request(rdev, ans, shost); break; case REVARP_REPLY: if (dflag) debug("REVARP_REPLY ignored"); break; case ARPOP_REPLY: if (dflag) debug("ARPOP_REPLY ignored"); break; default: if (dflag) debug("unknown opcode 0x%x", ans->ar_op); break; } } } /* * Reverse address determination and allocation code. */ static void rarp_request(struct rarpdev *rdev, struct arphdr *rp, uchar_t *shost) { ipaddr_t tpa, spa; struct rarpreply *rrp; uchar_t *shap, *thap, *spap, *tpap; char *str = NULL; int retval; shap = (uchar_t *)rp + sizeof (struct arphdr); spap = shap + rp->ar_hln; thap = spap + rp->ar_pln; tpap = thap + rp->ar_hln; if (dflag) { str = _link_ntoa(thap, str, rdev->physaddrlen, IFT_OTHER); if (str != NULL) { debug("RARP_REQUEST for %s", str); free(str); } } /* * Third party lookups are rare and wonderful. */ if ((memcmp(shap, thap, rdev->physaddrlen) != 0) || (memcmp(shap, shost, rdev->physaddrlen) != 0)) { if (dflag) debug("weird (3rd party lookup)"); } /* * Fill in given parts of reply packet. */ (void) memcpy(shap, rdev->physaddr, rdev->physaddrlen); /* * If a good address is stored in our lookup tables, return it * immediately or after a delay. Store it in our kernel's ARP cache. */ if (get_ipaddr(rdev, thap, tpap, &spa)) return; (void) memcpy(spap, &spa, sizeof (spa)); add_arp(rdev, tpap, thap); rp->ar_op = htons(REVARP_REPLY); if (dflag) { struct in_addr addr; (void) memcpy(&addr, tpap, sizeof (ipaddr_t)); debug("good lookup, maps to %s", inet_ntoa(addr)); } rrp = calloc(1, sizeof (struct rarpreply) + rdev->physaddrlen + rdev->ifrarplen); if (rrp == NULL) error("out of memory"); rrp->lldest = (uchar_t *)rrp + sizeof (struct rarpreply); rrp->arprep = rrp->lldest + rdev->physaddrlen; /* * Create rarpreply structure. */ (void) gettimeofday(&rrp->tv, NULL); rrp->tv.tv_sec += 3; /* delay */ rrp->rdev = rdev; (void) memcpy(rrp->lldest, shost, rdev->physaddrlen); (void) memcpy(rrp->arprep, rp, rdev->ifrarplen); /* * If this is diskless and we're not its bootserver, let the * bootserver reply first by delaying a while. */ (void) memcpy(&tpa, tpap, sizeof (ipaddr_t)); if (mightboot(ntohl(tpa))) { retval = dlpi_send(rdev->dh_rarp, rrp->lldest, rdev->physaddrlen, rrp->arprep, rdev->ifrarplen, NULL); if (retval != DLPI_SUCCESS) { error("dlpi_send failed: %s", dlpi_strerror(retval)); } else if (dflag) { debug("immediate reply sent"); } (void) free(rrp); } else { delay_write(rdev, rrp); } } /* * Download an ARP entry into our kernel. */ static void add_arp(struct rarpdev *rdev, uchar_t *ip, uchar_t *laddr) { struct xarpreq ar; struct sockaddr_in *sin; int fd; /* * Common part of query or set. */ (void) memset(&ar, 0, sizeof (ar)); ar.xarp_pa.ss_family = AF_INET; sin = (struct sockaddr_in *)&ar.xarp_pa; (void) memcpy(&sin->sin_addr, ip, sizeof (ipaddr_t)); /* * Open the IP provider. */ if ((fd = open(DEVARP, 0)) < 0) syserr(DEVARP); /* * Set the entry. */ (void) memcpy(LLADDR(&ar.xarp_ha), laddr, rdev->physaddrlen); ar.xarp_ha.sdl_alen = rdev->physaddrlen; ar.xarp_ha.sdl_family = AF_LINK; (void) strioctl(fd, SIOCDXARP, -1, sizeof (struct xarpreq), (char *)&ar); if (strioctl(fd, SIOCSXARP, -1, sizeof (struct xarpreq), (char *)&ar) < 0) syserr("SIOCSXARP"); (void) close(fd); } /* * The RARP spec says we must be able to process ARP requests, * even through the packet type is RARP. Let's hope this feature * is not heavily used. */ static void arp_request(struct rarpdev *rdev, struct arphdr *rp, uchar_t *shost) { struct rarpreply *rrp; struct ifdev *ifdev; uchar_t *shap, *thap, *spap, *tpap; int retval; shap = (uchar_t *)rp + sizeof (struct arphdr); spap = shap + rp->ar_hln; thap = spap + rp->ar_pln; tpap = thap + rp->ar_hln; if (dflag) debug("ARPOP_REQUEST"); for (ifdev = rdev->ifdev; ifdev != NULL; ifdev = ifdev->next) { if (memcmp(&ifdev->ipaddr, tpap, sizeof (ipaddr_t)) == 0) break; } if (ifdev == NULL) return; rp->ar_op = ARPOP_REPLY; (void) memcpy(shap, rdev->physaddr, rdev->physaddrlen); (void) memcpy(spap, &ifdev->ipaddr, sizeof (ipaddr_t)); (void) memcpy(thap, rdev->physaddr, rdev->physaddrlen); add_arp(rdev, tpap, thap); /* * Create rarp reply structure. */ rrp = calloc(1, sizeof (struct rarpreply) + rdev->physaddrlen + rdev->ifrarplen); if (rrp == NULL) error("out of memory"); rrp->lldest = (uchar_t *)rrp + sizeof (struct rarpreply); rrp->arprep = rrp->lldest + rdev->physaddrlen; rrp->rdev = rdev; (void) memcpy(rrp->lldest, shost, rdev->physaddrlen); (void) memcpy(rrp->arprep, rp, rdev->ifrarplen); retval = dlpi_send(rdev->dh_rarp, rrp->lldest, rdev->physaddrlen, rrp->arprep, rdev->ifrarplen, NULL); free(rrp); if (retval != DLPI_SUCCESS) error("dlpi_send failed: %s", dlpi_strerror(retval)); } /* ARGSUSED */ static void do_delay_write(void *buf) { struct timeval tv; struct rarpreply *rrp; struct rarpdev *rdev; int err; for (;;) { if ((err = sema_wait(&delay_sema)) != 0) { if (err == EINTR) continue; error("do_delay_write: sema_wait failed"); } (void) mutex_lock(&delay_mutex); rrp = delay_list; rdev = rrp->rdev; delay_list = delay_list->next; (void) mutex_unlock(&delay_mutex); (void) gettimeofday(&tv, NULL); if (tv.tv_sec < rrp->tv.tv_sec) (void) sleep(rrp->tv.tv_sec - tv.tv_sec); err = dlpi_send(rdev->dh_rarp, rrp->lldest, rdev->physaddrlen, rrp->arprep, rdev->ifrarplen, NULL); if (err != DLPI_SUCCESS) error("dlpi_send failed: %s", dlpi_strerror(err)); (void) free(rrp); } } /* ARGSUSED */ static void delay_write(struct rarpdev *rdev, struct rarpreply *rrp) { struct rarpreply *trp; (void) mutex_lock(&delay_mutex); if (delay_list == NULL) { delay_list = rrp; } else { trp = delay_list; while (trp->next != NULL) trp = trp->next; trp->next = rrp; } (void) mutex_unlock(&delay_mutex); (void) sema_post(&delay_sema); } /* * See if we have a TFTP boot file for this guy. Filenames in TFTP * boot requests are of the form for Sun-3's and of the form * . for all other architectures. Since we don't know * the client's architecture, either format will do. */ static int mightboot(ipaddr_t ipa) { char path[MAXPATHL]; DIR *dirp; struct dirent *dp; (void) snprintf(path, sizeof (path), "%s/%08X", BOOTDIR, ipa); /* * Try a quick access() first. */ if (access(path, 0) == 0) return (1); /* * Not there, do it the slow way by * reading through the directory. */ (void) sprintf(path, "%08X", ipa); if (!(dirp = opendir(BOOTDIR))) return (0); while ((dp = readdir(dirp)) != NULL) { if (strncmp(dp->d_name, path, 8) != 0) continue; if ((strlen(dp->d_name) != 8) && (dp->d_name[8] != '.')) continue; break; } (void) closedir(dirp); return ((dp != NULL) ? 1 : 0); } /* * Get our IP address and local netmask. */ static void get_ifdata(char *dev, int unit, ipaddr_t *ipp, ipaddr_t *maskp) { int fd; struct ifreq ifr; struct sockaddr_in *sin; /* LINTED pointer */ sin = (struct sockaddr_in *)&ifr.ifr_addr; /* * Open the IP provider. */ if ((fd = open(DEVIP, 0)) < 0) syserr(DEVIP); /* * Ask IP for our IP address. */ (void) snprintf(ifr.ifr_name, sizeof (ifr.ifr_name), "%s%d", dev, unit); if (strioctl(fd, SIOCGIFADDR, -1, sizeof (struct ifreq), (char *)&ifr) < 0) syserr("SIOCGIFADDR"); *ipp = (ipaddr_t)ntohl(sin->sin_addr.s_addr); if (dflag) debug("device %s%d address %s", dev, unit, inet_ntoa(sin->sin_addr)); /* * Ask IP for our netmask. */ if (strioctl(fd, SIOCGIFNETMASK, -1, sizeof (struct ifreq), (char *)&ifr) < 0) syserr("SIOCGIFNETMASK"); *maskp = (ipaddr_t)ntohl(sin->sin_addr.s_addr); if (dflag) debug("device %s%d subnet mask %s", dev, unit, inet_ntoa(sin->sin_addr)); /* * Thankyou ip. */ (void) close(fd); } /* * Translate mac address to IP address. * Return 0 on success, nonzero on failure. */ static int get_ipaddr(struct rarpdev *rdev, uchar_t *laddr, uchar_t *ipp, ipaddr_t *ipaddr) { char host[MAXHOSTL]; char hbuffer[BUFSIZE]; struct hostent *hp, res; int herror; struct in_addr addr; char **p; struct ifdev *ifdev; if (rdev->physaddrlen != ETHERADDRL) { if (dflag) debug("%s %s", " cannot map non 6 byte hardware ", "address to IP address"); return (1); } /* * Translate mac address to hostname and IP address. */ if (ether_ntohost(host, (struct ether_addr *)laddr) != 0 || !(hp = gethostbyname_r(host, &res, hbuffer, sizeof (hbuffer), &herror)) || hp->h_addrtype != AF_INET || hp->h_length != sizeof (ipaddr_t)) { if (dflag) debug("could not map hardware address to IP address"); return (1); } /* * Find the IP address on the right net. */ for (p = hp->h_addr_list; *p; p++) { (void) memcpy(&addr, *p, sizeof (ipaddr_t)); for (ifdev = rdev->ifdev; ifdev != NULL; ifdev = ifdev->next) { if (dflag) { struct in_addr daddr; ipaddr_t netnum; netnum = htonl(ifdev->if_netnum); (void) memcpy(&daddr, &netnum, sizeof (ipaddr_t)); if (ifdev->lunit == -1) debug("trying physical netnum %s" " mask %x", inet_ntoa(daddr), ifdev->if_netmask); else debug("trying logical %d netnum %s" " mask %x", ifdev->lunit, inet_ntoa(daddr), ifdev->if_netmask); } if ((ntohl(addr.s_addr) & ifdev->if_netmask) == ifdev->if_netnum) { /* * Return the correct IP address. */ (void) memcpy(ipp, &addr, sizeof (ipaddr_t)); /* * Return the interface's ipaddr */ (void) memcpy(ipaddr, &ifdev->ipaddr, sizeof (ipaddr_t)); return (0); } } } if (dflag) debug("got host entry but no IP address on this net"); return (1); } static int strioctl(int fd, int cmd, int timout, int len, char *dp) { struct strioctl si; si.ic_cmd = cmd; si.ic_timout = timout; si.ic_len = len; si.ic_dp = dp; return (ioctl(fd, I_STR, &si)); } static void usage(void) { error("Usage: %s [ -ad ] device unit", cmdname); } static void syserr(const char *s) { char buf[256]; int status = 1; (void) snprintf(buf, sizeof (buf), "%s: %s", s, strerror(errno)); (void) fprintf(stderr, "%s: %s\n", cmdname, buf); syslog(LOG_ERR, "%s", buf); thr_exit(&status); } static void error(const char *fmt, ...) { char buf[256]; va_list ap; int status = 1; va_start(ap, fmt); (void) vsprintf(buf, fmt, ap); va_end(ap); (void) fprintf(stderr, "%s: %s\n", cmdname, buf); syslog(LOG_ERR, buf); thr_exit(&status); } /*PRINTFLIKE1*/ static void debug(char *fmt, ...) { va_list ap; (void) mutex_lock(&debug_mutex); va_start(ap, fmt); (void) fprintf(stderr, "%s:[%u] ", cmdname, thr_self()); (void) vfprintf(stderr, fmt, ap); (void) fprintf(stderr, "\n"); va_end(ap); (void) mutex_unlock(&debug_mutex); }