Index: trunk/minix/commands/dhcpd/Makefile
===================================================================
--- trunk/minix/commands/dhcpd/Makefile	(revision 9)
+++ 	(revision )
@@ -1,25 +1,0 @@
-# Makefile for dhcpd.
-
-CFLAGS	= $(OPT) -D_MINIX
-LDFLAGS	=
-CC = exec cc
-
-all:	dhcpd
-
-OBJ=	dhcpd.o tags.o devices.o ether.o
-
-dhcpd:	$(OBJ)
-	$(CC) $(LDFLAGS) -o $@ $(OBJ)
-	install -S 12kw $@
-
-install:	/usr/bin/dhcpd
-
-/usr/bin/dhcpd:	dhcpd
-	install -c $? $@
-
-clean:
-	rm -f *.o dhcpd core a.out
-
-# Dependencies.
-$(OBJ):			dhcpd.h
-dhcpd.o ether.o:	arp.h
Index: trunk/minix/commands/dhcpd/arp.h
===================================================================
--- trunk/minix/commands/dhcpd/arp.h	(revision 9)
+++ 	(revision )
@@ -1,26 +1,0 @@
-/*	arp.h - Address Resolution Protocol packet format.
- *							Author: Kees J. Bot
- *								16 Dec 2000
- */
-#ifndef ARP_H
-#define ARP_H
-
-typedef struct arp46 {
-	ether_addr_t	dstaddr;
-	ether_addr_t	srcaddr;
-	ether_type_t	ethtype;	/* ARP_PROTO. */
-	u16_t		hdr, pro;	/* ARP_ETHERNET & ETH_IP_PROTO. */
-	u8_t		hln, pln;	/* 6 & 4. */
-	u16_t		op;		/* ARP_REQUEST or ARP_REPLY. */
-	ether_addr_t	sha;		/* Source hardware address. */
-	u8_t		spa[4];		/* Source protocol address. */
-	ether_addr_t	tha;		/* Likewise for the target. */
-	u8_t		tpa[4];
-	char		padding[60 - (4*6 + 2*4 + 4*2 + 2*1)];
-} arp46_t;
-
-#define ARP_ETHERNET	1	/* ARP on Ethernet. */
-#define ARP_REQUEST	1	/* A request for an IP address. */
-#define ARP_REPLY	2	/* A reply to a request. */
-
-#endif /* ARP_H */
Index: trunk/minix/commands/dhcpd/build
===================================================================
--- trunk/minix/commands/dhcpd/build	(revision 9)
+++ 	(revision )
@@ -1,3 +1,0 @@
-#!/bin/sh
-make clean
-make && make install
Index: trunk/minix/commands/dhcpd/devices.c
===================================================================
--- trunk/minix/commands/dhcpd/devices.c	(revision 9)
+++ 	(revision )
@@ -1,280 +1,0 @@
-/*	devices.c - Handle network devices.
- *							Author: Kees J. Bot
- *								11 Jun 1999
- */
-#include <sys/types.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <string.h>
-#include <limits.h>
-#include <time.h>
-#include <sys/ioctl.h>
-#include <sys/asynchio.h>
-#include <net/hton.h>
-#include <net/gen/in.h>
-#include <net/gen/ether.h>
-#include <net/gen/eth_hdr.h>
-#include <net/gen/eth_io.h>
-#include <net/gen/ip_hdr.h>
-#include <net/gen/ip_io.h>
-#include <net/gen/udp.h>
-#include <net/gen/udp_hdr.h>
-#include <net/gen/udp_io.h>
-#include <net/gen/dhcp.h>
-#include "dhcpd.h"
-
-void get_buf(buf_t **bp)
-{
-    /* Allocate and return a buffer pointer iff *bp == nil. */
-    if (*bp != nil) {
-	/* Already has one. */
-    } else {
-	/* Get one from the heap. */
-	buf_t *new= allocate(sizeof(*new));
-	new->dhcp= (dhcp_t *) (new->buf + sizeof(eth_hdr_t)
-				+ sizeof(ip_hdr_t) + sizeof(udp_hdr_t));
-	new->udpio= ((udp_io_hdr_t *) new->dhcp) - 1;
-	new->udp= ((udp_hdr_t *) new->dhcp) - 1;
-	new->ip= ((ip_hdr_t *) new->udp) - 1;
-	new->eth= ((eth_hdr_t *) new->ip) - 1;
-	*bp= new;
-    }
-}
-
-void put_buf(buf_t **bp)
-{
-    /* Return a buffer to the heap. */
-    if (*bp != nil) {
-	free(*bp);
-	*bp= nil;
-    }
-}
-
-void give_buf(buf_t **dbp, buf_t **sbp)
-{
-    /* Hand over a buffer to another variable. */
-    put_buf(dbp);
-    *dbp= *sbp;
-    *sbp= nil;
-}
-
-#if __minix_vmd
-#define N_FDS		16	/* Minix-vmd can go async on many fds. */
-#else
-#define N_FDS		 1	/* Minix doesn't have async I/O. */
-#endif
-
-static fd_t fds[N_FDS];			/* List of open descriptors. */
-static struct network *fdwaitq;		/* Queue of nets waiting for fds. */
-
-network_t *newnetwork(void)
-{
-    /* Create and initialize a network structure. */
-    network_t *new;
-
-    new= allocate(sizeof(*new));
-    memset(new, 0, sizeof(*new));
-    new->hostname= nil;
-    new->solicit= NEVER;
-    new->sol_ct= -1;
-    return new;
-}
-
-void closefd(fd_t *fdp)
-{
-    /* Close a descriptor. */
-    if (fdp->fdtype != FT_CLOSED) {
-	asyn_close(&asyn, fdp->fd);
-	close(fdp->fd);
-	fdp->fdtype= FT_CLOSED;
-	fdp->since= 0;
-	put_buf(&fdp->bp);
-	if (debug >= 3) printf("%s: Closed\n", fdp->device);
-    }
-}
-
-int opendev(network_t *np, fdtype_t fdtype, int compete)
-{
-    /* Make sure that a network has the proper device open and configured.
-     * Return true if this is made so, or false if the device doesn't exist.
-     * If compete is true then the caller competes for old descriptors.
-     * The errno value is EAGAIN if we're out of descriptors.
-     */
-    fd_t *fdp, *fdold;
-    time_t oldest;
-    nwio_ethstat_t ethstat;
-    nwio_ethopt_t ethopt;
-    nwio_ipopt_t ipopt;
-    nwio_udpopt_t udpopt;
-    network_t **pqp;
-    static char devbytype[][4] = { "", "eth", "ip", "udp", "udp" };
-
-    /* Don't attempt to open higher level devices if not bound. */
-    if (!(np->flags & NF_BOUND) && fdtype > FT_ETHERNET) {
-	errno= EAGAIN;
-	return 0;
-    }
-
-    /* Check if already open / Find the oldest descriptor. */
-    fdold= nil;
-    oldest= NEVER;
-    for (fdp= fds; fdp < arraylimit(fds); fdp++) {
-	if (fdp->n == np->n && fdp->fdtype == fdtype) {
-	    /* Already open. */
-	    np->fdp= fdp;
-	    return 1;
-	}
-	if (fdp->since <= oldest) { fdold= fdp; oldest= fdp->since; }
-    }
-
-    /* None free?  Then wait for one to get old if so desired. */
-    if (fdold->fdtype != FT_CLOSED && !compete) {
-	errno= EAGAIN;
-	return 0;
-    }
-
-    if (!(np->flags & NF_WAIT)) {
-	for (pqp= &fdwaitq; *pqp != nil; pqp= &(*pqp)->wait) {}
-	*pqp= np;
-	np->wait= nil;
-	np->flags |= NF_WAIT;
-    }
-
-    /* We allow a net to keep a descriptor for half of the fast period. */
-    oldest += DELTA_FAST/2;
-
-    if (fdwaitq != np || (fdold->fdtype != FT_CLOSED && oldest > now)) {
-	/* This net is not the first in the queue, or the oldest isn't
-	 * old enough.  Forget it for now.
-	 */
-	if (oldest < event) event= oldest;
-	errno= EAGAIN;
-	return 0;
-    }
-
-    /* The oldest is mine. */
-    np->flags &= ~NF_WAIT;
-    fdwaitq= np->wait;
-    closefd(fdold);
-
-    /* Open the proper device in the proper mode. */
-    fdp= fdold;
-    fdp->n= np->n;
-    sprintf(fdp->device, "/dev/%s%d", devbytype[fdtype], np->n);
-    np->fdp= fdp;
-
-    if ((fdp->fd= open(fdp->device, O_RDWR)) < 0) {
-	if (errno == ENOENT || errno == ENODEV || errno == ENXIO) return 0;
-	fatal(fdp->device);
-    }
-
-    switch (fdtype) {
-    case FT_ETHERNET:
-	fcntl(np->fdp->fd, F_SETFL, fcntl(np->fdp->fd, F_GETFL) | O_NONBLOCK);
-	if (ioctl(np->fdp->fd, NWIOGETHSTAT, &ethstat) < 0) {
-	    /* Not an Ethernet. */
-	    close(fdp->fd);
-	    return 0;
-	}
-	np->eth= ethstat.nwes_addr;
-	ethopt.nweo_flags= NWEO_COPY | NWEO_EN_LOC | NWEO_EN_BROAD
-			| NWEO_REMANY | NWEO_TYPEANY | NWEO_RWDATALL;
-
-	if (ioctl(fdp->fd, NWIOSETHOPT, &ethopt) < 0) {
-	    fprintf(stderr, "%s: %s: Unable to set eth options: %s\n",
-		program, fdp->device, strerror(errno));
-	    exit(1);
-	}
-	break;
-
-    case FT_ICMP:
-	ipopt.nwio_flags= NWIO_COPY | NWIO_EN_LOC | NWIO_EN_BROAD
-			| NWIO_REMANY | NWIO_PROTOSPEC
-			| NWIO_HDR_O_SPEC | NWIO_RWDATALL;
-	ipopt.nwio_tos= 0;
-	ipopt.nwio_ttl= 1;
-	ipopt.nwio_df= 0;
-	ipopt.nwio_hdropt.iho_opt_siz= 0;
-	ipopt.nwio_proto= IPPROTO_ICMP;
-
-	if (ioctl(fdp->fd, NWIOSIPOPT, &ipopt) < 0) {
-	    fprintf(stderr, "%s: %s: Unable to set IP options: %s\n",
-		program, fdp->device, strerror(errno));
-	    exit(1);
-	}
-	break;
-
-    case FT_BOOTPC:
-	udpopt.nwuo_flags= NWUO_COPY | NWUO_EN_LOC | NWUO_EN_BROAD
-			| NWUO_RP_ANY | NWUO_RA_ANY | NWUO_RWDATALL
-			| NWUO_DI_IPOPT | NWUO_LP_SET;
-	udpopt.nwuo_locport= port_client;
-	goto udp;
-
-    case FT_BOOTPS:
-	udpopt.nwuo_flags= NWUO_EXCL | NWUO_EN_LOC | NWUO_EN_BROAD
-			| NWUO_RP_ANY | NWUO_RA_ANY | NWUO_RWDATALL
-			| NWUO_DI_IPOPT | NWUO_LP_SET;
-	udpopt.nwuo_locport= port_server;
-    udp:
-	if (ioctl(fdp->fd, NWIOSUDPOPT, &udpopt) == -1) {
-	    fprintf(stderr, "%s: %s: Unable to set UDP options: %s\n",
-		program, fdp->device, strerror(errno));
-	    exit(1);
-	}
-	break;
-
-    default:;
-    }
-
-    fdp->fdtype= fdtype;
-    fdp->since= now;
-    if (debug >= 3) printf("%s: Opened\n", fdp->device);
-    return 1;
-}
-
-void closedev(network_t *np, fdtype_t fdtype)
-{
-    /* We no longer need a given type of device to be open. */
-    fd_t *fdp;
-
-    for (fdp= fds; fdp < arraylimit(fds); fdp++) {
-	if (fdp->n == np->n && (fdp->fdtype == fdtype || fdtype == FT_ALL)) {
-	    closefd(fdp);
-	}
-    }
-}
-
-char *ipdev(int n)
-{
-    /* IP device for network #n. */
-    static char device[sizeof("/dev/ipNNN")];
-
-    sprintf(device, "/dev/ip%d", n);
-    return device;
-}
-
-void set_ipconf(char *device, ipaddr_t ip, ipaddr_t mask, unsigned mtu)
-{
-    /* Set IP address and netmask of an IP device. */
-    int fd;
-    nwio_ipconf_t ipconf;
-
-    if (test > 0) return;
-
-    if ((fd= open(device, O_RDWR)) < 0) fatal(device);
-    ipconf.nwic_flags= NWIC_IPADDR_SET | NWIC_NETMASK_SET;
-    ipconf.nwic_ipaddr= ip;
-    ipconf.nwic_netmask= mask;
-#ifdef NWIC_MTU_SET
-    if (mtu != 0) {
-	ipconf.nwic_flags |= NWIC_MTU_SET;
-	ipconf.nwic_mtu= mtu;
-    }
-#endif
-    if (ioctl(fd, NWIOSIPCONF, &ipconf) < 0) fatal(device);
-    close(fd);
-}
Index: trunk/minix/commands/dhcpd/dhcpd.c
===================================================================
--- trunk/minix/commands/dhcpd/dhcpd.c	(revision 9)
+++ 	(revision )
@@ -1,1406 +1,0 @@
-/*	dhcpd 1.15 - Dynamic Host Configuration Protocol daemon.
- *							Author: Kees J. Bot
- *								11 Jun 1999
- */
-#include <sys/types.h>
-#include <stdio.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <signal.h>
-#include <string.h>
-#include <time.h>
-#include <limits.h>
-#include <configfile.h>
-#include <sys/ioctl.h>
-#include <sys/asynchio.h>
-#include <net/hton.h>
-#include <net/gen/socket.h>
-#include <net/gen/netdb.h>
-#include <net/gen/in.h>
-#include <net/gen/inet.h>
-#include <net/gen/ether.h>
-#include <net/gen/if_ether.h>
-#include <net/gen/eth_hdr.h>
-#include <net/gen/ip_hdr.h>
-#include <net/gen/udp.h>
-#include <net/gen/udp_hdr.h>
-#include <net/gen/udp_io.h>
-#include <net/gen/dhcp.h>
-#include "arp.h"
-#define EXTERN
-#include "dhcpd.h"
-
-char *configfile= PATH_DHCPCONF;
-char *poolfile= PATH_DHCPPOOL;
-static char *cachefile= PATH_DHCPCACHE;
-static int qflag;		/* True if printing cached DHCP data. */
-static int aflag, rflag;	/* True if adding or deleting pool addresses. */
-
-#define BCAST_IP	HTONL(0xFFFFFFFFUL)
-
-/* We try to play with up to this many networks. */
-#define N_NETS		32
-static unsigned n_nets;		/* Actual number of networks. */
-
-void report(const char *label)
-{
-    static FILE *logfp;
-    if(!logfp)
-	logfp = fopen("/usr/log/dhcp.log", "w");
-    if(logfp)
-    	fprintf(logfp, "%s: %s: %s\n", program, label, strerror(errno));
-}
-
-void fatal(const char *label)
-{
-    report(label);
-    exit(1);
-}
-
-void *allocate(size_t size)
-{
-    void *mem;
-
-    if ((mem= malloc(size)) == nil) fatal("Can't allocate memory");
-    return mem;
-}
-
-/* Choose a DHCP xid based on the start time and network number.  Not really
- * random, but we don't have anything more random than the clock anyway.
- */
-#define XID(np)		htonl(((u32_t) (np)->start << 8) | (np)->n)
-
-static network_t *network[N_NETS];
-
-int ifname2if(const char *name)
-{
-    /* Translate an interface name to a number, -1 if bad. */
-    char *end;
-    unsigned long n;
-
-    if (*name++ != 'i' || *name++ != 'p') return -1;
-    n= strtoul(name, &end, 10);
-    if (end == name || *end != 0) return -1;
-    if (n >= N_NETS) return -1;
-    return n;
-}
-
-network_t *if2net(int n)
-{
-    /* Translate an interface number to a network struct. */
-    int i;
-
-    for (i= 0; i < n_nets; i++) {
-	if (network[i]->n == n) return network[i];
-    }
-    return nil;
-}
-
-static ipaddr_t defaultmask(ipaddr_t ip)
-{
-    /* Compute netmask by the oldfashioned Class rules. */
-    if (B(&ip)[0] < 0x80) return HTONL(0xFF000000UL);	/* Class A. */
-    if (B(&ip)[0] < 0xC0) return HTONL(0xFFFF0000UL);	/* Class B. */
-    if (B(&ip)[0] < 0xE0) return HTONL(0xFFFFFF00UL);	/* Class C. */
-    return HTONL(0xFFFFFFFFUL);  /* Multicast?  Shouldn't happen... */
-}
-
-#define POOL_MAGIC	HTONL(0x81F85D00UL)
-
-typedef struct pool {		/* Dynamic pool entry. */
-	u32_t		magic;		/* Pool file magic number. */
-	ipaddr_t	ip;		/* IP address. */
-	u32_t		expire;		/* When does/did the lease expire? */
-	u8_t		len;		/* Client ID length. */
-	u8_t		unused[19];	/* Space for extensions. */
-	u8_t		clid[CLID_MAX];	/* Client ID of current/last user. */
-} pool_t;
-
-static int openpool(int mode)
-{
-    /* Open the dynamic pool and lock it, return fd on success or -1. */
-    int fd;
-    struct flock lck;
-
-    if ((fd= open(poolfile, mode, 0644)) < 0) {
-	if (errno != ENOENT) fatal(poolfile);
-	return -1;
-    }
-    if (mode != O_RDONLY) {
-	lck.l_type= F_WRLCK;
-	lck.l_whence= SEEK_SET;
-	lck.l_start= 0;
-	lck.l_len= 0;
-	if (fcntl(fd, F_SETLKW, &lck) < 0) fatal(poolfile);
-    }
-    return fd;
-}
-
-static int readpool(int fd, pool_t *entry)
-{
-    /* Read one pool table entry, return true unless EOF. */
-    ssize_t r;
-
-    if ((r= read(fd, entry, sizeof(*entry))) < 0) fatal(poolfile);
-    if (r == 0) return 0;
-
-    if (r != sizeof(*entry) || entry->magic != POOL_MAGIC) {
-	fprintf(stderr, "%s: %s: Pool table is corrupt\n",
-	    program, poolfile);
-	close(fd);
-	return 0;
-    }
-    return 1;
-}
-
-#if !__minix_vmd	/* No fsync() for Minix. */
-#define fsync(fd)	sync()
-#endif
-
-static void writepool(int fd, pool_t *entry)
-{
-    /* (Over)write a pool table entry. */
-    if (write(fd, entry, sizeof(*entry)) < 0
-	|| (entry->expire > now && fsync(fd) < 0)
-    ) {
-	fatal(poolfile);
-    }
-}
-
-static ipaddr_t findpool(u8_t *client, size_t len, ipaddr_t ifip)
-{
-    /* Look for a client ID in the dynamic address pool within the same network
-     * as 'ifip'.  Select an unused one for a new client if necessary.  Return
-     * 0 if nothing is available, otherwise the IP address we can offer.
-     */
-    int fd, found;
-    pool_t entry, oldest;
-    dhcp_t dhcp;
-    u8_t *pmask;
-    ipaddr_t mask;
-
-    /* Any information available on the network the client is at? */
-    if (!makedhcp(&dhcp, nil, 0, nil, 0, ifip, ifip, nil)) return 0;
-
-    if ((fd= openpool(O_RDWR)) < 0) return 0;
-
-    (void) gettag(&dhcp, DHCP_TAG_NETMASK, &pmask, nil);
-    memcpy(&mask, pmask, sizeof(mask));
-
-    oldest.expire= NEVER;
-    while ((found= readpool(fd, &entry))) {
-	/* Deleted entry? */
-	if (entry.ip == 0) continue;
-
-	/* Correct network? */
-	if (((entry.ip ^ ifip) & mask) != 0) continue;
-
-	/* Client present? */
-	if (entry.len == len && memcmp(entry.clid, client, len) == 0) break;
-
-	/* Oldest candidate for a new lease? */
-	entry.expire= ntohl(entry.expire);
-	if (entry.expire < oldest.expire) oldest= entry;
-    }
-    close(fd);
-
-    if (found) return entry.ip;
-    if (oldest.expire <= now) return oldest.ip;
-    return 0;
-}
-
-static int commitpool(ipaddr_t ip, u8_t *client, size_t len, time_t expire)
-{
-    /* Commit a new binding to stable storage, return true on success. */
-    int fd;
-    pool_t entry;
-
-    if ((fd= openpool(O_RDWR)) < 0) return 0;
-
-    do {
-	if (!readpool(fd, &entry)) {
-	    close(fd);
-	    return 0;
-	}
-    } while (entry.ip != ip);
-
-    entry.expire= htonl(expire);
-    entry.len= len;
-    memcpy(entry.clid, client, len);
-    if (lseek(fd, -(off_t)sizeof(entry), SEEK_CUR) == -1) fatal(poolfile);
-    writepool(fd, &entry);
-    close(fd);
-    return 1;
-}
-
-static void updatepool(int add, const char *name)
-{
-    /* Add a new IP address to the dynamic pool. */
-    ipaddr_t ip;
-    int fd, i;
-    pool_t entry;
-    struct hostent *he;
-    off_t off, off0;
-
-    if ((he= gethostbyname(name)) == nil || he->h_addrtype != AF_INET) {
-	fprintf(stderr, "%s: %s: Unknown host\n", program, name);
-	exit(1);
-    }
-    for (i= 0; he->h_addr_list[i] != nil; i++) {}
-    if (i != 1) {
-	fprintf(stderr, "%s: %s has %d addresses\n", program, name, i);
-	exit(1);
-    }
-    memcpy(&ip, he->h_addr_list[0], sizeof(ip));
-
-    if ((fd= openpool(O_RDWR|O_CREAT)) < 0) fatal(poolfile);
-
-    off= 0;
-    off0= -1;
-    while (readpool(fd, &entry)) {
-	if (add) {
-	    if (entry.ip == ip) {
-		fprintf(stderr, "%s: %s: %s is already present\n",
-		    program, poolfile, name);
-		exit(1);
-	    }
-	    if (entry.ip == 0 && off0 == -1) off0= off;
-	} else {
-	    if (entry.ip == ip) {
-		memset(&entry, 0, sizeof(entry));
-		entry.magic= POOL_MAGIC;
-		entry.ip= 0;
-		if (lseek(fd, off, SEEK_SET) == -1) fatal(poolfile);
-		writepool(fd, &entry);
-	    }
-	}
-	off+= sizeof(entry);
-    }
-
-    if (add) {
-	if (off0 != -1 && lseek(fd, off0, SEEK_SET) == -1) fatal(poolfile);
-	memset(&entry, 0, sizeof(entry));
-	entry.magic= POOL_MAGIC;
-	entry.ip= ip;
-	writepool(fd, &entry);
-    }
-    close(fd);
-}
-
-static void cachedhcp(int n, dhcp_t *dp)
-{
-    /* Store a DHCP packet in a cache where those who care can find it. */
-    static int inited;
-    FILE *fp;
-    int fd;
-    int mode;
-
-    if (test > 0) return;
-
-    if (!inited) {
-	/* First time, clear store and also save my pid. */
-	if ((fp= fopen(PATH_DHCPPID, "w")) != nil) {
-	    if (fprintf(fp, "%d\n", getpid()) == EOF || fclose(fp) == EOF) {
-		fatal(PATH_DHCPPID);
-	    }
-	}
-	inited= 1;
-	mode= O_WRONLY | O_CREAT | O_TRUNC;
-    } else {
-	mode= O_WRONLY;
-    }
-
-    dp->xid= htonl(now);	/* To tell how old this data is. */
-
-    if ((fd= open(cachefile, mode, 0666)) < 0
-	|| lseek(fd, (off_t) n * sizeof(*dp), SEEK_SET) == -1
-	|| write(fd, dp, sizeof(*dp)) < 0
-	|| close(fd) < 0
-    ) {
-	if (errno != ENOENT) fatal(cachefile);
-    }
-}
-
-static void printdata(void)
-{
-    /* Show the contents of the cache and the dynamic pool. */
-    int fd;
-    dhcp_t d;
-    ssize_t r;
-    int i;
-    pool_t entry;
-    unsigned long expire;
-    char delta[3*sizeof(u32_t)];
-
-    initdhcpconf();
-
-    if ((fd= open(cachefile, O_RDONLY)) < 0) fatal(cachefile);
-    i= 0;
-    while ((r= read(fd, &d, sizeof(d))) == sizeof(d)) {
-	if (d.yiaddr != 0) {
-	    printf("DHCP data for network %d:\n", i);
-	    printdhcp(&d);
-	}
-	i++;
-    }
-    if (r < 0) fatal(cachefile);
-    close(fd);
-
-    if ((fd= openpool(O_RDONLY)) >= 0) {
-	printf("Dynamic address pool since %ld:\n", (long) now);
-	while (readpool(fd, &entry)) {
-	    if (entry.ip == 0) continue;
-	    expire= ntohl(entry.expire);
-	    if (expire == 0) {
-		strcpy(delta, "unused");
-	    } else
-	    if (expire == 0xFFFFFFFFUL) {
-		strcpy(delta, "infinite");
-	    } else
-	    if (expire < now) {
-		sprintf(delta, "-%lu", now - expire);
-	    } else {
-		sprintf(delta, "+%lu", expire - now);
-	    }
-	    printf("\t%-15s %8s  ", inet_ntoa(entry.ip), delta);
-	    for (i= 0; i < entry.len; i++) {
-		printf("%02X", entry.clid[i]);
-	    }
-	    fputc('\n', stdout);
-	}
-	close(fd);
-    }
-}
-
-static udpport_t portbyname(const char *name)
-{
-    struct servent *se;
-
-    if ((se= getservbyname(name, "udp")) == nil) {
-	fprintf(stderr, "%s: Unknown port \"%s\"\n", program, name);
-	exit(1);
-    }
-    return se->s_port;
-}
-
-static int send(network_t *np, void *data, size_t len)
-{
-    /* Send out a packet using a filedescriptor that is probably in async mode,
-     * so first dup() a sync version, then write.  Return true on success.
-     */
-    int fd;
-    ssize_t r;
-
-    if ((fd= dup(np->fdp->fd)) < 0) fatal("Can't dup()");
-    if ((r= write(fd, data, len)) < 0) {
-	report(np->fdp->device);
-	sleep(10);
-    }
-    close(fd);
-    return r >= 0;
-}
-
-static size_t servdhcp(network_t *np, buf_t *bp, size_t dlen)
-{
-    buf_t *abp= nil;
-    ipaddr_t cip, ifip;
-    u8_t defclid[1+sizeof(bp->dhcp->chaddr)];
-    u8_t *pdata, *client, *class, *server, *reqip, *lease;
-    u32_t expire;
-    size_t len, cilen, calen;
-    int type, dyn;
-    u8_t atype;
-    static char NAKMESS[] = "IP address requested isn't yours";
-
-    if (test > 0) return 0;
-
-    /* The IP address of the interface close to the client. */
-    ifip= bp->dhcp->giaddr != 0 ? bp->dhcp->giaddr : np->ip;
-
-    /* All kinds of DHCP tags. */
-    if (gettag(bp->dhcp, DHCP_TAG_TYPE, &pdata, nil)) {
-	type= *pdata;
-    } else {
-	type= -1;		/* BOOTP? */
-    }
-
-    if (!gettag(bp->dhcp, DHCP_TAG_CLIENTID, &client, &cilen)) {
-	defclid[0]= bp->dhcp->htype;
-	memcpy(defclid+1, bp->dhcp->chaddr, bp->dhcp->hlen);
-	client= defclid;
-	cilen= 1+bp->dhcp->hlen;
-    }
-
-    if (!gettag(bp->dhcp, DHCP_TAG_CLASSID, &class, &calen)) {
-	calen= 0;
-    }
-
-    if (!gettag(bp->dhcp, DHCP_TAG_SERVERID, &server, nil)) {
-	server= B(&np->ip);
-    }
-
-    if (!gettag(bp->dhcp, DHCP_TAG_REQIP, &reqip, nil)) {
-	reqip= nil;
-    }
-
-    /* I'm a server?  Then see if I know this client. */
-    if ((np->flags & NF_SERVING)
-	&& bp->dhcp->op == DHCP_BOOTREQUEST
-	&& between(1, bp->dhcp->hlen, sizeof(bp->dhcp->chaddr))
-	&& (server == nil || memcmp(server, &np->ip, sizeof(np->ip)) == 0)
-    ) {
-	get_buf(&abp);
-
-	/* Is the client in my tables? */
-	(void) makedhcp(abp->dhcp, class, calen, client, cilen, 0, ifip, nil);
-	cip= abp->dhcp->yiaddr;
-
-	dyn= 0;
-	/* If not, do we have a dynamic address? */
-	if (cip == 0 && (cip= findpool(client, cilen, ifip)) != 0) dyn= 1;
-
-	if (type == DHCP_INFORM) {
-	    /* The client already has an address, it just wants information.
-	     * We only answer if we could answer a normal request (cip != 0),
-	     * unless configured to answer anyone.
-	     */
-	    if (cip != 0 || (np->flags & NF_INFORM)) cip= bp->dhcp->ciaddr;
-	}
-
-	if (cip == 0 || !makedhcp(abp->dhcp, class, calen,
-					client, cilen, cip, ifip, nil)) {
-	    put_buf(&abp);
-	}
-
-	if (abp != nil) {
-	    if (gettag(abp->dhcp, DHCP_TAG_LEASE, &lease, nil)) {
-		memcpy(&expire, lease, sizeof(expire));
-		expire= now + ntohl(expire);
-		if (expire < now) expire= 0xFFFFFFFFUL;
-	    } else {
-		if (dyn) {
-		    /* A dynamic address must have a lease. */
-		    fprintf(stderr, "%s: No lease set for address %s\n",
-			program, inet_ntoa(cip));
-		    exit(1);
-		}
-		lease= nil;
-		expire= 0xFFFFFFFFUL;
-	    }
-
-	    /* What does our client want, and what do we say? */
-	    switch (type) {
-	    case DHCP_DISCOVER:
-		atype= DHCP_OFFER;
-
-		/* Assign this address for a short moment. */
-		if (dyn && !commitpool(cip, client, cilen, now + DELTA_FAST)) {
-		    put_buf(&abp);
-		}
-		break;
-
-	    case -1:/* BOOTP */
-	    case DHCP_REQUEST:
-	    case DHCP_INFORM:
-		atype= DHCP_ACK;
-		/* The address wanted must be the address we offer. */
-		if ((reqip != nil && memcmp(reqip, &cip, sizeof(cip)) != 0)
-		    || (bp->dhcp->ciaddr != 0 && bp->dhcp->ciaddr != cip)
-		) {
-		    atype= DHCP_NAK;
-		} else
-		if (dyn && type == DHCP_REQUEST) {
-		    /* Assign this address for the duration of the lease. */
-		    if (!commitpool(cip, client, cilen, expire)) put_buf(&abp);
-		}
-		break;
-
-	    case DHCP_DECLINE:
-		/* Our client doesn't want the offered address! */
-		if (dyn
-		    && reqip != nil
-		    && memcmp(reqip, &cip, sizeof(cip)) == 0
-		) {
-		    int i;
-
-		    fprintf(stderr, "%s: ", program);
-		    for (i= 0; i < cilen; i++) {
-			fprintf(stderr, "%02X", client[i]);
-		    }
-		    fprintf(stderr, " declines %s", inet_ntoa(cip));
-		    if (gettag(bp->dhcp, DHCP_TAG_MESSAGE, &pdata, &len)) {
-			fprintf(stderr, " saying: \"%.*s\"", (int)len, pdata);
-		    }
-		    fputc('\n', stderr);
-
-		    /* Disable address for the duration of the lease. */
-		    (void) commitpool(cip, nil, 0, expire);
-		}
-		put_buf(&abp);
-		break;
-
-	    case DHCP_RELEASE:
-		/* Our client is nice enough to return its address. */
-		if (dyn) (void) commitpool(cip, client, cilen, now);
-		put_buf(&abp);
-		break;
-
-	    default:	/* Anything else is ignored. */
-		put_buf(&abp);
-	    }
-	}
-
-	if (abp != nil) {
-	    /* Finish the return packet. */
-	    abp->dhcp->htype= bp->dhcp->htype;
-	    abp->dhcp->hlen= bp->dhcp->hlen;
-	    abp->dhcp->hops= 0;
-	    abp->dhcp->xid= bp->dhcp->xid;
-	    abp->dhcp->secs= 0;
-	    abp->dhcp->flags= bp->dhcp->flags;
-	    abp->dhcp->ciaddr= 0;
-	    abp->dhcp->yiaddr= atype == DHCP_NAK ? 0 : cip;
-	    if (atype == DHCP_NAK) abp->dhcp->siaddr= 0;
-	    abp->dhcp->giaddr= bp->dhcp->giaddr;
-	    memcpy(abp->dhcp->chaddr,bp->dhcp->chaddr,sizeof(bp->dhcp->chaddr));
-
-	    settag(abp->dhcp, DHCP_TAG_SERVERID, &np->ip, sizeof(np->ip));
-
-	    if (lease == nil) {
-		/* No lease specified?  Then give an infinite lease. */
-		settag(abp->dhcp, DHCP_TAG_LEASE, &expire, sizeof(expire));
-	    }
-
-	    if (type == DHCP_INFORM) {
-		/* Oops, this one has a fixed address, so no lease business. */
-		abp->dhcp->yiaddr= 0;
-		settag(abp->dhcp, DHCP_TAG_LEASE, nil, 0);
-		settag(abp->dhcp, DHCP_TAG_RENEWAL, nil, 0);
-		settag(abp->dhcp, DHCP_TAG_REBINDING, nil, 0);
-	    }
-
-	    if (atype == DHCP_NAK) {
-		/* A NAK doesn't need much. */
-		memset(abp->dhcp->sname, 0, sizeof(abp->dhcp->sname));
-		memset(abp->dhcp->file, 0, sizeof(abp->dhcp->file));
-		memset(abp->dhcp->options, 255, sizeof(abp->dhcp->options));
-		settag(abp->dhcp, DHCP_TAG_MESSAGE, NAKMESS, sizeof(NAKMESS));
-	    }
-
-	    settag(abp->dhcp, DHCP_TAG_TYPE, &atype, sizeof(atype));
-
-	    /* Figure out where to send this to. */
-	    abp->udpio->uih_src_addr= np->ip;
-	    abp->udpio->uih_src_port= port_server;
-	    if (bp->dhcp->giaddr != 0) {
-		abp->udpio->uih_dst_addr= bp->dhcp->giaddr;
-		abp->udpio->uih_dst_port= port_server;
-	    } else
-	    if (bp->dhcp->flags & DHCP_FLAGS_BCAST) {
-		abp->udpio->uih_dst_addr= BCAST_IP;
-		abp->udpio->uih_dst_port= port_client;
-	    } else
-	    if (bp->udpio->uih_src_addr != 0
-		&& bp->udpio->uih_dst_addr == np->ip
-	    ) {
-		abp->udpio->uih_dst_addr= bp->udpio->uih_src_addr;
-		abp->udpio->uih_dst_port= port_client;
-	    } else {
-		abp->udpio->uih_dst_addr= BCAST_IP;
-		abp->udpio->uih_dst_port= port_client;
-	    }
-	    abp->udpio->uih_ip_opt_len= 0;
-	    abp->udpio->uih_data_len= sizeof(dhcp_t);
-
-	    /* Copy the packet to the input buffer, and return the new size. */
-	    memcpy(bp->buf, abp->buf, sizeof(bp->buf));
-	    put_buf(&abp);
-	    return sizeof(udp_io_hdr_t) + sizeof(dhcp_t);
-	}
-    }
-
-    /* I'm a relay?  If it is a not already a relayed request then relay. */
-    if ((np->flags & NF_RELAYING)
-	&& bp->dhcp->op == DHCP_BOOTREQUEST
-	&& bp->dhcp->giaddr == 0
-    ) {
-	bp->dhcp->giaddr= np->ip;
-	bp->udpio->uih_src_addr= np->ip;
-	bp->udpio->uih_src_port= port_server;
-	bp->udpio->uih_dst_addr= np->server;
-	bp->udpio->uih_dst_port= port_server;
-	return dlen;
-    }
-
-    /* I'm a relay?  If the server sends a reply to me then relay back. */
-    if ((np->flags & NF_RELAYING)
-	&& bp->dhcp->op == DHCP_BOOTREPLY
-	&& bp->dhcp->giaddr == np->ip
-    ) {
-	bp->dhcp->giaddr= 0;
-	bp->udpio->uih_src_addr= np->ip;
-	bp->udpio->uih_src_port= port_server;
-	bp->udpio->uih_dst_addr= BCAST_IP;
-	bp->udpio->uih_dst_port= port_client;
-	return dlen;
-    }
-
-    /* Don't know what to do otherwise, so doing nothing seems wise. */
-    return 0;
-}
-
-static void onsig(int sig)
-{
-    switch (sig) {
-    case SIGUSR1:	debug++;	break;
-    case SIGUSR2:	debug= 0;	break;
-    }
-}
-
-static void usage(void)
-{
-    fprintf(stderr,
-"Usage: %s [-qar] [-t[L]] [-d[L]] [-f config] [-c cache] [-p pool] [host ...]\n",
-	program);
-    exit(1);
-}
-
-int main(int argc, char **argv)
-{
-    int i;
-    network_t *np;
-    struct sigaction sa;
-    ssize_t r= -1;
-    buf_t *bp= nil;
-    static struct timeval eventtv;
-
-    program= argv[0];
-    start= now= time(nil);
-
-    debug= 0;
-    i= 1;
-    while (i < argc && argv[i][0] == '-') {
-	char *opt= argv[i++]+1;
-
-	if (opt[0] == '-' && opt[1] == 0) break;	/* -- */
-
-	while (*opt != 0) switch (*opt++) {
-	case 'f':
-	    if (*opt == 0) {
-		if (i == argc) usage();
-		opt= argv[i++];
-	    }
-	    configfile= opt;
-	    opt= "";
-	    break;
-	case 'c':
-	    if (*opt == 0) {
-		if (i == argc) usage();
-		opt= argv[i++];
-	    }
-	    cachefile= opt;
-	    opt= "";
-	    break;
-	case 'p':
-	    if (*opt == 0) {
-		if (i == argc) usage();
-		opt= argv[i++];
-	    }
-	    poolfile= opt;
-	    opt= "";
-	    break;
-	case 't':
-	    test= 1;
-	    if (between('0', *opt, '9')) test= strtoul(opt, &opt, 10);
-	    break;
-	case 'd':
-	    debug= 1;
-	    if (between('0', *opt, '9')) debug= strtoul(opt, &opt, 10);
-	    break;
-	case 'q':
-	    qflag= 1;
-	    break;
-	case 'a':
-	    aflag= 1;
-	    break;
-	case 'r':
-	    rflag= 1;
-	    break;
-	default:
-	    usage();
-	}
-    }
-    if (aflag + rflag + qflag > 1) usage();
-
-    if (aflag || rflag) {
-	/* Add or remove addresses from the dynamic pool. */
-	while (i < argc) updatepool(aflag, argv[i++]);
-	exit(0);
-    }
-
-    if (i != argc) usage();
-
-    if (qflag) {
-	/* Only show the contents of the cache and dynamic pool to the user. */
-	printdata();
-	exit(0);
-    }
-
-    /* BOOTP ports. */
-    port_server= portbyname("bootps");
-    port_client= portbyname("bootpc");
-
-    sa.sa_handler= onsig;
-    sigemptyset(&sa.sa_mask);
-    sa.sa_flags= 0;
-    sigaction(SIGUSR1, &sa, nil);
-    sigaction(SIGUSR2, &sa, nil);
-
-    /* Initial configuration. */
-    for (i= 0; i < N_NETS; i++) {
-	int fd;
-	ipaddr_t ip, mask;
-
-	/* Is there something there? */
-	if ((fd= open(ipdev(i), O_RDWR|O_NONBLOCK)) < 0) {
-	    if (errno != ENOENT && errno != ENODEV && errno != ENXIO) {
-		fatal(ipdev(i));
-	    }
-	    continue;
-	}
-	close(fd);
-
-	network[n_nets++]= np= newnetwork();
-	np->n= i;
-
-	/* Ethernet? */
-	if (opendev(np, FT_ETHERNET, 1)) {
-	    np->type= B(&np->eth)[0] != 'Z' ? NT_ETHERNET : NT_SINK;
-	    if (debug >= 1) {
-		printf("%s: Ethernet address is %s%s\n",
-		    np->fdp->device, ether_ntoa(&np->eth),
-		    np->type == NT_SINK ? " (sink)" : "");
-	    }
-	    closedev(np, FT_ETHERNET);
-	}
-
-	/* Only true Ethernets worry about DHCP. */
-	if (np->type != NT_ETHERNET) np->renew= np->rebind= np->lease= NEVER;
-    }
-
-    /* Try to find my interfaces in the DHCP table. */
-    for (i= 0; i < n_nets; i++) {
-	ipaddr_t cip;
-	u8_t clid[1+DHCP_HLEN_ETH];
-	size_t cilen;
-
-	np= network[i];
-	if (np->flags & NF_BOUND) continue;
-
-	if (np->type == NT_IP) {
-	    cilen= 0;
-	} else {
-	    ether2clid(clid, &np->eth);
-	    cilen= 1+DHCP_HLEN_ETH;
-	}
-
-	/* Try to find an Ethernet address, or the IP address of an already
-	 * configured network.  If we have data we get an IP address back.
-	 */
-	get_buf(&bp);
-	(void) makedhcp(bp->dhcp, (u8_t *) "Minix", 5,
-					clid, cilen, np->ip, 0, np);
-	cip= bp->dhcp->yiaddr;
-
-	/* Gather information on the interface. */
-	if (cip != 0
-	    && makedhcp(bp->dhcp, (u8_t *) "Minix", 5,
-					clid, cilen, cip, cip, np)
-	    && test < 2
-	) {
-	    u8_t *pdata;
-	    u16_t mtu;
-
-	    cachedhcp(np->n, bp->dhcp);
-	    np->ip= cip;
-	    (void) gettag(bp->dhcp, DHCP_TAG_NETMASK, &pdata, nil);
-	    memcpy(&np->mask, pdata, sizeof(np->mask));
-	    if (gettag(bp->dhcp, DHCP_TAG_GATEWAY, &pdata, nil)) {
-		memcpy(&np->gateway, pdata, sizeof(np->gateway));
-	    } else {
-		np->gateway= 0;
-	    }
-	    if (gettag(bp->dhcp, DHCP_TAG_IPMTU, &pdata, nil)) {
-		memcpy(&mtu, pdata, sizeof(mtu));
-		mtu= ntohs(mtu);
-	    } else {
-		mtu= 0;
-	    }
-	    set_ipconf(ipdev(np->n), np->ip, np->mask, mtu);
-	    if (debug >= 1) {
-		printf("%s: IP address is %s\n",
-		    ipdev(np->n), cidr_ntoa(np->ip, np->mask));
-	    }
-	    np->flags |= NF_BOUND;
-	    np->renew= np->rebind= np->lease= NEVER;
-	    np->sol_ct= N_SOLICITS;
-	    np->solicit= 0;
-
-	    /* Other (previous) interfaces may have been defined. */
-	    i= 0;
-	}
-	put_buf(&bp);
-    }
-
-    for (;;) {
-	now= time(nil);
-	event= NEVER;
-
-	/* Is it time to request/renew a lease? */
-	for (i= 0; i < n_nets; i++) {
-	    np= network[i];
-
-	    if (np->renew <= now) {
-		u8_t type;
-		static u8_t taglist[] = {
-		    DHCP_TAG_NETMASK, DHCP_TAG_GATEWAY, DHCP_TAG_DNS,
-		    	DHCP_TAG_HOSTNAME
-		};
-		u8_t ethclid[1+DHCP_HLEN_ETH];
-
-		/* We may have lost our binding or even our lease. */
-		if (np->rebind <= now) np->server= BCAST_IP;
-
-		if (np->lease <= now) {
-		    if (np->flags & NF_BOUND) closedev(np, FT_ALL);
-
-		    if ((np->flags & (NF_BOUND | NF_POSSESSIVE)) == NF_BOUND) {
-			set_ipconf(ipdev(np->n), np->ip= 0, np->mask= 0, 0);
-			if (debug >= 1) {
-			    printf("%s: Interface disabled (lease expired)\n",
-				ipdev(np->n));
-			}
-		    }
-		    np->flags &= ~NF_BOUND;
-		}
-
-		/* See if we can open the network we need to send on. */
-		if (!(np->flags & NF_BOUND)) {
-		    if (!opendev(np, FT_ETHERNET, 1)) continue;
-		} else {
-		    if (!opendev(np, FT_BOOTPC, 1)) continue;
-		}
-
-		if (!(np->flags & NF_NEGOTIATING)) {
-		    /* We need to start querying a DHCP server. */
-		    np->start= now;
-		    np->delta= DELTA_FIRST;
-		    np->flags |= NF_NEGOTIATING;
-		}
-
-		/* Fill in a DHCP query packet. */
-		get_buf(&bp);
-		dhcp_init(bp->dhcp);
-		bp->dhcp->op= DHCP_BOOTREQUEST;
-		bp->dhcp->htype= DHCP_HTYPE_ETH;
-		bp->dhcp->hlen= DHCP_HLEN_ETH;
-		bp->dhcp->xid= XID(np);
-		bp->dhcp->secs= htons(now - np->start > 0xFFFF
-					? 0xFFFF : now - np->start);
-		memcpy(bp->dhcp->chaddr, &np->eth, sizeof(np->eth));
-
-		if (np->lease <= now) {
-		    /* First time, or my old server is unresponsive. */
-		    type= DHCP_DISCOVER;
-		} else {
-		    /* Request an offered address or renew an address. */
-		    type= DHCP_REQUEST;
-		    if (np->flags & NF_BOUND) {
-			/* A renewal, I claim my current address. */
-			bp->dhcp->ciaddr= np->ip;
-		    } else {
-			/* Nicely ask for the address just offered. */
-			settag(bp->dhcp, DHCP_TAG_REQIP, &np->ip,
-							sizeof(np->ip));
-			settag(bp->dhcp, DHCP_TAG_SERVERID, &np->server,
-							sizeof(np->server));
-		    }
-		}
-		settag(bp->dhcp, DHCP_TAG_TYPE, &type, 1);
-
-		/* My client ID.  Simply use the default. */
-		ether2clid(ethclid, &np->eth);
-		settag(bp->dhcp, DHCP_TAG_CLIENTID, ethclid, sizeof(ethclid));
-
-		/* The Class ID may serve to recognize Minix hosts. */
-		settag(bp->dhcp, DHCP_TAG_CLASSID, "Minix", 5);
-
-		/* The few tags that Minix can make good use of. */
-		settag(bp->dhcp, DHCP_TAG_REQPAR, taglist, sizeof(taglist));
-
-		/* Some weird sites use a hostname, not a client ID. */
-		if (np->hostname != nil) {
-		    settag(bp->dhcp, DHCP_TAG_HOSTNAME,
-					np->hostname, strlen(np->hostname));
-		}
-
-		bp->udpio->uih_src_addr= np->ip;
-		bp->udpio->uih_dst_addr= np->server;
-		bp->udpio->uih_src_port= port_client;
-		bp->udpio->uih_dst_port= port_server;
-		bp->udpio->uih_ip_opt_len= 0;
-		bp->udpio->uih_data_len= sizeof(dhcp_t);
-
-		if (!(np->flags & NF_BOUND)) {
-		    /* Rebind over Ethernet. */
-		    udp2ether(bp, np);
-		    if (send(np, bp->eth, sizeof(eth_hdr_t) + sizeof(ip_hdr_t)
-					+ sizeof(udp_hdr_t) + sizeof(dhcp_t))) {
-			if (debug >= 1) {
-			    printf("%s: Broadcast DHCP %s\n",
-				np->fdp->device, dhcptypename(type));
-			    if (debug >= 2) printdhcp(bp->dhcp);
-			}
-		    }
-		} else {
-		    /* Renew over UDP. */
-		    if (send(np, bp->udpio, sizeof(udp_io_hdr_t)
-							+ sizeof(dhcp_t))) {
-			if (debug >= 1) {
-			    printf("%s: Sent DHCP %s to %s\n",
-				np->fdp->device,
-				dhcptypename(type),
-				inet_ntoa(np->server));
-			    if (debug >= 2) printdhcp(bp->dhcp);
-			}
-		    }
-		}
-		put_buf(&bp);
-
-		/* When to continue querying a DHCP server? */
-		if (np->flags & NF_BOUND) {
-		    /* Still bound, keep halving time till next event. */
-		    time_t e, d;
-
-		    e= now < np->rebind ? np->rebind : np->lease;
-		    d= (e - now) / 2;
-		    if (d < DELTA_SLOW) d= DELTA_SLOW;
-		    np->renew= now + d;
-		    if (np->renew > e) np->renew= e;
-		} else {
-		    /* Not bound, be desparate. */
-		    np->renew= now + np->delta;
-		    if ((np->delta *= 2) > DELTA_FAST) np->delta= DELTA_FAST;
-		}
-	    }
-	    if (np->renew < event) event= np->renew;
-	}
-
-	/* Read DHCP responses. */
-	for (i= 0; i < n_nets; i++) {
-	    np= network[i];
-	    if (!(np->flags & NF_NEGOTIATING)) continue;
-
-	    if (!(np->flags & NF_BOUND)) {
-		if (!opendev(np, FT_ETHERNET, 0)) continue;
-		get_buf(&np->fdp->bp);
-		r= asyn_read(&asyn, np->fdp->fd, np->fdp->bp->eth,
-							BUF_ETH_SIZE);
-	    } else {
-		if (!opendev(np, FT_BOOTPC, 0)) continue;
-		get_buf(&np->fdp->bp);
-		r= asyn_read(&asyn, np->fdp->fd, np->fdp->bp->udpio,
-							BUF_UDP_SIZE);
-	    }
-	    if (r != -1) break;
-	    if (errno != ASYN_INPROGRESS && errno != EPACKSIZE) {
-		report(np->fdp->device);
-		sleep(10);
-	    }
-	}
-
-	/* Is there a response? */
-	if (i < n_nets) {
-	    give_buf(&bp, &np->fdp->bp);
-	    if (((!(np->flags & NF_BOUND)
-		    && r >= (sizeof(eth_hdr_t) + sizeof(ip_hdr_t)
-				+ sizeof(udp_hdr_t) + offsetof(dhcp_t, options))
-		    && ether2udp(bp)
-		    && bp->udpio->uih_dst_port == port_client)
-		  ||
-		  ((np->flags & NF_BOUND)
-		    && r >= sizeof(udp_io_hdr_t) + offsetof(dhcp_t, options)))
-		&& bp->dhcp->op == DHCP_BOOTREPLY
-		&& bp->dhcp->htype == DHCP_HTYPE_ETH
-		&& bp->dhcp->hlen == DHCP_HLEN_ETH
-		&& bp->dhcp->xid == XID(np)
-		&& memcmp(bp->dhcp->chaddr, &np->eth, sizeof(np->eth)) == 0
-	    ) {
-		/* Pfew!  We got a DHCP reply! */
-		u8_t *pdata;
-		size_t len;
-		int type;
-		ipaddr_t mask, gateway, relay, server;
-		u16_t mtu;
-		u32_t lease, renew, rebind, t;
-
-		relay= bp->udpio->uih_src_addr;
-		if (gettag(bp->dhcp, DHCP_TAG_SERVERID, &pdata, nil)) {
-		    memcpy(&server, pdata, sizeof(server));
-		} else {
-		    server= relay;
-		}
-
-		if (gettag(bp->dhcp, DHCP_TAG_TYPE, &pdata, nil)) {
-		    type= pdata[0];
-		} else {
-		    type= DHCP_ACK;	/* BOOTP? */
-		}
-
-		if (debug >= 1) {
-		    printf("%s: Got a DHCP %s from %s",
-			np->fdp->device, dhcptypename(type), inet_ntoa(server));
-		    printf(relay != server ? " through %s\n" : "\n",
-			inet_ntoa(relay));
-		    if (debug >= 2) printdhcp(bp->dhcp);
-		}
-
-		if (gettag(bp->dhcp, DHCP_TAG_NETMASK, &pdata, nil)) {
-		    memcpy(&mask, pdata, sizeof(mask));
-		} else {
-		    mask= defaultmask(bp->dhcp->ciaddr);
-		}
-
-		if (gettag(bp->dhcp, DHCP_TAG_IPMTU, &pdata, nil)) {
-		    memcpy(&mtu, pdata, sizeof(mtu));
-		    mtu= ntohs(mtu);
-		} else {
-		    mtu= 0;
-		}
-
-		if (gettag(bp->dhcp, DHCP_TAG_GATEWAY, &pdata, nil)) {
-		    memcpy(&gateway, pdata, sizeof(gateway));
-		} else {
-		    gateway= 0;
-		}
-
-		lease= NEVER;
-		if (gettag(bp->dhcp, DHCP_TAG_LEASE, &pdata, nil)) {
-		    memcpy(&lease, pdata, sizeof(lease));
-		    lease= ntohl(lease);
-		}
-
-		rebind= lease - lease / 8;
-		if (gettag(bp->dhcp, DHCP_TAG_REBINDING, &pdata, nil)) {
-		    memcpy(&t, pdata, sizeof(t));
-		    t= ntohl(t);
-		    if (t < rebind) rebind= t;
-		}
-
-		renew= lease / 2;
-		if (gettag(bp->dhcp, DHCP_TAG_RENEWAL, &pdata, nil)) {
-		    memcpy(&t, pdata, sizeof(t));
-		    t= ntohl(t);
-		    if (t < renew) renew= t;
-		}
-
-		if (type == DHCP_OFFER && np->rebind <= np->renew) {
-		    /* It's an offer for an address and we haven't taken one
-		     * yet.  It's all the same to us, so take this one.
-		     */
-		    np->ip= bp->dhcp->yiaddr;
-		    np->mask= mask;
-		    np->server= server;
-		    np->gateway= gateway;
-		    np->delta= DELTA_FIRST;
-		    np->renew= now;
-		    np->rebind= np->lease= now + DELTA_FAST;
-
-		    /* Send out an ARP request to see if the offered address
-		     * is in use already.
-		     */
-		    make_arp(bp, np);
-		    if (send(np, bp->eth, sizeof(arp46_t))) {
-			if (debug >= 2) {
-			    printf("Sent ARP for %s\n", inet_ntoa(np->ip));
-			}
-		    }
-		    np->flags &= ~NF_CONFLICT;
-		}
-
-		if (type == DHCP_ACK && !(np->flags & NF_CONFLICT)) {
-		    /* An acknowledgment.  The address is all mine. */
-		    cachedhcp(np->n, bp->dhcp);
-		    np->ip= bp->dhcp->yiaddr;
-		    np->mask= mask;
-		    np->server= server;
-		    set_ipconf(ipdev(np->n), np->ip, np->mask, mtu);
-		    if (debug >= 1) {
-			printf("%s: Address set to %s\n",
-			    ipdev(np->n), cidr_ntoa(np->ip, np->mask));
-		    }
-		    if (lease >= NEVER - now) {
-			/* The lease is infinite! */
-			np->renew= np->rebind= np->lease= NEVER;
-		    } else {
-			np->lease= now + lease;
-			np->renew= now + renew;
-			np->rebind= now + rebind;
-		    }
-		    if (test >= 3) {
-			np->renew= now + 60;
-			np->rebind= test >= 4 ? np->renew : np->renew + 60;
-			np->lease= test >= 5 ? np->rebind : np->rebind + 60;
-		    }
-		    if (!(np->flags & NF_IRDP)) {
-			np->sol_ct= (np->flags & NF_BOUND) ? 1 : N_SOLICITS;
-			np->solicit= 0;
-		    }
-		    np->flags &= ~NF_NEGOTIATING;
-		    np->flags |= NF_BOUND;
-		    closedev(np, FT_ETHERNET);
-		    closedev(np, FT_BOOTPC);
-		}
-
-		if (type == DHCP_ACK && (np->flags & NF_CONFLICT)) {
-		    /* Alas there is a conflict.  Decline to use the address. */
-		    u8_t ethclid[1+DHCP_HLEN_ETH];
-		    static char USED[]= "Address in use by 00:00:00:00:00:00";
-
-		    type= DHCP_DECLINE;
-		    dhcp_init(bp->dhcp);
-		    bp->dhcp->op= DHCP_BOOTREQUEST;
-		    bp->dhcp->htype= DHCP_HTYPE_ETH;
-		    bp->dhcp->hlen= DHCP_HLEN_ETH;
-		    bp->dhcp->xid= XID(np);
-		    bp->dhcp->secs= 0;
-		    memcpy(bp->dhcp->chaddr, &np->eth, sizeof(np->eth));
-		    settag(bp->dhcp, DHCP_TAG_REQIP, &np->ip, sizeof(np->ip));
-		    settag(bp->dhcp, DHCP_TAG_TYPE, &type, 1);
-		    ether2clid(ethclid, &np->eth);
-		    settag(bp->dhcp, DHCP_TAG_CLIENTID,ethclid,sizeof(ethclid));
-		    strcpy(USED+18, ether_ntoa(&np->conflict));
-		    settag(bp->dhcp, DHCP_TAG_MESSAGE, USED, strlen(USED));
-
-		    bp->udpio->uih_src_port= port_client;
-		    bp->udpio->uih_dst_port= port_server;
-		    bp->udpio->uih_ip_opt_len= 0;
-		    bp->udpio->uih_data_len= sizeof(dhcp_t);
-		    udp2ether(bp, np);
-
-		    if (send(np, bp->eth, sizeof(eth_hdr_t) + sizeof(ip_hdr_t)
-					+ sizeof(udp_hdr_t) + sizeof(dhcp_t))) {
-			if (debug >= 1) {
-			    printf("%s: Broadcast DHCP %s\n",
-				np->fdp->device, dhcptypename(type));
-			    if (debug >= 2) printdhcp(bp->dhcp);
-			}
-		    }
-		    
-		    np->renew= np->rebind= np->lease= now + DELTA_FAST;
-		    np->delta= DELTA_FIRST;
-		}
-
-		if (type == DHCP_NAK) {
-		    /* Oops, a DHCP server doesn't like me, start over! */
-		    np->renew= np->rebind= np->lease= now + DELTA_FAST;
-		    np->delta= DELTA_FIRST;
-
-		    fprintf(stderr, "%s: Got a NAK from %s",
-			program, inet_ntoa(server));
-		    if (relay != server) {
-			fprintf(stderr, " through %s", inet_ntoa(relay));
-		    }
-		    if (gettag(bp->dhcp, DHCP_TAG_MESSAGE, &pdata, &len)) {
-			fprintf(stderr, " saying: \"%.*s\"", (int)len, pdata);
-		    }
-		    fputc('\n', stderr);
-		}
-	    } else
-	    if (!(np->flags & NF_BOUND)
-		&& np->rebind > now
-		&& r >= sizeof(arp46_t)
-		&& is_arp_me(bp, np)
-	    ) {
-		/* Oh no, someone else is using the address offered to me! */
-		np->flags |= NF_CONFLICT;
-
-		fprintf(stderr, "%s: %s: %s offered by ",
-			program,
-			np->fdp->device,
-			inet_ntoa(np->ip));
-		fprintf(stderr, "%s is already in use by %s\n",
-			inet_ntoa(np->server),
-			ether_ntoa(&np->conflict));
-	    }
-	    put_buf(&bp);
-	    if (np->renew < event) event= np->renew;
-	}
-
-	/* Perform router solicitations. */
-	for (i= 0; i < n_nets; i++) {
-	    np= network[i];
-	    if (!(np->flags & NF_BOUND)) continue;
-
-	    if (np->solicit <= now) {
-		if (!opendev(np, FT_ICMP, 1)) continue;
-		np->solicit= NEVER;
-
-		get_buf(&bp);
-		if (np->gateway != 0) {
-		    /* No IRDP response seen yet, advertise the router given
-		     * by DHCP to my own interface.
-		     */
-		    icmp_advert(bp, np);
-		    if (send(np, bp->ip, sizeof(ip_hdr_t) + 16)) {
-			if (debug >= 2) {
-			    printf("%s: Sent advert for %s to self\n",
-				np->fdp->device, inet_ntoa(np->gateway));
-			}
-		    }
-		    np->solicit= now + DELTA_ADV/2;
-		}
-
-		if (np->sol_ct >= 0 && --np->sol_ct >= 0) {
-		    /* Send a router solicitation. */
-		    icmp_solicit(bp);
-		    if (send(np, bp->ip, sizeof(*bp->ip) + 8)) {
-			if (debug >= 2) {
-			    printf("%s: Broadcast router solicitation\n",
-				np->fdp->device);
-			}
-		    }
-		    np->solicit= now + DELTA_SOL;
-		} else {
-		    /* No response, or not soliciting right now. */
-		    closedev(np, FT_ICMP);
-		}
-
-		put_buf(&bp);
-	    }
-	    if (np->solicit < event) event= np->solicit;
-	}
-
-	/* Read router adverts. */
-	for (i= 0; i < n_nets; i++) {
-	    np= network[i];
-	    if (!(np->flags & NF_BOUND)) continue;
-	    if (np->sol_ct < 0) continue;
-
-	    if (!opendev(np, FT_ICMP, 0)) continue;
-	    get_buf(&np->fdp->bp);
-	    r= asyn_read(&asyn, np->fdp->fd, np->fdp->bp->ip, BUF_IP_SIZE);
-	    if (r != -1) break;
-	    if (errno != ASYN_INPROGRESS && errno != EPACKSIZE) {
-		report(np->fdp->device);
-		sleep(10);
-	    }
-	}
-
-	/* Is there an advert? */
-	if (i < n_nets && r >= sizeof(ip_hdr_t) + 8) {
-	    ipaddr_t router;
-
-	    give_buf(&bp, &np->fdp->bp);
-	    if ((router= icmp_is_advert(bp)) != 0) {
-		if (debug >= 2) {
-		    printf("%s: Router advert received from %s\n",
-			np->fdp->device, inet_ntoa(router));
-		}
-		np->solicit= NEVER;
-		np->sol_ct= -1;
-		np->flags |= NF_IRDP;
-		closedev(np, FT_ICMP);
-	    }
-	    put_buf(&bp);
-	}
-
-	/* We start serving if all the interfaces so marked are configured. */
-	for (i= 0; i < n_nets; i++) {
-	    np= network[i];
-	    if ((np->flags & NF_RELAYING) && (np->flags & NF_BOUND)) {
-		if (((np->ip ^ np->server) & np->mask) == 0) {
-		    /* Don't relay to a server that is on this same net. */
-		    np->flags &= ~NF_RELAYING;
-		}
-	    }
-	    if (!(np->flags & (NF_SERVING|NF_RELAYING))) continue;
-	    if (!(np->flags & NF_BOUND)) { serving= 0; break; }
-	    serving= 1;
-	}
-
-	/* Read DHCP requests. */
-	for (i= 0; i < n_nets; i++) {
-	    np= network[i];
-	    if (!(np->flags & NF_BOUND)) continue;
-	    if (!(np->flags & (NF_SERVING|NF_RELAYING)) || !serving) continue;
-
-	    if (!opendev(np, FT_BOOTPS, 0)) continue;
-	    get_buf(&np->fdp->bp);
-	    r= asyn_read(&asyn, np->fdp->fd, np->fdp->bp->udpio, BUF_UDP_SIZE);
-
-	    if (r != -1) break;
-	    if (errno != ASYN_INPROGRESS && errno != EPACKSIZE) {
-		report(np->fdp->device);
-		sleep(10);
-	    }
-	}
-
-	/* Is there a request? */
-	if (i < n_nets
-	    && r >= sizeof(udp_io_hdr_t) + offsetof(dhcp_t, options)
-	) {
-	    give_buf(&bp, &np->fdp->bp);
-
-	    if (debug >= 1) {
-		printf("%s: Got DHCP packet from %s to ",
-		    np->fdp->device, inet_ntoa(bp->udpio->uih_src_addr));
-		printf("%s\n", inet_ntoa(bp->udpio->uih_dst_addr));
-		if (debug >= 2) printdhcp(bp->dhcp);
-	    }
-
-	    /* Can we do something with this DHCP packet? */
-	    if ((r= servdhcp(np, bp, r)) > 0) {
-		/* Yes, we have something to send somewhere. */
-		if (send(np, bp->udpio, r)) {
-		    if (debug >= 1) {
-			printf("%s: Sent DHCP packet to %s\n",
-			    np->fdp->device,
-			    inet_ntoa(bp->udpio->uih_dst_addr));
-			if (debug >= 2) printdhcp(bp->dhcp);
-		    }
-		}
-	    }
-	    put_buf(&bp);
-	}
-
-	if (debug >= 1) {
-	    static char *lastbrk;
-	    extern char _end;
-
-	    if (sbrk(0) != lastbrk) {
-		lastbrk= sbrk(0);
-		printf("Memory use = %lu\n",
-		    (unsigned long) (lastbrk - &_end));
-	    }
-	    fflush(stdout);
-	}
-
-	/* Bail out if not a server, and there is nothing else to do ever. */
-	if (!serving && event == NEVER) break;
-
-	/* Wait for something to do. */
-	eventtv.tv_sec= event;
-	if (asyn_wait(&asyn, 0, event == NEVER ? nil : &eventtv) < 0) {
-	    if (errno != EINTR) {
-		report("asyn_wait()");
-		sleep(10);
-	    }
-	}
-    }
-    if (debug >= 1) printf("Nothing more to do! Bailing out...\n");
-    return 0;
-}
Index: trunk/minix/commands/dhcpd/dhcpd.h
===================================================================
--- trunk/minix/commands/dhcpd/dhcpd.h	(revision 9)
+++ 	(revision )
@@ -1,159 +1,0 @@
-/*	dhcpd.h - Dynamic Host Configuration Protocol daemon.
- *							Author: Kees J. Bot
- *								16 Dec 2000
- */
-
-#define nil ((void*)0)
-
-#include <minix/paths.h>
-
-/* Paths to files. */
-#define PATH_DHCPCONF	_PATH_DHCPCONF
-#define PATH_DHCPPID	_PATH_DHCPPID
-#define PATH_DHCPCACHE	_PATH_DHCPCACHE
-#define PATH_DHCPPOOL	_PATH_DHCPPOOL
-
-#define CLID_MAX	32	/* Maximum client ID length. */
-
-#ifndef EXTERN
-#define EXTERN	extern
-#endif
-
-EXTERN char *program;		/* This program's name. */
-extern char *configfile;	/* Configuration file. */
-extern char *poolfile;		/* Dynamic address pool. */
-EXTERN int serving;		/* True if being a DHCP server. */
-EXTERN unsigned test;		/* Test level. */
-EXTERN unsigned debug;		/* Debug level. */
-EXTERN asynchio_t asyn;		/* Bookkeeping for all async I/O. */
-
-/* BOOTP UDP ports:  (That they are different is quite stupid.) */
-EXTERN u16_t port_server;	/* Port server listens on. */
-EXTERN u16_t port_client;	/* Port client listens on. */
-
-#define arraysize(a)	(sizeof(a) / sizeof((a)[0]))
-#define arraylimit(a)	((a) + arraysize(a))
-#define between(a,c,z)	(sizeof(c) <= sizeof(unsigned) ? \
-	(unsigned) (c) - (a) <= (unsigned) (z) - (a) : \
-	(unsigned long) (c) - (a) <= (unsigned long) (z) - (a))
-
-/* To treat objects as octet arrays: */
-#define B(a)		((u8_t *) (a))
-
-/* Times. */
-EXTERN time_t start, now;		/* Start and current time. */
-EXTERN time_t event;			/* Time of the next timed event. */
-
-/* Special times and periods: */
-#define NEVER	(sizeof(time_t) <= sizeof(int) ? INT_MAX : LONG_MAX)
-#define DELTA_FIRST		   4	/* Between first and second query. */
-#define DELTA_FAST		  64	/* Unbound queries this often. */
-#define DELTA_SLOW		 512	/* Bound queries are more relaxed. */
-#define N_SOLICITS		   3	/* Number of solicitations. */
-#define DELTA_SOL		   3	/* Time between solicitations. */
-#define DELTA_ADV		2048	/* Router adverts to self lifetime. */
-
-/* Buffers for packets. */
-typedef struct buf {
-	eth_hdr_t	*eth;		/* Ethernet header in payload. */
-	ip_hdr_t	*ip;		/* IP header in payload. */
-	udp_hdr_t	*udp;		/* UDP header in payload. */
-	udp_io_hdr_t	*udpio;		/* UDP I/O header in payload. */
-	dhcp_t		*dhcp;		/* DHCP data in payload. */
-	u8_t		pad[2];		/* buf[] must start at 2 mod 4. */
-					/* Payload: */
-	u8_t		buf[ETH_MAX_PACK_SIZE];
-} buf_t;
-
-#define BUF_ETH_SIZE	(ETH_MAX_PACK_SIZE)
-#define BUF_IP_SIZE	(BUF_ETH_SIZE - sizeof(eth_hdr_t))
-#define BUF_UDP_SIZE	(BUF_IP_SIZE - sizeof(ip_hdr_t) - sizeof(udp_hdr_t) \
-				+ sizeof(udp_io_hdr_t))
-
-/* Type of network device open: Ethernet, ICMP, BOOTP client, BOOTP server. */
-typedef enum { FT_CLOSED, FT_ETHERNET, FT_ICMP, FT_BOOTPC, FT_BOOTPS } fdtype_t;
-
-#define FT_ALL	FT_CLOSED	/* To close all open descriptors at once. */
-
-typedef struct fd {		/* An open descriptor. */
-	i8_t		fd;		/* Open descriptor. */
-	u8_t		fdtype;		/* Type of network open. */
-	char		device[sizeof("/dev/eth###")];	/* Device name. */
-	u8_t		n;		/* Network that owns it. */
-	buf_t		*bp;		/* Associated packet buffer. */
-	time_t		since;		/* Open since when? */
-} fd_t;
-
-/* Network state: Any IP device, Ethernet in sink mode, True Ethernet. */
-typedef enum { NT_IP, NT_SINK, NT_ETHERNET } nettype_t;
-
-typedef struct network {	/* Information on a network. */
-	u8_t		n;		/* Network number. */
-	ether_addr_t	eth;		/* Ethernet address of this net. */
-	u8_t		type;		/* What kind of net is this? */
-	i8_t		sol_ct;		/* Router solicitation count. */
-	ether_addr_t	conflict;	/* Address conflict with this one. */
-	unsigned	flags;		/* Various flags. */
-	fd_t		*fdp;		/* Current open device. */
-	struct network	*wait;		/* Wait for a resource list. */
-	ipaddr_t	ip;		/* IP address of this net. */
-	ipaddr_t	mask;		/* Associated netmask. */
-	ipaddr_t	gateway;	/* My router. */
-	ipaddr_t	server;		/* My DHCP server. */
-	const char	*hostname;	/* Optional hostname to query for. */
-	time_t		start;		/* Query or lease start time. */
-	time_t		delta;		/* Query again after delta seconds. */
-	time_t		renew;		/* Next query or go into renewal. */
-	time_t		rebind;		/* When to go into rebind. */
-	time_t		lease;		/* When our lease expires. */
-	time_t		solicit;	/* Time to do a router solicitation. */
-} network_t;
-
-/* Flags. */
-#define NF_NEGOTIATING	0x001		/* Negotiating with a DHCP server. */
-#define NF_BOUND	0x002		/* Address configured through DHCP. */
-#define NF_SERVING	0x004		/* I'm a server on this network. */
-#define NF_RELAYING	0x008		/* I'm relaying for this network. */
-#define NF_WAIT		0x010		/* Wait for a resource to free up. */
-#define NF_IRDP		0x020		/* IRDP is used on this net. */
-#define NF_CONFLICT	0x040		/* There is an address conflict. */
-#define NF_POSSESSIVE	0x080		/* Keep address if lease expires. */
-#define NF_INFORM	0x100		/* It's ok to answer DHCPINFORM. */
-
-/* Functions defined in dhcpd.c. */
-void report(const char *label);
-void fatal(const char *label);
-void *allocate(size_t size);
-int ifname2if(const char *name);
-network_t *if2net(int n);
-
-/* Devices.c */
-void get_buf(buf_t **bp);
-void put_buf(buf_t **bp);
-void give_buf(buf_t **dbp, buf_t **sbp);
-network_t *newnetwork(void);
-void closefd(fd_t *fdp);
-int opendev(network_t *np, fdtype_t fdtype, int compete);
-void closedev(network_t *np, fdtype_t fdtype);
-char *ipdev(int n);
-void set_ipconf(char *device, ipaddr_t ip, ipaddr_t mask, unsigned mtu);
-
-/* Ether.c */
-void udp2ether(buf_t *bp, network_t *np);
-int ether2udp(buf_t *bp);
-void make_arp(buf_t *bp, network_t *np);
-int is_arp_me(buf_t *bp, network_t *np);
-void icmp_solicit(buf_t *bp);
-void icmp_advert(buf_t *bp, network_t *np);
-ipaddr_t icmp_is_advert(buf_t *bp);
-
-/* Tags.c */
-#define gettag(dp, st, pd, pl)	dhcp_gettag((dp), (st), (pd), (pl))
-void settag(dhcp_t *dp, int tag, void *data, size_t len);
-char *cidr_ntoa(ipaddr_t addr, ipaddr_t mask);
-void ether2clid(u8_t *clid, ether_addr_t *eth);
-void initdhcpconf(void);
-int makedhcp(dhcp_t *dp, u8_t *class, size_t calen, u8_t *client, size_t cilen,
-				ipaddr_t ip, ipaddr_t ifip, network_t *np);
-char *dhcptypename(int type);
-void printdhcp(dhcp_t *dp);
Index: trunk/minix/commands/dhcpd/ether.c
===================================================================
--- trunk/minix/commands/dhcpd/ether.c	(revision 9)
+++ 	(revision )
@@ -1,203 +1,0 @@
-/*	ether.c - Raw Ethernet stuff
- *							Author: Kees J. Bot
- *								16 Dec 2000
- */
-#include <sys/types.h>
-#include <fcntl.h>
-#include <string.h>
-#include <sys/asynchio.h>
-#include <net/hton.h>
-#include <net/gen/in.h>
-#include <net/gen/ether.h>
-#include <net/gen/eth_hdr.h>
-#include <net/gen/ip_hdr.h>
-#include <net/gen/icmp.h>
-#include <net/gen/icmp_hdr.h>
-#include <net/gen/oneCsum.h>
-#include <net/gen/udp.h>
-#include <net/gen/udp_hdr.h>
-#include <net/gen/dhcp.h>
-#include "arp.h"
-#include "dhcpd.h"
-
-static ether_addr_t BCAST_ETH =	{{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }};
-#define BCAST_IP	HTONL(0xFFFFFFFFUL)
-#define LOCALHOST	HTONL(0x7F000001UL)
-
-static u16_t udp_cksum(ipaddr_t src, ipaddr_t dst, udp_hdr_t *udp)
-{
-    /* Compute the checksum of an UDP packet plus data. */
-    struct udp_pseudo {
-	ipaddr_t	src, dst;
-	u8_t		zero, proto;
-	u16_t		length;
-    } pseudo;
-    size_t len;
-
-    /* Fill in the UDP pseudo header that must be prefixed to the UDP
-     * packet to compute the checksum of the whole thing.
-     */
-    pseudo.src= src;
-    pseudo.dst= dst;
-    pseudo.zero= 0;
-    pseudo.proto= IPPROTO_UDP;
-    pseudo.length= udp->uh_length;
-
-    len= ntohs(udp->uh_length);
-    if (len & 1) {
-	/* Length is odd?  Pad with a zero. */
-	B(udp)[len++]= 0;
-    }
-    return oneC_sum(oneC_sum(0, &pseudo, sizeof(pseudo)), udp, len);
-}
-
-void udp2ether(buf_t *bp, network_t *np)
-{
-    /* Transform a packet in UDP format to raw Ethernet.  Ignore the UDP
-     * addresses, always broadcast from 0.0.0.0.
-     */
-    udp_io_hdr_t udpio;
-
-    /* Save the UDP I/O header. */
-    udpio= *bp->udpio;
-
-    /* Fill in the Ethernet, IP and UDP headers. */
-    bp->eth->eh_dst= BCAST_ETH;
-    bp->eth->eh_src= np->eth;
-    bp->eth->eh_proto= HTONS(ETH_IP_PROTO);
-    bp->ip->ih_vers_ihl= 0x45;
-    bp->ip->ih_tos= 0;
-    bp->ip->ih_length= htons(sizeof(ip_hdr_t)
-			+ sizeof(udp_hdr_t) + udpio.uih_data_len);
-    bp->ip->ih_id= 0;
-    bp->ip->ih_flags_fragoff= NTOHS(0x4000);
-    bp->ip->ih_ttl= IP_MAX_TTL;
-    bp->ip->ih_proto= IPPROTO_UDP;
-    bp->ip->ih_hdr_chk= 0;
-    bp->ip->ih_src= 0;
-    bp->ip->ih_dst= BCAST_IP;
-    bp->ip->ih_hdr_chk= ~oneC_sum(0, bp->ip, sizeof(*bp->ip));
-    bp->udp->uh_src_port= udpio.uih_src_port;
-    bp->udp->uh_dst_port= udpio.uih_dst_port;
-    bp->udp->uh_length= htons(sizeof(udp_hdr_t) + udpio.uih_data_len);
-    bp->udp->uh_chksum= 0;
-    bp->udp->uh_chksum= ~udp_cksum(bp->ip->ih_src, bp->ip->ih_dst, bp->udp);
-}
-
-int ether2udp(buf_t *bp)
-{
-    /* Transform an UDP packet read from raw Ethernet to normal UDP.
-     * Return true iff the packet is indeed UDP and has no errors.
-     */
-    udp_io_hdr_t udpio;
-
-    if (bp->eth->eh_proto != HTONS(ETH_IP_PROTO)
-	|| bp->ip->ih_vers_ihl != 0x45
-	|| bp->ip->ih_proto != IPPROTO_UDP
-	|| oneC_sum(0, bp->ip, 20) != (u16_t) ~0
-	|| udp_cksum(bp->ip->ih_src, bp->ip->ih_dst, bp->udp) != (u16_t) ~0
-    ) {
-	/* Not UDP/IP or checksums bad. */
-	return 0;
-    }
-    udpio.uih_src_addr= bp->ip->ih_src;
-    udpio.uih_dst_addr= bp->ip->ih_dst;
-    udpio.uih_src_port= bp->udp->uh_src_port;
-    udpio.uih_dst_port= bp->udp->uh_dst_port;
-    udpio.uih_ip_opt_len= 0;
-    udpio.uih_data_len= ntohs(bp->udp->uh_length) - sizeof(udp_hdr_t);
-    *bp->udpio= udpio;
-    return 1;
-}
-
-void make_arp(buf_t *bp, network_t *np)
-{
-    /* Create an ARP packet to query for my IP address. */
-    arp46_t *arp= (arp46_t *) bp->eth;
-
-    memset(arp, 0, sizeof(*arp));
-    arp->dstaddr= BCAST_ETH;
-    arp->srcaddr= np->eth;
-    arp->ethtype= HTONS(ETH_ARP_PROTO);
-    arp->hdr= HTONS(ARP_ETHERNET);
-    arp->pro= HTONS(ETH_IP_PROTO);
-    arp->hln= 6;
-    arp->pln= 4;
-    arp->op= HTONS(ARP_REQUEST);
-    arp->sha= np->eth;
-    memcpy(arp->spa, &np->ip, sizeof(np->ip));
-    memcpy(arp->tpa, &np->ip, sizeof(np->ip));
-}
-
-int is_arp_me(buf_t *bp, network_t *np)
-{
-    /* True iff an ARP packet is a reply from someone else with an address I
-     * thought was mine.  (That's like, bad.)
-     */
-    arp46_t *arp= (arp46_t *) bp->eth;
-
-    if (arp->ethtype == HTONS(ETH_ARP_PROTO)
-	&& arp->hdr == HTONS(ARP_ETHERNET)
-	&& arp->pro == HTONS(ETH_IP_PROTO)
-	&& arp->op == HTONS(ARP_REPLY)
-	&& memcmp(&arp->spa, &np->ip, sizeof(np->ip)) == 0
-	&& memcmp(&arp->sha, &np->eth, sizeof(np->eth)) != 0
-    ) {
-	np->conflict= arp->sha;
-	return 1;
-    }
-    return 0;
-}
-
-void icmp_solicit(buf_t *bp)
-{
-    /* Fill in a router solicitation ICMP packet. */
-    icmp_hdr_t *icmp= (icmp_hdr_t *) (bp->ip + 1);
-
-    bp->ip->ih_vers_ihl= 0x45;
-    bp->ip->ih_dst= BCAST_IP;
-
-    icmp->ih_type= ICMP_TYPE_ROUTE_SOL;
-    icmp->ih_code= 0;
-    icmp->ih_hun.ihh_unused= 0;
-    icmp->ih_chksum= 0;
-    icmp->ih_chksum= ~oneC_sum(0, icmp, 8);
-}
-
-void icmp_advert(buf_t *bp, network_t *np)
-{
-    /* Fill in a router advert to be sent to my own interface. */
-    icmp_hdr_t *icmp= (icmp_hdr_t *) (bp->ip + 1);
-
-    bp->ip->ih_vers_ihl= 0x45;
-    bp->ip->ih_dst= LOCALHOST;
-
-    icmp->ih_type= ICMP_TYPE_ROUTER_ADVER;
-    icmp->ih_code= 0;
-    icmp->ih_hun.ihh_ram.iram_na= 1;
-    icmp->ih_hun.ihh_ram.iram_aes= 2;
-    icmp->ih_hun.ihh_ram.iram_lt= htons(DELTA_ADV);
-    ((u32_t *) icmp->ih_dun.uhd_data)[0] = np->gateway;
-    ((u32_t *) icmp->ih_dun.uhd_data)[1] = HTONL((u32_t) -9999);
-    icmp->ih_chksum= 0;
-    icmp->ih_chksum= ~oneC_sum(0, icmp, 16);
-}
-
-ipaddr_t icmp_is_advert(buf_t *bp)
-{
-    /* Check if an IP packet is a router advertisement, and if it's genuine,
-     * i.e. the sender is mentioned in the packet.
-     */
-    icmp_hdr_t *icmp= (icmp_hdr_t *) (bp->ip + 1);
-    int i;
-
-    if (icmp->ih_type == ICMP_TYPE_ROUTER_ADVER) {
-	for (i= 0; i < icmp->ih_hun.ihh_ram.iram_na; i++) {
-	    if (((u32_t *) icmp->ih_dun.uhd_data)[2*i] == bp->ip->ih_src) {
-		/* It's a router! */
-		return bp->ip->ih_src;
-	    }
-	}
-    }
-    return 0;
-}
Index: trunk/minix/commands/dhcpd/tags.c
===================================================================
--- trunk/minix/commands/dhcpd/tags.c	(revision 9)
+++ 	(revision )
@@ -1,924 +1,0 @@
-/*	tags.c - Obtain DHCP tags from the config file
- *							Author: Kees J. Bot
- *								16 Dec 2000
- */
-#include <sys/types.h>
-#include <stdio.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <signal.h>
-#include <string.h>
-#include <time.h>
-#include <limits.h>
-#include <configfile.h>
-#include <sys/ioctl.h>
-#include <sys/asynchio.h>
-#include <net/hton.h>
-#include <net/gen/socket.h>
-#include <net/gen/netdb.h>
-#include <net/gen/in.h>
-#include <net/gen/inet.h>
-#include <net/gen/ether.h>
-#include <net/gen/if_ether.h>
-#include <net/gen/eth_hdr.h>
-#include <net/gen/ip_hdr.h>
-#include <net/gen/udp.h>
-#include <net/gen/udp_hdr.h>
-#include <net/gen/dhcp.h>
-#include "dhcpd.h"
-
-#define doff(field)		offsetof(dhcp_t, field)
-
-void settag(dhcp_t *dp, int tag, void *data, size_t len)
-{
-    if (!dhcp_settag(dp, tag, data, len)) {
-	/* Oops, it didn't fit?  Is this really Minix??? */
-	fprintf(stderr,
-	    "%s: DHCP packet too big, please trim the configuration\n",
-	    program);
-	exit(1);
-    }
-}
-
-static int name2ip(ipaddr_t *pip, const char *name, ipaddr_t ifip)
-{
-    /* Translate a name to an IP address, preferably from the hosts file,
-     * but also from the DNS if being a server.  Prefer the address closest
-     * to the interface with IP address 'ifip' if there are choices..
-     */
-    extern struct hostent *_gethostent(void);	/* File reading versions. */
-    extern void _endhostent(void);
-    struct hostent *he;
-    size_t len= strlen(name);
-    u32_t d, distance= -1;
-    ipaddr_t ip;
-    int i;
-    char *hn;
-
-    /* Already an IP address? */
-    if (inet_aton(name, pip)) return 1;
-
-    /* In the hosts file? */
-    while ((he= _gethostent()) != nil) {
-	hn= he->h_name;
-	i= -1;
-	do {
-	    if (strncasecmp(name, hn, len) == 0
-		&& (hn[len] == 0 || hn[len] == '.')
-	    ) {
-		memcpy(&ip, he->h_addr, sizeof(ip));
-		d= ntohl(ip) ^ ntohl(ifip);
-		if (d < distance) {
-		    *pip= ip;
-		    distance= d;
-		}
-		break;
-	    }
-	} while ((hn= he->h_aliases[++i]) != nil);
-    }
-    _endhostent();
-    if (distance < -1) return 1;
-
-    /* Nothing?  Try the real DNS if being a server. */
-    if (serving) {
-	if ((he= gethostbyname(name)) != nil && he->h_addrtype == AF_INET) {
-	    /* Select the address closest to 'ifip'. */
-	    for (i= 0; he->h_addr_list[i] != nil; i++) {
-		memcpy(&ip, he->h_addr_list[i], sizeof(ip));
-		d= ntohl(ip) ^ ntohl(ifip);
-		if (d < distance) {
-		    *pip= ip;
-		    distance= d;
-		}
-	    }
-	    return 1;
-	}
-    }
-    return 0;
-}
-
-static char *ip2name(ipaddr_t ip)
-{
-    /* Translate an IP address to a name, etc, etc. */
-    extern struct hostent *_gethostent(void);	/* File reading versions. */
-    extern void _endhostent(void);
-    struct hostent *he;
-
-    /* In the hosts file? */
-    while ((he= _gethostent()) != nil) {
-	if (memcmp(he->h_addr, &ip, sizeof(ip)) == 0) break;
-    }
-    _endhostent();
-
-    /* Nothing?  Try the real DNS if being a server. */
-    if (he == nil && serving) {
-	he= gethostbyaddr((char *) &ip, sizeof(ip), AF_INET);
-    }
-    return he != nil ? he->h_name : nil;
-}
-
-static int cidr_aton(const char *cidr, ipaddr_t *addr, ipaddr_t *mask)
-{
-    char *slash, *check;
-    ipaddr_t a;
-    int ok;
-    unsigned long len;
-
-    if ((slash= strchr(cidr, '/')) == nil) return 0;
-
-    *slash++= 0;
-    ok= inet_aton(cidr, &a);
-
-    len= strtoul(slash, &check, 10);
-    if (check == slash || *check != 0 || len > 32) ok= 0;
-
-    *--slash= '/';
-    if (!ok) return 0;
-    *addr= a;
-    *mask= htonl(len == 0 ? 0 : (0xFFFFFFFFUL << (32-len)) & 0xFFFFFFFFUL);
-    return 1;
-}
-
-char *cidr_ntoa(ipaddr_t addr, ipaddr_t mask)
-{
-    ipaddr_t testmask= 0xFFFFFFFFUL;
-    int n;
-    static char result[sizeof("255.255.255.255/255.255.255.255")];
-
-    for (n= 32; n >= 0; n--) {
-	if (mask == htonl(testmask)) break;
-	testmask= (testmask << 1) & 0xFFFFFFFFUL;
-    }
-
-    sprintf(result, "%s/%-2d", inet_ntoa(addr), n);
-    if (n == -1) strcpy(strchr(result, '/')+1, inet_ntoa(mask));
-    return result;
-}
-
-static size_t ascii2octet(u8_t *b, size_t size, const char *a)
-{
-    /* Convert a series of hex digit pairs to an octet (binary) array at
-     * 'b' with length 'size'.  Return the number of octets in 'a' or
-     * -1 on error.
-     */
-    size_t len;
-    int n, c;
-
-    len= 0;
-    n= 0;
-    while ((c= *a++) != 0) {
-	if (between('0', c, '9')) c= (c - '0') + 0x0;
-	else
-	if (between('a', c, 'f')) c= (c - 'a') + 0xa;
-	else
-	if (between('A', c, 'F')) c= (c - 'A') + 0xA;
-	else {
-	    return -1;
-	}
-
-	if (n == 0) {
-	    if (len < size) b[len] = c << 4;
-	} else {
-	    if (len < size) b[len] |= c;
-	    len++;
-	}
-	n ^= 1;
-    }
-    return n == 0 ? len : -1;
-}
-
-void ether2clid(u8_t *clid, ether_addr_t *eth)
-{
-    /* Convert an Ethernet address to the default client ID form. */
-    clid[0]= DHCP_HTYPE_ETH;
-    memcpy(clid+1, eth, DHCP_HLEN_ETH);
-}
-
-static size_t ascii2clid(u8_t *clid, const char *a)
-{
-    /* Convert an ethernet address, or a series of hex digits to a client ID.
-     * Return its length if ok, otherwise -1.
-     */
-    size_t len;
-    ether_addr_t *eth;
-
-    if ((eth= ether_aton(a)) != nil) {
-	ether2clid(clid, eth);
-	len= 1+DHCP_HLEN_ETH;
-    } else {
-	len= ascii2octet(clid, CLID_MAX, a);
-    }
-    return len;
-}
-
-static config_t *dhcpconf;		/* In-core DHCP configuration. */
-
-/* DHCP tag types. */
-typedef enum { TT_ASCII, TT_BOOLEAN, TT_IP, TT_NUMBER, TT_OCTET } tagtype_t;
-
-/* DHCP/BOOTP tag definitions. */
-typedef struct tagdef {
-	u8_t		tag;		/* Tag number. */
-	u8_t		type;		/* Type and flags. */
-	u8_t		gran;		/* Granularity. */
-	u8_t		max;		/* Maximum number of arguments. */
-	const char	*name;		/* Defined name. */
-} tagdef_t;
-
-#define TF_TYPE		0x07		/* To mask out the type. */
-#define TF_STATIC	0x08		/* "Static", i.e. a struct field. */
-#define TF_RO		0x10		/* Read-only, user can't set. */
-
-/* List of static DHCP fields.  The tag field is misused here as an offset
- * into the DHCP structure.
- */
-static tagdef_t statictag[] = {
-    { doff(op),     TT_NUMBER|TF_STATIC|TF_RO,	1,   1,	"op"		},
-    { doff(htype),  TT_NUMBER|TF_STATIC|TF_RO,	1,   1,	"htype"		},
-    { doff(hlen),   TT_NUMBER|TF_STATIC|TF_RO,	1,   1,	"hlen"		},
-    { doff(hops),   TT_NUMBER|TF_STATIC|TF_RO,	1,   1,	"hops"		},
-    { doff(xid),    TT_NUMBER|TF_STATIC|TF_RO,	4,   1,	"xid"		},
-    { doff(secs),   TT_NUMBER|TF_STATIC|TF_RO,	2,   1,	"secs"		},
-    { doff(flags),  TT_NUMBER|TF_STATIC|TF_RO,	2,   1,	"flags"		},
-    { doff(ciaddr), TT_IP|TF_STATIC|TF_RO,	1,   1,	"ciaddr"	},
-    { doff(yiaddr), TT_IP|TF_STATIC|TF_RO,	1,   1,	"yiaddr"	},
-    { doff(siaddr), TT_IP|TF_STATIC,		1,   1,	"siaddr"	},
-    { doff(giaddr), TT_IP|TF_STATIC|TF_RO,	1,   1,	"giaddr"	},
-    { doff(chaddr), TT_OCTET|TF_STATIC|TF_RO,	1,  16,	"chaddr"	},
-    { doff(sname),  TT_ASCII|TF_STATIC,		1,  64,	"sname"		},
-    { doff(file),   TT_ASCII|TF_STATIC,		1, 128,	"file"		},
-};
-#define N_STATIC	arraysize(statictag)
-
-static tagdef_t alltagdef[N_STATIC + 254];	/* List of tag definitions. */
-#define tagdef	(alltagdef+N_STATIC-1)		/* Just the optional ones. */
-
-#define tagdefined(tp)		((tp)->name != nil)
-
-static void inittagdef(void)
-{
-    /* Initialize the tag definitions from the "tag" commands in the config
-     * file.
-     */
-    int t;
-    tagdef_t *tp;
-    static tagdef_t predef[] = {
-	{ DHCP_TAG_NETMASK,	TT_IP,	   1,	  1,	"netmask"	},
-	{ DHCP_TAG_GATEWAY,	TT_IP,	   1,	255,	"gateway"	},
-	{ DHCP_TAG_DNS,		TT_IP,	   1,	255,	"DNSserver"	},
-    };
-    static char *typenames[] = { "ascii", "boolean", "ip", "number", "octet" };
-    config_t *cfg;
-    static u8_t rotags[] = {
-	DHCP_TAG_REQIP, DHCP_TAG_OVERLOAD, DHCP_TAG_TYPE, DHCP_TAG_SERVERID,
-	DHCP_TAG_REQPAR, DHCP_TAG_MESSAGE, DHCP_TAG_MAXDHCP
-    };
-
-    for (t= 1; t <= 254; t++) {
-	tp= &tagdef[t];
-	tp->tag= t;
-	tp->type= TT_OCTET;
-	tp->name= nil;
-    }
-
-    /* Set the static and "all Minix needs" tags. */
-    memcpy(alltagdef, statictag, sizeof(statictag));
-    for (tp= predef; tp < arraylimit(predef); tp++) tagdef[tp->tag] = *tp;
-
-    /* Search for tag definitions in the config file. */
-    for (cfg= dhcpconf; cfg != nil; cfg= cfg->next) {
-	config_t *cmd= cfg->list;
-
-	if (strcasecmp(cmd->word, "tag") == 0) {
-	    if (config_length(cmd) == 6
-		&& (cmd->next->flags & CFG_DULONG)
-		&& config_isatom(cmd->next->next)
-		&& config_isatom(cmd->next->next->next)
-		&& (cmd->next->next->next->next->flags & CFG_DULONG)
-		&& (cmd->next->next->next->next->next->flags & CFG_DULONG)
-	    ) {
-		unsigned long tag, gran, max;
-		const char *name, *typename;
-		unsigned type;
-
-		tag= strtoul(cmd->next->word, nil, 10);
-		name= cmd->next->next->word;
-		typename= cmd->next->next->next->word;
-		gran= strtoul(cmd->next->next->next->next->word, nil, 10);
-		max= strtoul(cmd->next->next->next->next->next->word, nil, 10);
-
-		for (type= 0; type < arraysize(typenames); type++) {
-		    if (strcasecmp(typename, typenames[type]) == 0) break;
-		}
-
-		if (!(1 <= tag && tag <= 254)
-		    || !(type < arraysize(typenames))
-		    || !((type == TT_NUMBER
-			    && (gran == 1 || gran == 2 || gran == 4))
-			|| (type != TT_NUMBER && 1 <= gran && gran <= 16))
-		    || !(max <= 255)
-		) {
-		    fprintf(stderr,
-			"\"%s\", line %u: Tag definition is incorrect\n",
-			cmd->file, cmd->line);
-		    exit(1);
-		}
-
-		tp= &tagdef[(int)tag];
-		tp->type= type;
-		tp->name= name;
-		tp->gran= gran;
-		tp->max= max;
-	    } else {
-		fprintf(stderr,
-	    "\"%s\", line %u: Usage: tag number name type granularity max\n",
-		    cmd->file, cmd->line);
-		exit(1);
-	    }
-	}
-    }
-
-    /* Many DHCP tags are not for the user to play with. */
-    for (t= 0; t < arraysize(rotags); t++) tagdef[rotags[t]].type |= TF_RO;
-}
-
-static tagdef_t *tagdefbyname(const char *name)
-{
-    /* Find a tag definition by the name of the tag.  Return null if not
-     * defined.
-     */
-    tagdef_t *tp;
-
-    for (tp= alltagdef; tp < arraylimit(alltagdef); tp++) {
-	if (tagdefined(tp) && strcasecmp(tp->name, name) == 0) return tp;
-    }
-    return nil;
-}
-
-void initdhcpconf(void)
-{
-    /* Read/refresh configuration from the DHCP configuration file. */
-    dhcpconf= config_read(configfile, 0, dhcpconf);
-    if (config_renewed(dhcpconf)) inittagdef();
-}
-
-static void configtag(dhcp_t *dp, config_t *cmd, ipaddr_t ifip)
-{
-    /* Add a tag to a DHCP packet from the config file. */
-    tagdef_t *tp;
-    u8_t data[260], *d;
-    size_t i;
-    int delete= 0;
-
-    if (strcasecmp(cmd->word, "no") == 0) {
-	if (config_length(cmd) != 2 || !config_isatom(cmd->next)) {
-	    fprintf(stderr, "\"%s\", line %u: Usage: no tag-name\n",
-		cmd->file, cmd->line);
-	    exit(1);
-	}
-	cmd= cmd->next;
-	delete= 1;
-    }
-
-    if ((tp= tagdefbyname(cmd->word)) == nil) {
-	fprintf(stderr, "\"%s\", line %u: Unknown tag '%s'\n",
-	    cmd->file, cmd->line, cmd->word);
-	exit(1);
-    }
-
-    if (tp->type & TF_RO) {
-	fprintf(stderr, "\"%s\", line %u: Tag '%s' can't be configured\n",
-	    cmd->file, cmd->line, cmd->word);
-	exit(1);
-    }
-
-    i= 0;
-    d= data;
-    if (!delete) {
-	config_t *arg= cmd->next;
-	do {
-	    switch (tp->type & TF_TYPE) {
-	    case TT_ASCII: {
-		if (arg == nil || !config_isatom(arg) || arg->next != nil) {
-		    fprintf(stderr, "\"%s\", line %u: Usage: %s string\n",
-			cmd->file, cmd->line, cmd->word);
-		    exit(1);
-		}
-		strncpy((char *) data, arg->word, sizeof(data));
-		d += i = strnlen((char *) data, sizeof(data));
-		break;}
-	    case TT_BOOLEAN: {
-		if (arg == nil || !config_isatom(arg)
-		    || !(strcasecmp(arg->word, "false") == 0
-			    || strcasecmp(arg->word, "true") == 0)
-		) {
-		    fprintf(stderr,
-			"\"%s\", line %u: Usage: %s false|true ...\n",
-			cmd->file, cmd->line, cmd->word);
-		    exit(1);
-		}
-		if (d < arraylimit(data)) {
-		    *d++ = (arg->word[0] != 'f' && arg->word[0] != 'F');
-		}
-		i++;
-		break;}
-	    case TT_IP: {
-		ipaddr_t ip;
-		unsigned long len;
-		char *end;
-
-		if (arg == nil || !config_isatom(arg)) {
-		    fprintf(stderr, "\"%s\", line %u: Usage: %s host ...\n",
-			cmd->file, cmd->line, cmd->word);
-		    exit(1);
-		}
-		if (arg->word[0] == '/'
-			&& between(1, len= strtoul(arg->word+1, &end, 10), 31)
-			&& *end == 0
-		) {
-		    ip= htonl((0xFFFFFFFFUL << (32-len)) & 0xFFFFFFFFUL);
-		} else
-		if (!name2ip(&ip, arg->word, ifip)) {
-		    fprintf(stderr,
-		    "\"%s\", line %u: Can't translate %s to an IP address\n",
-			arg->file, arg->line, arg->word);
-		    exit(1);
-		}
-		if (d <= arraylimit(data) - sizeof(ip)) {
-		    memcpy(d, &ip, sizeof(ip));
-		    d += sizeof(ip);
-		}
-		i++;
-		break;}
-	    case TT_NUMBER: {
-		unsigned long n;
-		int g;
-
-		if (arg == nil || !(arg->flags & CFG_CLONG)) {
-		    fprintf(stderr, "\"%s\", line %u: Usage: %s number ...\n",
-			cmd->file, cmd->line, cmd->word);
-		    exit(1);
-		}
-		n= strtoul(arg->word, nil, 0);
-		g= tp->gran;
-		do {
-		    if (d <= arraylimit(data)) *d++ = (n >> (--g * 8)) & 0xFF;
-		} while (g != 0);
-		i++;
-		break;}
-	    case TT_OCTET: {
-		if (arg == nil || !config_isatom(arg) || arg->next != nil) {
-		    fprintf(stderr, "\"%s\", line %u: Usage: %s hexdigits\n",
-			cmd->file, cmd->line, cmd->word);
-		    exit(1);
-		}
-		i= ascii2octet(data, sizeof(data), arg->word);
-		if (i == -1) {
-		    fprintf(stderr,
-			"\"%s\", line %u: %s: Bad hexdigit string\n",
-			arg->file, arg->line, arg->word);
-		    exit(1);
-		}
-		d= data + i;
-		break;}
-	    }
-	} while ((arg= arg->next) != nil);
-
-	if (d > data + 255) {
-	    fprintf(stderr, "\"%s\", line %u: Tag value is way too big\n",
-		cmd->file, cmd->line);
-	    exit(1);
-	}
-	if ((tp->type & TF_TYPE) != TT_NUMBER && (i % tp->gran) != 0) {
-	    fprintf(stderr,
-		"\"%s\", line %u: Expected a multiple of %d initializers\n",
-		cmd->file, cmd->line, tp->gran);
-	    exit(1);
-	}
-	if (tp->max != 0 && i > tp->max) {
-	    fprintf(stderr,
-		"\"%s\", line %u: Got %d initializers, can have only %d\n",
-		cmd->file, cmd->line, (int) i, tp->max);
-	    exit(1);
-	}
-    }
-    if (tp->type & TF_STATIC) {
-	size_t len= tp->gran * tp->max;
-	if ((tp->type & TF_TYPE) == TT_IP) len *= sizeof(ipaddr_t);
-	memset(B(dp) + tp->tag, 0, len);
-	memcpy(B(dp) + tp->tag, data, (d - data));
-    } else {
-	settag(dp, tp->tag, data, (d - data));
-    }
-}
-
-int makedhcp(dhcp_t *dp, u8_t *class, size_t calen, u8_t *client, size_t cilen,
-				ipaddr_t ip, ipaddr_t ifip, network_t *np)
-{
-    /* Fill in a DHCP packet at 'dp' for the host identified by the
-     * (class, client, ip) combination.  Makedhcp is normally called twice,
-     * once to find the IP address (so ip == 0) and once again to find all
-     * data that goes with that IP address (ip != 0).  On the first call the
-     * return value of this function should be ignored and only 'yiaddr'
-     * checked and used as 'ip' on the next pass.  True is returned iff there
-     * is information for the client on the network at interface address
-     * 'ifip', by checking if the 'ip' and 'ifip' are on the same network.
-     * If np is nonnull then we are working for one of our own interfaces, so
-     * options can be set and adjourning interfaces can be programmed.
-     */
-    config_t *todo[16];
-    size_t ntodo= 0;
-    ipaddr_t hip, mask;
-    u8_t *pmask;
-    char *hostname;
-    u32_t distance= -1;
-
-    initdhcpconf();
-
-    /* Start creating a packet. */
-    dhcp_init(dp);
-    dp->op= DHCP_BOOTREPLY;
-
-    /* The initial TODO list is the whole DHCP config. */
-    todo[ntodo++]= dhcpconf;
-
-    while (ntodo > 0) {
-	config_t *cmd, *follow;
-
-	if (todo[ntodo-1] == nil) { ntodo--; continue; }
-	cmd= todo[ntodo-1]->list;
-	todo[ntodo-1]= todo[ntodo-1]->next;
-
-	follow= nil;	/* Macro or list to follow next? */
-
-	if (strcasecmp(cmd->word, "client") == 0) {
-	    u8_t cfgid[CLID_MAX];
-	    size_t cfglen;
-	    char *name;
-	    int ifno;
-	    u32_t d;
-
-	    if (between(3, config_length(cmd), 5)
-		&& config_isatom(cmd->next)
-		&& (cfglen= ascii2clid(cfgid, cmd->next->word)) != -1
-		&& config_isatom(cmd->next->next)
-		&& (((ifno= ifname2if(cmd->next->next->word)) == -1
-			&& config_length(cmd) <= 4)
-		    || ((ifno= ifname2if(cmd->next->next->word)) != -1
-			&& config_length(cmd) >= 4
-			&& config_isatom(cmd->next->next->next)))
-	    ) {
-		if (cilen == cfglen && memcmp(client, cfgid, cilen) == 0
-		    && (ifno == -1 || np == nil || ifno == np->n)
-		) {
-		    config_t *atname= cmd->next->next;
-		    if (ifno != -1) atname= atname->next;
-		    name= atname->word;
-
-		    if (name2ip(&hip, name, ifip) && (ip == 0 || ip == hip)) {
-			d= ntohl(hip) ^ ntohl(ifip);
-			if (d < distance) {
-			    dp->yiaddr= hip;
-			    follow= atname->next;
-			    distance= d;
-			}
-		    }
-		}
-	    } else {
-		fprintf(stderr,
-	    "\"%s\", line %u: Usage: client ID [ip#] host [macro|{params}]\n",
-		    cmd->file, cmd->line);
-		exit(1);
-	    }
-	} else
-	if (strcasecmp(cmd->word, "class") == 0) {
-	    config_t *clist;
-	    int match;
-
-	    match= 0;
-	    for (clist= cmd->next; clist != nil
-				&& clist->next != nil
-				&& config_isatom(clist); clist= clist->next) {
-		if (calen > 0
-		    && strncmp(clist->word, (char *) class, calen) == 0
-		) {
-		    match= 1;
-		}
-	    }
-	    if (clist == cmd->next || clist->next != nil) {
-		fprintf(stderr,
-		"\"%s\", line %u: Usage: class class-name ... macro|{params}\n",
-		    cmd->file, cmd->line);
-	    }
-	    if (match) follow= clist;
-	} else
-	if (strcasecmp(cmd->word, "host") == 0) {
-	    if (config_length(cmd) == 3
-		&& config_isatom(cmd->next)
-	    ) {
-		if (ip != 0) {
-		    if (cidr_aton(cmd->next->word, &hip, &mask)) {
-			if (((hip ^ ip) & mask) == 0) {
-			    if (!gettag(dp, DHCP_TAG_NETMASK, nil, nil)) {
-				settag(dp, DHCP_TAG_NETMASK,
-						&mask, sizeof(mask));
-			    }
-			    dp->yiaddr= ip;
-			    follow= cmd->next->next;
-			}
-		    } else
-		    if (name2ip(&hip, cmd->next->word, ifip)) {
-			if (hip == ip) {
-			    dp->yiaddr= ip;
-			    follow= cmd->next->next;
-			}
-		    }
-		}
-	    } else {
-		fprintf(stderr,
-		"\"%s\", line %u: Usage: host host-spec macro|{params}\n",
-		    cmd->file, cmd->line);
-		exit(1);
-	    }
-	} else
-	if (strcasecmp(cmd->word, "interface") == 0) {
-	    if (between(3, config_length(cmd), 4)
-		&& config_isatom(cmd->next)
-		&& config_isatom(cmd->next->next)
-	    ) {
-		network_t *ifnp;
-
-		if (np != nil) {
-		    if ((ifnp= if2net(ifname2if(cmd->next->word))) == nil) {
-			fprintf(stderr,
-			    "\"%s\", line %u: Can't find interface %s\n",
-			    cmd->next->file, cmd->next->line, cmd->next->word);
-			exit(1);
-		    }
-		    if (!name2ip(&hip, cmd->next->next->word, 0)) {
-			fprintf(stderr,
-			    "\"%s\", line %u: Can't find IP address of %s\n",
-			    cmd->next->next->file, cmd->next->next->line,
-			    cmd->next->next->word);
-			exit(1);
-		    }
-		    ifnp->ip= hip;
-		    if (ifnp == np) {
-			dp->yiaddr= hip;
-			follow= cmd->next->next->next;
-		    }
-		}
-	    } else {
-		fprintf(stderr,
-		"\"%s\", line %u: Usage: interface ip# host%s\n",
-		    cmd->file, cmd->line, ntodo==1 ? " [macro|{params}]" : "");
-		exit(1);
-	    }
-	} else
-	if (strcasecmp(cmd->word, "macro") == 0) {
-	    if (config_length(cmd) == 2 && config_isatom(cmd->next)) {
-		follow= cmd->next;
-	    } else
-	    if (ntodo > 1) {
-		fprintf(stderr, "\"%s\", line %u: Usage: macro macro-name\n",
-		    cmd->file, cmd->line);
-		exit(1);
-	    }
-	} else
-	if (strcasecmp(cmd->word, "tag") == 0) {
-	    if (ntodo > 1) {
-		fprintf(stderr,
-		    "\"%s\", line %u: A %s can't be defined here\n",
-		    cmd->file, cmd->line, cmd->word);
-		exit(1);
-	    }
-	} else
-	if (strcasecmp(cmd->word, "option") == 0) {
-	    int ifno;
-	    network_t *ifnp;
-	    config_t *opt;
-
-	    if ((opt= cmd->next) != nil
-		&& config_isatom(opt)
-		&& (ifno= ifname2if(opt->word)) != -1
-	    ) {
-		if ((ifnp= if2net(ifno)) == nil) {
-		    fprintf(stderr,
-			"\"%s\", line %u: Interface %s is not enabled\n",
-			opt->file, opt->line, opt->word);
-		    exit(1);
-		}
-		opt= opt->next;
-	    } else {
-		ifnp= np;
-	    }
-
-	    if (between(1, config_length(opt), 2)
-		&& config_isatom(opt)
-		&& strcasecmp(opt->word, "server") == 0
-		&& (opt->next == nil
-		    || strcasecmp(opt->next->word, "inform") == 0)
-	    ) {
-		if (np != nil) {
-		    ifnp->flags |= NF_SERVING;
-		    if (opt->next != nil) ifnp->flags |= NF_INFORM;
-		}
-	    } else
-	    if (config_length(opt) == 2
-		&& config_isatom(opt)
-		&& strcasecmp(opt->word, "relay") == 0
-		&& config_isatom(opt->next)
-	    ) {
-		if (np != nil) {
-		    if (!name2ip(&hip, opt->next->word, ifip)) {
-			fprintf(stderr,
-			    "\"%s\", line %u: Can't find IP address of %s\n",
-			    opt->next->file, opt->next->line,
-			    opt->next->word);
-			exit(1);
-		    }
-		    ifnp->flags |= NF_RELAYING;
-		    ifnp->server= hip;
-		}
-	    } else
-	    if (config_length(opt) == 1
-		&& config_isatom(opt)
-		&& strcasecmp(opt->word, "possessive") == 0
-	    ) {
-		if (np != nil) ifnp->flags |= NF_POSSESSIVE;
-	    } else
-	    if (config_length(opt) == 2
-		&& config_isatom(opt)
-		&& strcasecmp(opt->word, "hostname") == 0
-		&& config_isatom(opt->next)
-	    ) {
-		if (np != nil) np->hostname= opt->next->word;
-	    } else {
-		fprintf(stderr, "\"%s\", line %u: Unknown option\n",
-		    cmd->file, cmd->line);
-		exit(1);
-	    }
-	} else {
-	    /* Must be an actual data carrying tag. */
-	    configtag(dp, cmd, ifip);
-	}
-
-	if (follow != nil) {
-	    /* A client/class/host entry selects a macro or list that must
-	     * be followed next.
-	     */
-	    config_t *macro;
-
-	    if (config_isatom(follow)) {	/* Macro name */
-		config_t *cfg;
-
-		for (cfg= dhcpconf; cfg != nil; cfg= cfg->next) {
-		    macro= cfg->list;
-
-		    if (strcasecmp(macro->word, "macro") == 0) {
-			if (config_length(macro) == 3
-			    && config_isatom(macro->next)
-			    && config_issub(macro->next->next)
-			) {
-			    if (strcasecmp(macro->next->word, follow->word) == 0
-			    ) {
-				break;
-			    }
-			} else {
-			    fprintf(stderr,
-			"\"%s\", line %u: Usage: macro macro-name {params}\n",
-				macro->file, macro->line);
-			}
-		    }
-		}
-		follow= cfg == nil ? nil : macro->next->next->list;
-	    } else {
-		/* Simply a list of more tags and stuff. */
-		follow= follow->list;
-	    }
-
-	    if (ntodo == arraysize(todo)) {
-		fprintf(stderr, "\"%s\", line %u: Nesting is too deep\n",
-		    follow->file, follow->line);
-		exit(1);
-	    }
-	    todo[ntodo++]= follow;
-	}
-    }
-
-    /* Check if the IP and netmask are OK for the interface. */
-    if (!gettag(dp, DHCP_TAG_NETMASK, &pmask, nil)) return 0;
-    memcpy(&mask, pmask, sizeof(mask));
-    if (((ip ^ ifip) & mask) != 0) return 0;
-
-    /* Fill in the hostname and/or domain. */
-    if ((hostname= ip2name(ip)) != nil) {
-	char *domain;
-
-	if ((domain= strchr(hostname, '.')) != nil) *domain++ = 0;
-
-	if (!gettag(dp, DHCP_TAG_HOSTNAME, nil, nil)) {
-	    settag(dp, DHCP_TAG_HOSTNAME, hostname, strlen(hostname));
-	}
-
-	if (domain != nil && !gettag(dp, DHCP_TAG_DOMAIN, nil, nil)) {
-	    settag(dp, DHCP_TAG_DOMAIN, domain, strlen(domain));
-	}
-    }
-
-    return 1;
-}
-
-static char *dhcpopname(int op)
-{
-    static char *onames[] = { "??\?", "REQUEST", "REPLY" };
-    return onames[op < arraysize(onames) ? op : 0];
-}
-
-char *dhcptypename(int type)
-{
-    static char *tnames[] = {
-	"??\?", "DISCOVER", "OFFER", "REQUEST", "DECLINE",
-	"ACK", "NAK", "RELEASE", "INFORM"
-    };
-    return tnames[type < arraysize(tnames) ? type : 0];
-}
-
-void printdhcp(dhcp_t *dp)
-{
-    /* Print the contents of a DHCP packet, usually for debug purposes. */
-    tagdef_t *tp;
-    u8_t *data, *ovld;
-    size_t i, len;
-
-    for (tp= alltagdef; tp < arraylimit(alltagdef); tp++) {
-	if (tp->type & TF_STATIC) {
-	    data= B(dp) + tp->tag;
-	    len= tp->gran * tp->max;
-	    if ((tp->type & TF_TYPE) == TT_IP) len *= sizeof(ipaddr_t);
-	    if (tp->tag == doff(chaddr)) len= dp->hlen;
-
-	    /* Don't show uninteresting stuff. */
-	    if (tp->tag == doff(htype) && dp->htype == DHCP_HTYPE_ETH) continue;
-
-	    if (tp->tag == doff(hlen) && dp->hlen == DHCP_HLEN_ETH) continue;
-
-	    if ((tp->tag == doff(file) || tp->tag == doff(sname))
-		&& gettag(dp, DHCP_TAG_OVERLOAD, &ovld, nil)
-		&& (ovld[0] & (tp->tag == doff(file) ? 1 : 2))
-	    ) {
-		continue;
-	    }
-	    for (i= 0; i < len && data[i] == 0; i++) {}
-	    if (i == len) continue;
-	} else {
-	    if (!gettag(dp, tp->tag, &data, &len)) continue;
-	}
-
-	if (tagdefined(tp)) {
-	    printf("\t%s =", tp->name);
-	} else {
-	    printf("\tT%d =", tp->tag);
-	}
-
-	i= 0;
-	while (i < len) {
-	    switch (tp->type & TF_TYPE) {
-	    case TT_ASCII: {
-		printf(" \"%.*s\"", (int) len, data);
-		i= len;
-		break;}
-	    case TT_BOOLEAN: {
-		printf(data[i++] == 0 ? " false" : " true");
-		break;}
-	    case TT_IP: {
-		ipaddr_t ip;
-		memcpy(&ip, data+i, sizeof(ip));
-		printf(" %s", inet_ntoa(ip));
-		i += sizeof(ip);
-		break;}
-	    case TT_NUMBER: {
-		u32_t n= 0;
-		int g= tp->gran;
-
-		do n= (n << 8) | data[i++]; while (--g != 0);
-		printf(" %lu", (unsigned long) n);
-		if ((tp->type & TF_STATIC) && tp->tag == doff(op)) {
-		    printf(" (%s)", dhcpopname(n));
-		}
-		if (!(tp->type & TF_STATIC) && tp->tag == DHCP_TAG_TYPE) {
-		    printf(" (%s)", dhcptypename(n));
-		}
-		break;}
-	    case TT_OCTET: {
-		if (i == 0) fputc(' ', stdout);
-		printf("%02X", data[i++]);
-		break;}
-	    }
-	}
-	fputc('\n', stdout);
-    }
-}
