./usr/bin/deroff minix-base
./usr/bin/devmand minix-base
./usr/bin/devsize minix-base
-./usr/bin/dhcpd minix-base
+./usr/bin/dhcpd minix-base obsolete
./usr/bin/dhrystone minix-base
./usr/bin/diff minix-base
./usr/bin/dirname minix-base
./usr/bin/znew minix-base
./usr/etc minix-base
./usr/etc/daily minix-base
-./usr/etc/dhcptags.conf minix-base
+./usr/etc/dhcptags.conf minix-base obsolete
./usr/etc/rc minix-base
./usr/include/c++ minix-base gcc=5
./usr/include/c++/experimental minix-base gcc=5
./usr/libdata/debug/usr/bin/deroff.debug minix-debug debug
./usr/libdata/debug/usr/bin/devmand.debug minix-debug debug
./usr/libdata/debug/usr/bin/devsize.debug minix-debug debug
-./usr/libdata/debug/usr/bin/dhcpd.debug minix-debug debug
+./usr/libdata/debug/usr/bin/dhcpd.debug minix-debug debug,obsolete
./usr/libdata/debug/usr/bin/dhrystone.debug minix-debug debug
./usr/libdata/debug/usr/bin/diff.debug minix-debug debug
./usr/libdata/debug/usr/bin/dirname.debug minix-debug debug
./usr/man/man5/configfile.5 minix-man
./usr/man/man5/cpio.5 minix-man
./usr/man/man5/crontab.5 minix-man
-./usr/man/man5/dhcp.conf.5 minix-man
+./usr/man/man5/dhcp.conf.5 minix-man obsolete
./usr/man/man5/dir.5 minix-man obsolete
./usr/man/man5/editrc.5 minix-man
./usr/man/man5/ethers.5 minix-man
./usr/man/man8/cron.8 minix-man
./usr/man/man8/dev_mkdb.8 minix-man
./usr/man/man8/devsize.8 minix-man
-./usr/man/man8/dhcpd.8 minix-man
+./usr/man/man8/dhcpd.8 minix-man obsolete
./usr/man/man8/diskctl.8 minix-man
./usr/man/man8/fbdctl.8 minix-man
./usr/man/man8/fdisk.8 minix-man
.else # LSC Minix Specific
.for owner group mode sdir tdir files in \
${BINOWN} ${BINGRP} ${BINMODE} ${NETBSDSRCDIR}/etc/usr/ ${DESTDIR}/usr/etc/ daily \
- ${BINOWN} ${BINGRP} ${BINMODE} ${NETBSDSRCDIR}/etc/usr/ ${DESTDIR}/usr/etc/ dhcptags.conf \
${BINOWN} ${BINGRP} ${BINMODE} ${NETBSDSRCDIR}/etc/usr/ ${DESTDIR}/usr/etc/ rc \
${BINOWN} ${BINGRP} ${BINMODE} ${NETBSDSRCDIR}/etc/ ${DESTDIR}/usr/lib/ crontab \
${BINOWN} ${BINGRP} ${BINMODE} ${NETBSDSRCDIR}/etc/ ${DESTDIR}/etc/ system.conf \
+++ /dev/null
-# A list of all tags mentioned in RFC-1533.
-
-tag 1 netmask ip 1 1;
-tag 2 zoneoffset number 4 1;
-tag 3 gateway ip 1 0;
-tag 4 timeserver ip 1 0;
-tag 5 nameserver ip 1 0;
-tag 6 DNSserver ip 1 0;
-tag 7 logserver ip 1 0;
-tag 8 cookieserver ip 1 0;
-tag 9 LPR ip 1 0;
-tag 10 impress ip 1 0;
-tag 11 resource ip 1 0;
-tag 12 hostname ascii 1 0;
-tag 13 bootfilesize number 2 1;
-tag 14 coredump ip 1 0;
-tag 15 domain ascii 1 0;
-tag 16 swapserver ip 1 1;
-tag 17 rootpath ascii 1 0;
-tag 18 extensions ascii 1 0;
-tag 19 IPforwarding boolean 1 1;
-tag 20 IPnonlocalsource boolean 1 1;
-tag 21 IPpolicyfilter ip 2 0;
-tag 22 IPmaxreassembly number 2 1;
-tag 23 IPTTL number 1 1;
-tag 24 IPMTUaging number 4 1;
-tag 25 IPMTUplateau number 2 0;
-tag 26 IPMTU number 2 1;
-tag 27 IPsublocal boolean 1 1;
-tag 28 IPbroadcast ip 1 1;
-tag 29 IPmaskdiscovery boolean 1 1;
-tag 30 IPmasksupplier boolean 1 1;
-tag 31 IPdiscovery boolean 1 1;
-tag 32 IPsolicitation ip 1 1;
-tag 33 IPstaticroute ip 2 0;
-tag 34 ARPtrailer boolean 1 1;
-tag 35 ARPtimeout number 4 1;
-tag 36 ETHencapsulation boolean 1 1;
-tag 37 TCPTTL number 1 1;
-tag 38 TCPkeepaliveinterval number 4 1;
-tag 39 TCPkeepalivegarbage boolean 1 1;
-tag 40 NISdomain ascii 1 0;
-tag 41 NISserver ip 1 0;
-tag 42 NTPserver ip 1 0;
-tag 43 VENDOR octet 1 0;
-tag 44 NetBIOSNS ip 1 0;
-tag 45 NetBIOSdgram ip 1 0;
-tag 46 NetBIOSnodetype number 1 1;
-tag 47 NetBIOSscope octet 1 0;
-tag 48 Xfontserver ip 1 0;
-tag 49 XDM ip 1 0;
-tag 50 DHCPreqip ip 1 1;
-tag 51 DHCPlease number 4 1;
-tag 52 DHCPoverload number 1 1;
-tag 53 DHCPtype number 1 1;
-tag 54 DHCPserverID ip 1 1;
-tag 55 DHCPreqpar number 1 0;
-tag 56 DHCPmessage ascii 1 0;
-tag 57 DHCPsize number 2 1;
-tag 58 DHCPrenewal number 4 1;
-tag 59 DHCPrebinding number 4 1;
-tag 60 DHCPclassID ascii 1 0;
-tag 61 DHCPclientID octet 1 0;
CPPFLAGS.fslib.c+= -I${NETBSDSRCDIR}/minix/fs
CPPFLAGS.fsversion.c+= -I${NETBSDSRCDIR}/minix/fs
-SRCS+= dhcp_gettag.c dhcp_settag.c fsversion.c gcov.c itoa.c \
+SRCS+= fsversion.c gcov.c itoa.c \
oneC_sum.c read_tsc_64.c servxcheck.c fslib.c
.endif # defined(__MINIX)
cawf cdprobe \
cleantmp \
compress crc cron crontab \
- DESCRIBE devmand devsize dhcpd \
+ DESCRIBE devmand devsize \
dhrystone \
eject \
fix format fsck.mfs \
+++ /dev/null
-# Makefile for dhcpd.
-
-PROG= dhcpd
-SRCS= dhcpd.c tags.c devices.c ether.c
-MAN= dhcpd.8 dhcp.conf.5
-
-.include <bsd.prog.mk>
+++ /dev/null
-/* 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 */
+++ /dev/null
-/* 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 <signal.h>
-#include <time.h>
-#include <sys/ioctl.h>
-#include <sys/asynchio.h>
-#include <net/hton.h>
-#include <net/gen/in.h>
-#include <netinet/in.h>
-#include <sys/socket.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;
-}
-
-#define N_FDS 16 /* Minix can go async on many fds. */
-
-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);
- }
-}
-
-static void timeout(int signum)
-{
- /* nothing to do, ioctl will be aborted automatically */
- if (alarm(1) == (unsigned int)-1) fatal("alarm(1)");
-}
-
-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;
- if (lwip && (fdtype == FT_ETHERNET || fdtype == FT_ICMP))
- sprintf(fdp->device, "/dev/ip");
- else
- 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:
- if (lwip) {
- nwio_ipopt_t ipopt;
- int result;
- char ethdev[64];
- int efd;
-
- sprintf(ethdev, "/dev/eth%d", np->n);
-
- if ((efd = open(fdp->device, O_RDWR)) < 0) {
- if (errno == ENOENT || errno == ENODEV ||
- errno == ENXIO)
- return 0;
- fatal(ethdev);
- }
-
- if (ioctl(efd, NWIOGETHSTAT, ðstat) < 0) {
- /* Not an Ethernet. */
- close(efd);
- return 0;
- }
- close(efd);
-
- np->eth= ethstat.nwes_addr;
-
- ipopt.nwio_flags= NWIO_COPY | NWIO_PROTOSPEC;
- ipopt.nwio_proto= 17; /* UDP */
- result= ioctl (fdp->fd, NWIOSIPOPT, &ipopt);
- if (result<0)
- perror("ioctl (NWIOSIPOPT)"), exit(1);
-
- break;
- }
- /* Cannot use NWIOGETHSTAT in non-blocking mode due to a race between
- * the reply from the ethernet driver and the cancel message from VFS
- * for reaching inet. Hence, a signal is used to interrupt NWIOGETHSTAT
- * in case the driver isn't ready yet.
- */
- if (signal(SIGALRM, timeout) == SIG_ERR) fatal("signal(SIGALRM)");
- if (alarm(1) == (unsigned int)-1) fatal("alarm(1)");
- if (ioctl(np->fdp->fd, NWIOGETHSTAT, ðstat) < 0) {
- /* Not an Ethernet. */
- close(fdp->fd);
- return 0;
- }
- if (alarm(0) == (unsigned int)-1) fatal("alarm(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, ðopt) < 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:
- if (lwip) {
- struct sockaddr_in si_me;
-
- close(fdp->fd);
- fdp->fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
- if (fdp->fd < 0)
- return 0;
- memset((char *) &si_me, 0, sizeof(si_me));
- si_me.sin_family = AF_INET;
- si_me.sin_addr.s_addr = htonl(INADDR_ANY);
- si_me.sin_port = htons(port_client);
- if (bind(fdp->fd, (struct sockaddr *) &si_me,
- sizeof(si_me)) == -1) {
- close(fdp->fd);
- printf("DHCP : cannot bind client socket to port %d\n",
- port_client);
- return 0;
- }
- break;
- }
- 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);
-}
+++ /dev/null
-.TH DHCP.CONF 5
-.SH NAME
-dhcp.conf \- dynamic host configuration protocol configuration
-.SH SYNOPSIS
-.B /etc/dhcp.conf
-.SH DESCRIPTION
-.de SP
-.if t .sp 0.4
-.if n .sp
-..
-The file
-.B /etc/dhcp.conf
-contains the configuration for the DHCP client/server program
-.BR dhcpd .
-This text is a long summation of all the elements that can be found in this
-configuration file. For a more "just tell me what to do" approach see
-.BR boot (8).
-.PP
-The syntax used is that of the common configuration file described in
-.BR configfile (5).
-.PP
-To find information for a client we first need its IP address. Occasionally
-this IP address is already known (the special "INFORM" query), but normally
-we have to make a first pass through the configuration file for a
-.B client
-entry. If that fails then we use an IP address from the pool file. If we
-now have an IP address then the real information gathering can begin.
-.PP
-The DHCP daemon reads the configuration file from beginning to end and
-gathers all information that matches, and information from all macros that
-are mentioned within the elements that match. If we end up with DHCP
-information that includes at least a netmask definition, and is good for the
-network the request came in from, then it is returned to the client. If a
-DHCP tag is specified twice then the last one wins.
-.PP
-In the description below we use [ and ] to denote optional things, and | to
-show a choice between two things.
-.PP
-Client IDs can be either ordinary Ethernet addresses, that are treated as a
-seven octet string (01 followed by the Ethernet address), or any random
-octet string in hexadecimal.
-.PP
-IP addresses can be simply that, or host names. These host names are
-searched in
-.B /etc/hosts
-by
-.B dhcpd
-itself using a domain based prefix match, i.e. you can use "flotsam" for
-"flotsam.example.com", but not "alpha" for "alphabeta". Once the program
-decides to be a server it will also look up names normally in the DNS.
-If a host has more than one IP address then the address on the network the
-query was seen on is used.
-.PP
-Case isn't important in the configuration file, "client", "CLIENT" and
-"ClIeNt" are all treated the same.
-.PP
-Some elements may optionally name a macro or a curly braces enclosed
-parameter list of more elements. If the element matches then the data
-in the macro body or parameter list is gathered.
-.PP
-The following elements can be used:
-.PP
-.B client
-.I client-ID
-.RB [ ip #]
-.I host
-.RI [ macro |{ params }];
-.PP
-.RS
-Defines a client with a given client ID that is to have the IP address
-denoted by
-.I host .
-On the first pass only the client ID is matched looking for an IP address
-that lies on the network the request came in on. On the
-information gathering pass both client ID and IP address must match. If
-a machine has the same Ethernet address on two or more interfaces then the
-IP address given out is the one on the same network as the request came in
-on. The optional interface name
-.RB ( ip #)
-must be used if the DHCP daemon is gathering data for itself at boot time
-to differentiate interfaces with the same ethernet addresses. This is
-only necessary under Minix-vmd when ethernets on different VLANs share
-the same physical ethernet. The interface name is only used for a machine's
-own networks, it ignored on entries for other hosts.
-.RE
-.PP
-.B class
-.IR class-name " ..."
-.IR macro |{ params };
-.PP
-.RS
-Includes the macro or parameters if one of the class names is matched. A
-host normally includes a class ID in its request. MINIX 3 and Minix-vmd
-use "Minix" as the class name. For Windows the class ID starts with
-"MSFT", and Solaris' starts with "SUNW".
-(Use
-.B dhcpd \-d3
-to find out what the full IDs are exactly.) The class names are matched if a
-.I class-name
-is a prefix of the class ID sent by the client.
-.RE
-.PP
-.B host
-.I host-spec
-.IR macro |{ params };
-.PP
-.RS
-Includes the macro or parameters if the IP address of the client matches the
-host specification. This can either be an ordinary hostname, or a netblock
-in CIDR notation, e.g. 172.35.0.0/16. The example includes all IP addresses
-whose top 16 bits are the same as the top 16 bits of 172.35.0.0. Such a
-netblock automatically defines a netmask (255.255.0.0 in the example) if no
-netmask has been specified yet.
-.RE
-.PP
-.B interface
-.BR ip #
-.I host
-.RI [ macro |{ params }];
-.PP
-.RS
-Makes
-.B dhcpd
-set the IP address of interface
-.BR ip #
-(where # is a number) to the IP address denoted by
-.IR host .
-This element should only be used for interfaces that are not true Ethernets,
-and so do not have a unique Ethernet address that can be used for a client
-element. If the machine has at least one true Ethernet then all interface
-elements should be added to the parameter list of a host or client element
-for that Ethernet interface. This binds them to that machine and allows a
-single configuration file to be shared among machines. Especially a server
-should never have "free" interface elements. The macro or parameters are
-only evaluated if data is gathered for the given interface. (Note that they
-will be hidden by a client element for another interface.)
-.RE
-.PP
-.B macro
-.IR macro-name ;
-.PP
-.RS
-Include the parameter list of the macro named
-.I macro-name
-defined elsewhere. (This means that "host flotsam stuff" is just short
-for "host flotsam { macro stuff; }".)
-.RE
-.PP
-.B macro
-.I macro-name
-.RI { params };
-.PP
-.RS
-Defines a macro with the given parameter list. Whenever the macro is used
-the parameter list is substituted instead. A macro can not be defined
-within another parameter list.
-.RE
-.PP
-.B option
-.RB [ ip #]
-.B server
-.RB [ inform ];
-.br
-.B option
-.RB [ ip #]
-.B relay
-.IR host ;
-.br
-.B option
-.RB [ ip #]
-.BR possessive ;
-.br
-.B option
-.RB [ ip #]
-.B hostname
-.IR name ;
-.PP
-.RS
-Makes
-.B dhcpd
-set special options for the interface that it is gathering data for, or the
-interface denoted by the optional
-.BR ip #
-argument. The options are:
-.SP
-.B server
-.RB [ inform ]
-.RS
-Be a DHCP server on the network connected to the interface. Add the word
-.B inform
-if DHCPINFORM requests must be answered for hosts we don't have an address
-for.
-.RE
-.SP
-.B relay
-.I host
-.RS
-Be a DHCP relay to the indicated host.
-.RE
-.SP
-.B possessive
-.RS
-Do not disable the interface if the DHCP lease expires. Useful if the
-DHCP server of the provider is unreliable, crashing a lot and causing the
-lease to expire. (Think twice before turning this option on. You have to
-be absolutely sure that it's the DHCP server that's the culprit and not
-a flaky network. You don't want an IP address conflict to be your fault.)
-.RE
-.SP
-.B hostname
-.I name
-.RS
-Use the given name as our hostname in the DHCP queries. Some sites key on
-that bit of information instead of a client ID.
-.RE
-.RE
-.PP
-.B tag
-.I number name type granularity
-.IR max ;
-.PP
-.RS
-Defines a DHCP tag for the given tag number and gives it a name. The name can
-be used in the configuration file to set tag values when gathering data.
-The
-.I type
-field can be one of
-.BR ascii ,
-.BR boolean ,
-.BR ip ,
-.BR number
-or
-.BR octet
-to specify the type of the tag as a simple string, a boolean, an IP address,
-a number, or a string of octet values.
-The
-.I granularity
-field specifies that that number of items must be given or a multiple
-thereof, unless the type is a number, then it is the size of the number (1,
-2 or 4).
-The
-.I max
-field tells the maximum number of items that may be used with the tag, with
-0 meaning "unlimited".
-.SP
-Three tags, the ones that MINIX 3 really cares about, have been predefined,
-and there are also a few pseudotags predefined for the static fields in a
-DHCP packet that one may want to set:
-.SP
-.RS
-.nf
-tag ? siaddr ip 1 1;
-tag ? sname ascii 1 64;
-tag ? file ascii 1 128;
-tag 1 netmask ip 1 1;
-tag 3 gateway ip 1 0;
-tag 6 DNSserver ip 1 0;
-.fi
-.RE
-.SP
-The file
-.B /usr/etc/dhcptags.conf
-contains tag definitions for all standard DHCP tags. It is wise to include
-this file at the top of any DHCP configuration file.
-.RE
-.PP
-.B no
-.IR tag-name ;
-.PP
-.RS
-Removes a tag with the given name from the data gathered at this point.
-Useful if one host is different from all others, for instance if it doesn't
-need a gateway definition, because it happens to be the gateway.
-.RE
-.PP
-.IR "ascii-tag string" ;
-.PP
-.RS
-Adds an ASCII tag to the gathered data. The string can be a simple word, or
-a quoted string.
-.RE
-.PP
-.I boolean-tag
-.BR false | true ;
-.PP
-.RS
-Set a boolean tag to be false or true. (Encoded as a octet of value 0 or 1.
-Note that if you prefer to use 0 or 1 instead of false or true then you can
-define a boolean tag as a size 1 number instead.)
-.RE
-.PP
-.IR "ip-tag host" " ...;"
-.PP
-.RS
-Sets a tag that needs one or more IP addresses. The host names are
-translated as usual. To make it easier to specify netmasks one can use a
-slash followed by a number, e.g.
-.BR "netmask /27" ,
-which is a handy alternative for
-.BR "netmask 255.255.255.224" .
-.RE
-.PP
-.IR "number-tag number" " ...;"
-.PP
-.RS
-Set a number tag.
-.RE
-.PP
-.IR "octet-tag hexdigits" ;
-.PP
-.RS
-Set an octet string tag.
-.I Hexdigits
-is a series of hexadecimal digits that are two by two used to set the
-octets.
-.RE
-.PP
-.SH EXAMPLE
-As an example the DHCP configuration used by the author of this document is
-included. His network at home consists of a number of PCs, an ISDN router
-named rhone and a PC named saone serving as router/tunnel to/via a cable
-ISP. Both the rhone and the saone connect the home net to the network of
-the Vrije Universiteit, but the rhone is only active if the cable doesn't
-work.
-.PP
-The saone is a DHCP server, and one of the ordinary PCs is a backup DHCP
-server. Both use the same configuration file, which is added below, with
-extra commentary introduced by
-.B ##
-at a deeper indent level:
-.RS
-.de xS \" Example start
-.sp
-.nf
-.ft C
-..
-.de xE \" Example end
-.fi
-.ft R
-..
-.de cS \" Commentary start
-.sp
-.in +12m
-.ti -\w'## 'u
-##\ \c
-..
-.de cE \" Commentary end
-.in -12m
-..
-.xS
-.ta +8m +16m
-include /usr/etc/dhcptags.conf;
-.xE
-.cS
-With the help of the tag definitions we can use tags like "DHCPlease".
-.cE
-.xS
-host 130.37.102.64/27 {
- DNSserver saone darask;
- host 130.37.102.88/29 { DHCPlease 259200; }
-};
-.xE
-.cS
-This defines the network 130.37.102.64/27, with netmask 255.255.255.224
-(implicit from the network definition). The DNS servers for this net are
-saone and darask. A smaller subrange of addresses is used as an address
-pool on the saone, so a lease of 259200 seconds (3 days) is defined. The
-netmask is still /27, as set by the outer network definition.
-.cE
-.xS
-host 130.37.102.248/30 {};
-.xE
-.cS
-A network of two addresses for routing tests.
-.cE
-.xS
-host saone {
- option server;
- option ip1 possessive;
- interface ip2 saone-net2;
- DNSserver 130.37.24.3 130.37.24.6;
-};
-.xE
-.cS
-With the network definitions done we turn our attention to the hosts. Saone
-is a DHCP server on its main interface. The second interface
-.RB ( ip1 )
-is connected to the cable modem. It gets its address from the cableco's
-DHCP server, and if that server decides to go deaf then the saone keeps
-the interface up ("possessive") even if the lease expires. The pseudo IP
-interface
-.B ip2
-is set to the IP address of
-.BR saone-net2 ,
-one side of the encrypted tunnel over the cable to a Minix-vmd box at the VU.
-The DNS servers specified override the default setting for the network, naming
-two external servers at the VU that know the world.
-.cE
-.xS
-host darask {
- option server;
- DNSserver saone;
- class MINIX 3 { DNSserver saone 130.37.24.3 130.37.24.6; };
-};
-.xE
-.cS
-The darask is also a server, the backup for saone on the odd chance that it
-is unavailable. It uses saone and the external name servers, but only
-when it is running MINIX 3. When running Windows it only uses saone.
-.cE
-.xS
-.ta +32m +16m
-client 0:1:1b:a:68:ce darask; # NE2000
-client 0:1:1b:a:77:23 burask; # NE2000
-#lient 0:0:c0:b0:da:64 burask; # WD8013EWC
-client 8:0:5a:38:b2:f finiah; # PCMCIA NE2000
-client 0:0:c0:3a:12:10 bardelask; # WD8003
-#lient 2:60:8c:ab:8a:6d bardelask; # 3C503
-client 0:a0:c5:20:9:6d rhone;
-client 0:1:1b:a:4c:3b saone; # NE2000
-#lient 0:0:c0:fb:2:6a saone-net1; # WD8013EWC
-.xE
-.cS
-Lastly the ethernet addresses of all the hosts are listed, so that they can
-be translated to IP addresses. The lines that are commented out are for
-extra network cards that are currently unused. The last is used to connect
-to the cable modem, so it's only here because it's nice to have the ethernet
-address written down somewhere.
-.cE
-.RE
-.PP
-The host names shown above are translated by DHCP using this
-.BR /etc/hosts :
-.RS
-.xS
-.ta +\w'130.37.102.249mm'u
-604800 %ttl
-2419200 %stale
-
-130.37.102.65 darask.kjb.upwind.org
-130.37.102.66 burask.kjb.upwind.org
-130.37.102.67 finiah.kjb.upwind.org
-130.37.102.68 bardelask.kjb.upwind.org
-130.37.102.69 roniah.kjb.upwind.org
-
-130.37.102.70 saone.kjb.upwind.org
-130.37.102.2 saone-net2.kjb.upwind.org
-
-130.37.102.88 rhone.kjb.upwind.org
-130.37.102.89 dyn89.kjb.upwind.org
-130.37.102.90 dyn90.kjb.upwind.org
-130.37.102.91 dyn91.kjb.upwind.org
-130.37.102.92 dyn92.kjb.upwind.org
-130.37.102.93 dyn93.kjb.upwind.org
-130.37.102.94 dyn94.kjb.upwind.org
-
-130.37.102.249 tst1.kjb.upwind.org
-130.37.102.250 tst2.kjb.upwind.org
-.xE
-.RE
-.SH FILES
-.TP
-.B /usr/etc/dhcptags.conf
-A supplied list of standard tag definitions as per RFC-1533. (Well, the
-tag numbers and their meaning are standard, the names are made up.)
-.SH "SEE ALSO"
-.BR RFC-2131 ,
-.BR RFC-1533 ,
-.BR configfile (5),
-.BR hosts (5),
-.BR boot (8),
-.BR dhcpd (8).
-.SH NOTES
-The amount of memory
-.B dhcpd
-needs increases with the size of configuration file. MINIX 3 can
-handle
-.B dhcptags.conf
-and a modest sized
-.BR dhcp.conf .
-You have to increase the stack size to accommodate more. (No problem under
-Minix-vmd, of course.)
-.SH NOTES
-Items that are only necessary for a certain host should only be specified
-for that host. Items for a whole network are best added to a netblock
-specification. Use class elements for a certain type of host, and macros
-for exceptions. Try to limit information as much as possibly to those hosts
-that need it. (Don't go overboard. A MINIX 3 machine won't be bothered by a
-few NetBIOS tags.)
-.PP
-DHCPINFORM requests should always be answered when being a server, but
-J. Random Sysadmin trying to diagnose problems doesn't like it when little
-MINIX 3 machines show up in a packet trace unexpectedly. It's best to be
-inconspicuous on a network you don't own.
-.SH BUGS
-There are a few too many subtle mistakes one can make.
-.SH AUTHOR
-Kees J. Bot <kjb@cs.vu.nl>
+++ /dev/null
-.TH DHCPD 8
-.SH NAME
-dhcpd \- dynamic host configuration protocol daemon
-.SH SYNOPSIS
-.in +.5i
-.ti -.5i
-.B dhdpd
-.RB [ \-qar ]
-.RB [ \-t [\fIlevel\fP]]
-.RB [ \-d [\fIlevel\fP]]
-.RB [ \-f
-.IR configfile ]
-.RB [ \-c
-.IR cachefile ]
-.RB [ \-p
-.IR poolfile ]
-.RI [ host " ...]"
-.in -.5i
-.SH DESCRIPTION
-.de SP
-.if t .sp 0.4
-.if n .sp
-..
-.B Dhcpd
-is a client and a server for the Dynamic Host Configuration Protocol. As a
-client it collects DHCP data to configure the Ethernet networks with, and as
-a server it answers DHCP queries from other machines.
-.PP
-This manual page describes the operation of
-.BR dhcpd ,
-the associated configuration file is described in
-.BR dhcp.conf (5).
-(The latter, together with
-.BR boot (8),
-is of more practical value when it comes to getting a machine's networks
-interfaces up and running. See the options section below for debugging DCHP
-problems.)
-.SS Initialization
-On a normal startup, i.e. none of the
-.BR \-q ,
-.BR \-a
-or
-.BR \-r
-options are given,
-.B dhcpd
-determines what IP devices are present, and which of those are Ethernets.
-For each network it looks for information in the configuration file as if
-it were a server answering a query for that network. If any information is
-found then the IP address is configured and the information stored in the
-cache file.
-.SS "Client Operation"
-For each still unconfigured network a DHCP DISCOVER request is broadcast on
-that network. If a DHCP OFFER reply is received then a DHCP REQUEST is
-broadcast for the IP address offered, and if a DHCP ACK is received then the
-network is configured and the information stored in the cache file.
-.PP
-If no reply is received then another query is sent after 4 seconds, and then
-again after 8 seconds, doubling each time until 64 seconds. Every 64
-seconds thereafter a request is broadcast until a reply is received.
-.PP
-Once configured the DHCP lease, rebind and renew times are computed. At the
-renew time a DHCP REQUEST is sent to the DHCP server to extend the lease.
-Normally we get an answer and refresh our information, but if no reply is
-received we wait for half the remaining time until the rebind time and keep
-retrying and halving the remaining time. When the rebind time is reached
-the DHCP REQUEST is broadcast to try and reach some other DHCP server.
-Halving the remaining time again and again until the lease expires. At that
-point we go back to square one and broadcast a DHCP DISCOVER.
-.PP
-If at any point a DHCP NAK is received we start over completely. After a
-DHCP OFFER an ARP request is transmitted just before the DHCP REQUEST to
-check if the address offered is already in use. If an ARP reply is received
-before the DHCP ACK then after the ACK we send a DHCP DECLINE to the server
-to tell that the address isn't what we want and again we start over.
-.SS "Router Discovery"
-The gateway offered by the DHCP server is made known to the TCP/IP server by
-sending an ICMP router advertisement to the local interface with a short
-lifetime and a low priority. Then up to three router solicitations are
-broadcast three seconds apart to look for a router. If a router answers
-with a router advertisement then we no longer worry about routing for that
-interface. Otherwise the router information is refreshed before it expires
-and another solicitation is sent out. This happens about twice an hour.
-.SS "Server Operation"
-Once all networks so marked are configured the daemon starts answering
-requests by other machines or relaying requests to other DHCP servers.
-DHCP requests are answered if information for a client
-can be found in the configuration file, or if a free address can be found in
-the pool file, or if a client rerequests an address it already owns.
-.PP
-If the daemon is both a server and a relay for a network then it will try
-to answer a request and only relay if it has no answer.
-.SS "Nothing more to do?"
-If the daemon finds out that all networks have an infinite lease (configured
-with a fixed address), there is no router information to keep warm, and
-it isn't a server then it simply exits.
-.SS "Asynchronous I/O?"
-MINIX 3 doesn't have the asynchronous I/O that Minix-vmd has, so under MINIX 3
-the daemon only works with one network at a time. If it's stuck on the same
-network for 32 seconds then that network is closed and another network is
-tried for 32 seconds. This usually works ok as a client, but as a server it
-can only handle one network.
-.SH OPTIONS
-.TP
-.B \-q
-Read and print the cache and pool file contents, showing DHCP information
-for each network, and the IP addresses in the pool with lease times and
-current/last owners of those addresses.
-.TP
-.B \-a
-Add the named hosts (or IP addresses) to the pool file.
-.TP
-.B \-r
-Remove hosts from the pool file.
-.TP
-.RB [ \-t [\fIlevel\fP]]
-Set the test level (by default 1). At test level 1 all networks are seen as
-unconfigured, will not be configured and no data will be put in the cache.
-The program will just act as-if. At test level 2 the interfaces will not be
-configured from the configuration file, the data must come from a remote
-server. At level 3 the renewal, rebind and lease time will be 60, 120
-and 180 seconds. At level 4 these times will be 60, 60, and 120. At
-level 5 these times will be 60, 60, and 60. These test levels are meant
-to debug the DHCP client code, and are best used with a high debug level.
-.TP
-.RB [ \-d [\fIlevel\fP]]
-Set the debug level (by default 1). At debug level 1 the program shows
-Ethernet and IP addresses as they are determined or configured, DHCP
-messages sent and received with little detail (one line per message), and
-memory use. At debug level 2 each DHCP packet is decoded and shown in
-detail. At debug level 3 device opens and closes are shown. The debugging
-level may also be increased by 1 at runtime by sending signal
-.BR SIGUSR1
-or turned off (set to 0) with
-.BR SIGUSR2 .
-.TP
-.BI \-f " configfile"
-Names the configuration file, by default
-.BR /etc/dhcp.conf .
-.TP
-.BI \-c " cachefile"
-Names the cache file, by default
-.BR /usr/adm/dhcp.cache .
-.TP
-.BI \-p " poolfile"
-Names the IP address pool, by default
-.BR /usr/adm/dhcp.pool .
-.SH "SEE ALSO"
-.BR RFC-2131 ,
-.BR RFC-1533 ,
-.BR dhcp.conf (5),
-.BR hosts (5),
-.BR ifconfig (8),
-.BR inet (8),
-.BR boot (8),
-.BR inetd (8),
-.BR nonamed (8).
-.SH DIAGNOSTICS
-.TP
-"'/etc/dhcp.conf', line ..."
-The program exits on any configuration file error. You have to correct the
-error and restart the program.
-.TP
-"No lease set for address ..."
-There must be a lease time defined for addresses in the pool. Correct and
-restart the program.
-.TP
-"###### declines #.#.#.# saying '...'"
-A client with the given client identifier (usually 01 followed by the client's
-Ethernet address) declines an IP address, hopefully with a message telling
-why. This usually means that the IP address is already in use by another
-host. This program, acting as a client, will tell what other host in its
-message, but Windows has no additional info alas.
-.TP
-"Got a NAK from #.#.#.# [through #.#.#.#] saying '...'"
-The server with the given IP address doesn't want us to have or keep the IP
-address we were offered or are rerequesting. This could mean that the server
-has forgotten about us and has given our address to another machine. This
-is bad if our lease hasn't yet expired. There may be a relay involved, and
-there may even be a text message with precise information.
-.TP
-"#.#.#.# offered by #.#.#.# is already in use by #:#:#:#:#:#"
-We got an ARP reply for an offered address. We won't accept it, and send
-out a DECLINE when we get an ACK.
-.TP
-"DHCP packet too big, ..."
-You've got way to much information in the configuration file, more than fits
-in a minimum size DHCP packet. (Notify the author if you really need to send
-more information. He doesn't think anyone needs to.)
-.TP
-"Pool table is corrupt"
-You will have to remove and refill the pool file. Chaos may ensue if
-there are active clients and they don't use ARP to detect each other.
-(Most do.)
-.SH BUGS
-There is no randomization of timers. Modern systems don't blink under the
-load of several clients broadcasting a few packets in sync.
-.PP
-There is no extra time spent waiting for an ARP reply. It is assumed that
-any IP stack will immediately respond, so that the DHCP server can't
-possibly beat it at sending out an ACK. (The DHCP server has to commit the
-lease to stable storage first anyway.)
-.PP
-Way more nonsense can be sent in a DHCP packet that MINIX 3 could do
-something with, but nobody does so we don't bother.
-.PP
-DHCP was invented by a rabid gerbil on speed.
-.SH AUTHOR
-Kees J. Bot <kjb@cs.vu.nl>
+++ /dev/null
-/* 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 <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 <arpa/inet.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. */
-
-int lwip;
-
-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;
-}
-
-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, "-%llu", now - expire);
- } else {
- sprintf(delta, "+%llu", expire - now);
- }
- printf("\t%-15s %8s ", inet_ntoa(*(struct in_addr *)&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 sendpacket(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(*(struct in_addr *)&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(*(struct in_addr *)&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;
- buf_t *bp;
- static struct timeval eventtv;
-
-main:
- n_nets = 0;
- r = -1;
- bp = nil;
- 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; /* -- */
-
- if (strcmp(opt, "-lwip") == 0) {
- lwip = 1;
- continue;
- }
-
- 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 (lwip) {
- np->type = NT_ETHERNET;
- } else 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,
- (void *)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 (sendpacket(np, (lwip ? bp->ip : (void *) bp->eth),
- (lwip ? 0 : 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 (sendpacket(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(*(struct in_addr *)&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,
- lwip ? np->fdp->bp->ip : (void *) np->fdp->bp->eth,
- lwip ? BUF_IP_SIZE : 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 >= (lwip ? 0 : (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(*(struct in_addr *)&server));
- if (relay != server)
- printf(" through %s\n",
- inet_ntoa(*(struct in_addr *)&relay));
- else printf("\n");
- 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 (sendpacket(np, bp->eth, sizeof(arp46_t))) {
- if (debug >= 2) {
- printf("Sent ARP for %s\n",
- inet_ntoa(*(struct in_addr *)&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 (sendpacket(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(*(struct in_addr *)&server));
- if (relay != server) {
- fprintf(stderr, " through %s",
- inet_ntoa(*(struct in_addr *)&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(*(struct in_addr *)&np->ip));
- fprintf(stderr, "%s is already in use by %s\n",
- inet_ntoa(*(struct in_addr *)&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 (sendpacket(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(*(struct in_addr *)&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 (sendpacket(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(*(struct in_addr *)&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(*(struct in_addr *)&bp->udpio->uih_src_addr));
- printf("%s\n",
- inet_ntoa(*(struct in_addr *)&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 (sendpacket(np, bp->udpio, r)) {
- if (debug >= 1) {
- printf("%s: Sent DHCP packet to %s\n",
- np->fdp->device,
- inet_ntoa(*(struct in_addr *)
- &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! Starting over...\n");
- sleep(2);
- goto main;
-
- return 0;
-}
+++ /dev/null
-/* dhcpd.h - Dynamic Host Configuration Protocol daemon.
- * Author: Kees J. Bot
- * 16 Dec 2000
- */
-
-#define nil ((void*)0)
-
-#include <minix/paths.h>
-#include <net/if_ether.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 int lwip;
-
-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);
+++ /dev/null
-/* 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->op= htons(ARP_REQUEST);
- arp->hln= 6;
- arp->pln= 4;
-
- 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. */
- u32_t *data;
- 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);
- data = (u32_t *) icmp->ih_dun.uhd_data;
- data[0] = np->gateway;
- 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;
-}
+++ /dev/null
-/* 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 <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 <arpa/inet.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, (struct in_addr *)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, (struct in_addr *)&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(*(struct in_addr *)&addr), n);
- if (n == -1) strcpy(strchr(result, '/')+1,
- inet_ntoa(*(struct in_addr *)&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= (char *)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(*(struct in_addr *)&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);
- }
-}
#define _PATH_SYSTEM_CONF_DIR "/etc/system.conf.d"
#define _PATH_SYSTEM_CONF_PKG_DIR "/usr/pkg/etc/system.conf.d"
-#define _PATH_DHCPCONF "/etc/dhcp.conf"
-#define _PATH_DHCPPID "/usr/run/dhcpd.pid"
-#define _PATH_DHCPCACHE "/usr/adm/dhcp.cache"
-#define _PATH_DHCPPOOL "/usr/adm/dhcp.pool"
-
#define _PATH_RAMDISK "/dev/ram"
#define _PATH_DRIVERS "/service"
+++ /dev/null
-/* dhcp_gettag() Author: Kees J. Bot
- * 1 Dec 2000
- */
-#define nil ((void*)0)
-#include <stddef.h>
-#include <string.h>
-#include <sys/types.h>
-#include <net/hton.h>
-#include <net/gen/in.h>
-#include <net/gen/dhcp.h>
-
-#define arraysize(a) (sizeof(a) / sizeof((a)[0]))
-
-int dhcp_gettag(dhcp_t *dp, int searchtag, u8_t **pdata, size_t *plen)
-{
- /* Find a tag in the options field, or possibly in the file or sname
- * fields. Return true iff found, and return the data and/or length if
- * their pointers are non-null.
- */
- u8_t *p;
- u8_t *optfield[3];
- size_t optlen[3];
- int i, tag, len;
-
- /* The DHCP magic number must be correct, or no tags. */
- if (dp->magic != DHCP_MAGIC) return 0;
-
- optfield[0]= dp->options;
- optlen[0]= arraysize(dp->options);
- optfield[1]= dp->file;
- optlen[1]= 0; /* Unknown if used for options yet. */
- optfield[2]= dp->sname;
- optlen[2]= 0;
-
- for (i= 0; i < 3; i++) {
- p= optfield[i];
- while (p < optfield[i] + optlen[i]) {
- tag= *p++;
- if (tag == 255) break;
- len= tag == 0 ? 0 : *p++;
- if (tag == searchtag) {
- if (pdata != nil) *pdata= p;
- if (plen != nil) *plen= len;
- return 1;
- }
- if (tag == DHCP_TAG_OVERLOAD) {
- /* There are also options in the file or sname field. */
- if (*p & 1) optlen[1]= arraysize(dp->file);
- if (*p & 2) optlen[1]= arraysize(dp->sname);
- }
- p += len;
- }
- }
- return 0;
-}
+++ /dev/null
-/* dhcp_init(), dhcp_settag() Author: Kees J. Bot
- * 1 Dec 2000
- */
-#define nil ((void*)0)
-#include <stddef.h>
-#include <string.h>
-#include <sys/types.h>
-#include <net/hton.h>
-#include <net/gen/in.h>
-#include <net/gen/dhcp.h>
-
-#define arraysize(a) (sizeof(a) / sizeof((a)[0]))
-#define arraylimit(a) ((a) + arraysize(a))
-
-void dhcp_init(dhcp_t *dp)
-{
- /* Initialize a DHCP packet. */
- memset(dp, 0, offsetof(dhcp_t, magic));
- dp->magic= DHCP_MAGIC;
- memset(dp->options, 255, sizeof(dp->options));
-}
-
-int dhcp_settag(dhcp_t *dp, int tag, void *data, size_t len)
-{
- /* Add a tag to a DHCP packet. No padding. Only do the options field.
- * (This is Minix, we don't need megabytes of silly bits of data.)
- * The length may be zero to delete a tag.
- */
- u8_t *p;
- int n;
-
- if (tag <= 0 || tag >= 255) return 0;
-
- for (p= dp->options; p < arraylimit(dp->options) && *p != 255; p += n) {
- n= 1 + 1 + p[1];
- if (*p == tag) {
- /* The tag is already there, remove it so it gets replaced. */
- memmove(p, p + n, arraylimit(dp->options) - (p + n));
- memset(arraylimit(dp->options) - n, 255, n);
- n= 0;
- }
- }
-
- /* Add tag. */
- if (len == 0) {
- /* We're merely deleting a tag. */
- } else
- if (p + 1 + 1 + len <= arraylimit(dp->options)) {
- *p++ = tag;
- *p++ = len;
- memcpy(p, data, len);
- } else {
- /* Oops, it didn't fit? Is this really Minix??? */
- return 0;
- }
- return 1;
-}
.PP
A generic configuration file can be read with the functions described in
.BR configfile (3).
-.SH EXAMPLES
-Have a look at
-.BR /etc/dhcp.conf .
.SH "SEE ALSO"
.BR configfile (3).
.SH NOTES