xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.lib/in.dhcpd/tests/test_client.c (revision 1914:8a8c5f225b1b)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*1914Scasper  * Common Development and Distribution License (the "License").
6*1914Scasper  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*1914Scasper  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include <stdio.h>
29*1914Scasper #include <stdio_ext.h>
300Sstevel@tonic-gate #include <stdlib.h>
310Sstevel@tonic-gate #include <unistd.h>
320Sstevel@tonic-gate #include <ctype.h>
330Sstevel@tonic-gate #include <string.h>
340Sstevel@tonic-gate #include <syslog.h>
350Sstevel@tonic-gate #include <signal.h>
360Sstevel@tonic-gate #include <time.h>
370Sstevel@tonic-gate #include <limits.h>
380Sstevel@tonic-gate #include <sys/resource.h>
390Sstevel@tonic-gate #include <sys/fcntl.h>
400Sstevel@tonic-gate #include <sys/types.h>
410Sstevel@tonic-gate #include <fcntl.h>
420Sstevel@tonic-gate #include <sys/resource.h>
430Sstevel@tonic-gate #include <sys/stat.h>
440Sstevel@tonic-gate #include <sys/systeminfo.h>
450Sstevel@tonic-gate #include <sys/socket.h>
460Sstevel@tonic-gate #include <sys/sockio.h>
470Sstevel@tonic-gate #include <net/if.h>
480Sstevel@tonic-gate #include <netinet/in.h>
490Sstevel@tonic-gate #include <arpa/inet.h>
500Sstevel@tonic-gate #include <errno.h>
510Sstevel@tonic-gate #include <sys/stropts.h>
520Sstevel@tonic-gate #include <netinet/dhcp.h>
530Sstevel@tonic-gate #include <dhcp_impl.h>
540Sstevel@tonic-gate #include <synch.h>
550Sstevel@tonic-gate #include <netdb.h>
560Sstevel@tonic-gate #include <locale.h>
570Sstevel@tonic-gate #include <mtmalloc.h>
580Sstevel@tonic-gate #include <tnf/probe.h>
590Sstevel@tonic-gate #include <libinetutil.h>
600Sstevel@tonic-gate 
610Sstevel@tonic-gate struct client {
620Sstevel@tonic-gate 	thread_t	id;
630Sstevel@tonic-gate 	PKT_LIST	*pktlistp;
640Sstevel@tonic-gate 	cond_t		cv;
650Sstevel@tonic-gate 	cond_t		acv;
660Sstevel@tonic-gate 	mutex_t		mtx;
670Sstevel@tonic-gate 	int		proto;
680Sstevel@tonic-gate 	uchar_t		chaddr[20];
690Sstevel@tonic-gate 	char		chost[40];
700Sstevel@tonic-gate 	int		hlen;
710Sstevel@tonic-gate 	uint_t		xid;
720Sstevel@tonic-gate 	int		flags;
730Sstevel@tonic-gate 	time_t		ltime;
740Sstevel@tonic-gate 	int		state;
750Sstevel@tonic-gate };
760Sstevel@tonic-gate 
770Sstevel@tonic-gate #define	CLIENT_BUSY		0x1
780Sstevel@tonic-gate #define	CLIENT_FIRSTTIME	0x2
790Sstevel@tonic-gate 
800Sstevel@tonic-gate ushort_t	port_offset = 0;	/* offset to port for multiple server */
810Sstevel@tonic-gate int		fast = 0;		/* higher load */
820Sstevel@tonic-gate int		bound = 0;		/* only broadcast on given interface */
830Sstevel@tonic-gate int		lrecv = 1;		/* only receive on given interface */
840Sstevel@tonic-gate static struct in_addr relay;		/* spoof being a relay agent */
850Sstevel@tonic-gate static struct sockaddr_in from, relfrom;
860Sstevel@tonic-gate static int clients, s, srelay = -1;
870Sstevel@tonic-gate static struct client *clientsp;
880Sstevel@tonic-gate 
890Sstevel@tonic-gate static PKT request;
900Sstevel@tonic-gate static char ifname[IFNAMSIZ];
910Sstevel@tonic-gate static int startindex;
920Sstevel@tonic-gate static mutex_t go_mtx;
930Sstevel@tonic-gate static cond_t go_cv;
940Sstevel@tonic-gate static boolean_t time_to_go;
950Sstevel@tonic-gate static int release_time = 0;
960Sstevel@tonic-gate static int desynch = 1;
970Sstevel@tonic-gate static double avg = 0;
980Sstevel@tonic-gate static timespec_t avgslp;
990Sstevel@tonic-gate static volatile ulong_t tops, otops;
1000Sstevel@tonic-gate static volatile ulong_t minops[6];
1010Sstevel@tonic-gate static volatile time_t mintim[6];
1020Sstevel@tonic-gate static volatile int minind;
1030Sstevel@tonic-gate long sample_time = 10L;
1040Sstevel@tonic-gate long nsamples = 2;
1050Sstevel@tonic-gate 
1060Sstevel@tonic-gate static volatile ulong_t ops_outstanding;
1070Sstevel@tonic-gate static time_t start, ostart;
1080Sstevel@tonic-gate int verbose = 0;
1090Sstevel@tonic-gate int dohost = 0;
1100Sstevel@tonic-gate int randcl = 0;
1110Sstevel@tonic-gate int randhlen = 0;
1120Sstevel@tonic-gate int randerr = 0;
1130Sstevel@tonic-gate int dos = 0;
1140Sstevel@tonic-gate int dofork = 0;
1150Sstevel@tonic-gate int printid = 0;
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate static time_t ltime;
1180Sstevel@tonic-gate static struct lifreq lifr;
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate static void corrupt(char *, int);
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate static void
dhcpmsgtype(uchar_t pkt,char * buf)1230Sstevel@tonic-gate dhcpmsgtype(uchar_t pkt, char *buf)
1240Sstevel@tonic-gate {
1250Sstevel@tonic-gate 	char	*p;
1260Sstevel@tonic-gate 
1270Sstevel@tonic-gate 	switch (pkt) {
1280Sstevel@tonic-gate 	case DISCOVER:
1290Sstevel@tonic-gate 		p = "DISCOVER";
1300Sstevel@tonic-gate 		break;
1310Sstevel@tonic-gate 	case OFFER:
1320Sstevel@tonic-gate 		p = "OFFER";
1330Sstevel@tonic-gate 		break;
1340Sstevel@tonic-gate 	case REQUEST:
1350Sstevel@tonic-gate 		p = "REQUEST";
1360Sstevel@tonic-gate 		break;
1370Sstevel@tonic-gate 	case DECLINE:
1380Sstevel@tonic-gate 		p = "DECLINE";
1390Sstevel@tonic-gate 		break;
1400Sstevel@tonic-gate 	case ACK:
1410Sstevel@tonic-gate 		p = "ACK";
1420Sstevel@tonic-gate 		break;
1430Sstevel@tonic-gate 	case NAK:
1440Sstevel@tonic-gate 		p = "NAK";
1450Sstevel@tonic-gate 		break;
1460Sstevel@tonic-gate 	case RELEASE:
1470Sstevel@tonic-gate 		p = "RELEASE";
1480Sstevel@tonic-gate 		break;
1490Sstevel@tonic-gate 	case INFORM:
1500Sstevel@tonic-gate 		p = "INFORM";
1510Sstevel@tonic-gate 		break;
1520Sstevel@tonic-gate 	default:
1530Sstevel@tonic-gate 		p = "UNKNOWN";
1540Sstevel@tonic-gate 		break;
1550Sstevel@tonic-gate 	}
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate 	(void) strcpy(buf, p);
1580Sstevel@tonic-gate }
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate static int
closeif(int ms,char * cifname,struct sockaddr_in * myip,thread_t myself)1610Sstevel@tonic-gate closeif(int ms, char *cifname, struct sockaddr_in *myip, thread_t myself)
1620Sstevel@tonic-gate {
1630Sstevel@tonic-gate 	struct ifreq ifr;
1640Sstevel@tonic-gate 	int error = 0;
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate 	(void) strcpy(ifr.ifr_name, cifname);
1670Sstevel@tonic-gate 	if (ioctl(ms, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
1680Sstevel@tonic-gate 		(void) fprintf(stderr,
1690Sstevel@tonic-gate 		    "Client %04d - can't get interface flags on %s\n", myself,
1700Sstevel@tonic-gate 		    cifname);
1710Sstevel@tonic-gate 		error = 7;
1720Sstevel@tonic-gate 	}
1730Sstevel@tonic-gate 	ifr.ifr_flags &= ~IFF_UP;
1740Sstevel@tonic-gate 	if (ioctl(ms, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) {
1750Sstevel@tonic-gate 		(void) fprintf(stderr,
1760Sstevel@tonic-gate 		    "Client %04d - can't set interface flags on %s\n", myself,
1770Sstevel@tonic-gate 		    cifname);
1780Sstevel@tonic-gate 		error = 7;
1790Sstevel@tonic-gate 	}
1800Sstevel@tonic-gate 	myip->sin_addr.s_addr = htonl(INADDR_ANY);
1810Sstevel@tonic-gate 	ifr.ifr_addr = *(struct sockaddr *)myip;
1820Sstevel@tonic-gate 	if (ioctl(ms, SIOCSIFADDR, (caddr_t)&ifr)) {
1830Sstevel@tonic-gate 		(void) fprintf(stderr,
1840Sstevel@tonic-gate 		    "Client %04d - Can't unset address on %s\n", myself,
1850Sstevel@tonic-gate 		    cifname);
1860Sstevel@tonic-gate 		error = 8;
1870Sstevel@tonic-gate 	}
1880Sstevel@tonic-gate 	(void) close(ms);
1890Sstevel@tonic-gate 	return (error);
1900Sstevel@tonic-gate }
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate static void *
client(void * args)1930Sstevel@tonic-gate client(void *args)
1940Sstevel@tonic-gate {
1950Sstevel@tonic-gate 	PKT crequest, *irequestp;
1960Sstevel@tonic-gate 	PKT_LIST *bp = NULL, *wbp, *twbp;
1970Sstevel@tonic-gate 	struct client *mep = (struct client *)args;
1980Sstevel@tonic-gate 	time_t retry_time = 2, lease, sleep_time = 0;
1990Sstevel@tonic-gate 	uchar_t *endp;
2000Sstevel@tonic-gate 	boolean_t	done, config, timeout;
2010Sstevel@tonic-gate 	int nstate, ms = -1;
2020Sstevel@tonic-gate 	DHCP_OPT *optp, *unused_optp;
2030Sstevel@tonic-gate 	timespec_t ts, tr;
2040Sstevel@tonic-gate 	int error = 0;
2050Sstevel@tonic-gate 	thread_t myself = thr_self();
2060Sstevel@tonic-gate 	struct sockaddr_in to, myip, maskip;
2070Sstevel@tonic-gate 	struct in_addr serverip;
2080Sstevel@tonic-gate 	time_t start_time, expired = 0;
2090Sstevel@tonic-gate 	char	cid[BUFSIZ];
2100Sstevel@tonic-gate 	char	cifname[IFNAMSIZ];
2110Sstevel@tonic-gate 	char		host[40];
2120Sstevel@tonic-gate 	char		domain[40];
2130Sstevel@tonic-gate 	char p[30], np[30];
2140Sstevel@tonic-gate 	struct ifreq ifr;
2150Sstevel@tonic-gate 	int moldy;
2160Sstevel@tonic-gate 	int i;
2170Sstevel@tonic-gate 	uint_t cidlen;
2180Sstevel@tonic-gate 	char		*domainp;
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate forever:
2210Sstevel@tonic-gate 	if (bp) {
2220Sstevel@tonic-gate 		(void) free(bp->pkt);
2230Sstevel@tonic-gate 		(void) free(bp);
2240Sstevel@tonic-gate 		bp = NULL;
2250Sstevel@tonic-gate 	}
2260Sstevel@tonic-gate 	if (!time_to_go) {
2270Sstevel@tonic-gate 		(void) mutex_lock(&mep->mtx);
2280Sstevel@tonic-gate 		mep->flags &= ~CLIENT_BUSY;
2290Sstevel@tonic-gate 		if (mep->flags & CLIENT_FIRSTTIME) {
2300Sstevel@tonic-gate 			mep->flags &= ~CLIENT_FIRSTTIME;
2310Sstevel@tonic-gate 		} else {
2320Sstevel@tonic-gate 			tops++;
2330Sstevel@tonic-gate 			ops_outstanding--;
2340Sstevel@tonic-gate 		}
2350Sstevel@tonic-gate 		if (avg)
2360Sstevel@tonic-gate 			(void) cond_wait(&mep->acv, &mep->mtx);
2370Sstevel@tonic-gate 		mep->flags |= CLIENT_BUSY;
2380Sstevel@tonic-gate 		mep->ltime = time(NULL);
2390Sstevel@tonic-gate 		ops_outstanding++;
2400Sstevel@tonic-gate 		(void) mutex_unlock(&mep->mtx);
2410Sstevel@tonic-gate 	}
2420Sstevel@tonic-gate 	if (desynch)
2430Sstevel@tonic-gate 		(void) sleep((desynch & myself) + 3);	/* desynch clients */
2440Sstevel@tonic-gate 	if (verbose == 1)
2450Sstevel@tonic-gate 		(void) fprintf(stdout, "Client %04d - started.\n", myself);
2460Sstevel@tonic-gate 	start_time = time(NULL);
2470Sstevel@tonic-gate 	(void) sprintf(cifname, "%s:%d", ifname, startindex + myself);
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate 	/* reset client addr each time */
2500Sstevel@tonic-gate 	if (relay.s_addr != INADDR_ANY) {
2510Sstevel@tonic-gate 		to.sin_addr.s_addr = relay.s_addr;
2520Sstevel@tonic-gate 	} else {
2530Sstevel@tonic-gate 		to.sin_addr.s_addr = INADDR_BROADCAST;
2540Sstevel@tonic-gate 	}
2550Sstevel@tonic-gate 	to.sin_port = htons(IPPORT_BOOTPS + port_offset);
2560Sstevel@tonic-gate 	to.sin_family = AF_INET;
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate 	domain[0] = host[0] = NULL;
2590Sstevel@tonic-gate 	if (randcl) {
2600Sstevel@tonic-gate 		/* Further randomize. */
2610Sstevel@tonic-gate 		if (randhlen > 0) {
2620Sstevel@tonic-gate 			mep->hlen = randhlen;
2630Sstevel@tonic-gate 		}
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate 		for (i = 3; i < mep->hlen; i++) {
2660Sstevel@tonic-gate 			mep->chaddr[i] = random() & 0xff;
2670Sstevel@tonic-gate 		}
2680Sstevel@tonic-gate 	}
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate 	(void) memcpy(&crequest, &request, sizeof (request));
2710Sstevel@tonic-gate 	(void) memcpy(crequest.chaddr, mep->chaddr, mep->hlen);
2720Sstevel@tonic-gate 	crequest.hlen = mep->hlen;
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate 	if (mep->proto) {
2760Sstevel@tonic-gate 		mep->state = DISCOVER;
2770Sstevel@tonic-gate 		optp = (DHCP_OPT *) & crequest.options[3];	/* skip TYPE */
2780Sstevel@tonic-gate 		optp->code = CD_CLIENT_ID;
2790Sstevel@tonic-gate 		optp->len = mep->hlen + 1;
2800Sstevel@tonic-gate 		optp->value[0] = 0x01;
2810Sstevel@tonic-gate 		(void) memcpy(&optp->value[1], mep->chaddr, mep->hlen);
2820Sstevel@tonic-gate 		cidlen = sizeof (cid);
2830Sstevel@tonic-gate 		(void) octet_to_hexascii(optp->value, mep->hlen + 1, cid,
2840Sstevel@tonic-gate 		    &cidlen);
2850Sstevel@tonic-gate 		unused_optp = (DHCP_OPT *) & optp->value[mep->hlen + 1];
2860Sstevel@tonic-gate 	} else {
2870Sstevel@tonic-gate 		mep->state = 0;
2880Sstevel@tonic-gate 		cidlen = sizeof (cid);
2890Sstevel@tonic-gate 		(void) octet_to_hexascii(mep->chaddr, mep->hlen, cid, &cidlen);
2900Sstevel@tonic-gate 		unused_optp = (DHCP_OPT *)&crequest.options[3]; /* skip TYPE */
2910Sstevel@tonic-gate 	}
2920Sstevel@tonic-gate 
2930Sstevel@tonic-gate 	/* Use global descriptor at first */
2940Sstevel@tonic-gate 	ms = s;
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate 	myip.sin_addr.s_addr = htonl(INADDR_ANY);
2970Sstevel@tonic-gate 	done = B_FALSE;
2980Sstevel@tonic-gate 	config = B_FALSE;
2990Sstevel@tonic-gate 	do {
3000Sstevel@tonic-gate 		timeout = B_FALSE;
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate 		TNF_PROBE_2(client,
3030Sstevel@tonic-gate 			    "client",
3040Sstevel@tonic-gate 			    "client%debug 'in func client'",
3050Sstevel@tonic-gate 			    tnf_ulong, state, mep->state,
3060Sstevel@tonic-gate 			    tnf_string, cid, (char *)cid);
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate 		if (time_to_go) {
3090Sstevel@tonic-gate 			if (mep->state == ACK) {
3100Sstevel@tonic-gate 				mep->state = RELEASE;
3110Sstevel@tonic-gate 				if (verbose == 1)
3120Sstevel@tonic-gate 					(void) fprintf(stderr,
3130Sstevel@tonic-gate 					    "Client %04d - RELEASEing %s\n",
3140Sstevel@tonic-gate 					    myself, inet_ntoa(myip.sin_addr));
3150Sstevel@tonic-gate 				else if (verbose == 2)
3160Sstevel@tonic-gate 					fprintf(stderr, "[%d %s]",
3170Sstevel@tonic-gate 						clientsp[i].id,
3180Sstevel@tonic-gate 						inet_ntoa(myip.sin_addr));
3190Sstevel@tonic-gate 				optp = (DHCP_OPT *) crequest.options;
3200Sstevel@tonic-gate 				(void) memset((char *)unused_optp, 0,
3210Sstevel@tonic-gate 				    (int)((char *)&crequest.options[
3220Sstevel@tonic-gate 				    sizeof (crequest.options)] -
3230Sstevel@tonic-gate 				    (char *)unused_optp));
3240Sstevel@tonic-gate 				optp->value[0] = RELEASE;
3250Sstevel@tonic-gate 			} else {
3260Sstevel@tonic-gate 				done = B_TRUE;
3270Sstevel@tonic-gate 				if (verbose == 1)
3280Sstevel@tonic-gate 					(void) fprintf(stderr,
3290Sstevel@tonic-gate 					    "Client %04d - terminated.\n",
3300Sstevel@tonic-gate 					    myself);
3310Sstevel@tonic-gate 				break;
3320Sstevel@tonic-gate 			}
3330Sstevel@tonic-gate 		} else if (release_time || avg) {
3340Sstevel@tonic-gate 			if (mep->state == ACK) {
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate 				/* lru testing: don't release lease */
3370Sstevel@tonic-gate 				if (randcl & 0x2) {
3380Sstevel@tonic-gate 					done = B_FALSE;
3390Sstevel@tonic-gate 					mep->state = nstate = 0;
3400Sstevel@tonic-gate 					sleep_time = 0;
3410Sstevel@tonic-gate 					if (bp) {
3420Sstevel@tonic-gate 						(void) free(bp->pkt);
3430Sstevel@tonic-gate 						(void) free(bp);
3440Sstevel@tonic-gate 						bp = NULL;
3450Sstevel@tonic-gate 					}
3460Sstevel@tonic-gate 					goto forever;
3470Sstevel@tonic-gate 				}
3480Sstevel@tonic-gate 				mep->state = RELEASE;
3490Sstevel@tonic-gate 				if (verbose == 1)
3500Sstevel@tonic-gate 					(void) fprintf(stderr,
3510Sstevel@tonic-gate 					    "Client %04d - RELEASEing %s\n",
3520Sstevel@tonic-gate 					    myself, inet_ntoa(myip.sin_addr));
3530Sstevel@tonic-gate 				else if (verbose == 2)
3540Sstevel@tonic-gate 					fprintf(stderr, "[%d %s]",
3550Sstevel@tonic-gate 						clientsp[i].id,
3560Sstevel@tonic-gate 						inet_ntoa(myip.sin_addr));
3570Sstevel@tonic-gate 				optp = (DHCP_OPT *) crequest.options;
3580Sstevel@tonic-gate 				(void) memset((char *)unused_optp, 0,
3590Sstevel@tonic-gate 				    (int)((char *)&crequest.options[
3600Sstevel@tonic-gate 				    sizeof (crequest.options)] -
3610Sstevel@tonic-gate 				    (char *)unused_optp));
3620Sstevel@tonic-gate 				optp->value[0] = RELEASE;
3630Sstevel@tonic-gate 			}
3640Sstevel@tonic-gate 		}
3650Sstevel@tonic-gate 		if (mep->state == REQUEST && expired < time(NULL)) {
3660Sstevel@tonic-gate 			/* drop back to INIT state. */
3670Sstevel@tonic-gate 			if (verbose == 1)
3680Sstevel@tonic-gate 				(void) fprintf(stderr,
3690Sstevel@tonic-gate 				    "Client %04d - Dropping back to INIT.\n",
3700Sstevel@tonic-gate 				    myself);
3710Sstevel@tonic-gate 			done = B_FALSE;
3720Sstevel@tonic-gate 			mep->state = nstate = 0;
3730Sstevel@tonic-gate 			sleep_time = 0;
3740Sstevel@tonic-gate 			if (bp) {
3750Sstevel@tonic-gate 				(void) free(bp->pkt);
3760Sstevel@tonic-gate 				(void) free(bp);
3770Sstevel@tonic-gate 				bp = NULL;
3780Sstevel@tonic-gate 			}
3790Sstevel@tonic-gate 			goto forever;
3800Sstevel@tonic-gate 		}
3810Sstevel@tonic-gate 		if (mep->state == RELEASE && !time_to_go) {
3820Sstevel@tonic-gate 			(void) mutex_lock(&mep->mtx);
3830Sstevel@tonic-gate 			tops++;
3840Sstevel@tonic-gate 			ops_outstanding--;
3850Sstevel@tonic-gate 			mep->flags &= ~CLIENT_BUSY;
3860Sstevel@tonic-gate 			if (avg)
3870Sstevel@tonic-gate 				(void) cond_wait(&mep->acv, &mep->mtx);
3880Sstevel@tonic-gate 			mep->ltime = time(NULL);
3890Sstevel@tonic-gate 			ops_outstanding++;
3900Sstevel@tonic-gate 			mep->flags |= CLIENT_BUSY;
3910Sstevel@tonic-gate 			(void) mutex_unlock(&mep->mtx);
3920Sstevel@tonic-gate 		}
3930Sstevel@tonic-gate 		/* Send request... */
3940Sstevel@tonic-gate 		crequest.secs = htons((ushort_t)(time(NULL) - start_time));
3950Sstevel@tonic-gate 		crequest.xid = htonl((myself << 2) + mep->xid++);
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate 		/* Randomly corrupt packets of a certain type. */
3980Sstevel@tonic-gate 		if ((randerr & 0xF) == mep->state || (randerr & 0xF) == 0xF) {
3990Sstevel@tonic-gate 			if (randerr & 0x10) {
4000Sstevel@tonic-gate 				/* Randomly corrupt entire request. */
4010Sstevel@tonic-gate 				corrupt((char *)&crequest, sizeof (crequest));
4020Sstevel@tonic-gate 			} else {
4030Sstevel@tonic-gate 				/* Randomly corrupt options. */
4040Sstevel@tonic-gate 				corrupt((char *)&crequest.options[3],
4050Sstevel@tonic-gate 				    sizeof (crequest.options) - 3);
4060Sstevel@tonic-gate 			}
4070Sstevel@tonic-gate 		}
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate 		if (sendto(ms, (char *)&crequest, sizeof (PKT), 0,
4100Sstevel@tonic-gate 		    (struct sockaddr *)&to, sizeof (struct sockaddr)) < 0) {
4110Sstevel@tonic-gate 			perror("Sendto");
4120Sstevel@tonic-gate 			error = 4;
4130Sstevel@tonic-gate 			thr_exit(&error);
4140Sstevel@tonic-gate 		}
4150Sstevel@tonic-gate 		if (mep->state == RELEASE) {
4160Sstevel@tonic-gate 			done = B_TRUE;
4170Sstevel@tonic-gate 			if (!avg) {
4180Sstevel@tonic-gate 				(void) strcpy(ifr.ifr_name, cifname);
4190Sstevel@tonic-gate 				if (ioctl(ms, SIOCGIFFLAGS,
4200Sstevel@tonic-gate 				    (caddr_t)&ifr) < 0) {
4210Sstevel@tonic-gate 					(void) fprintf(stderr, "Client %04d - "
4220Sstevel@tonic-gate 					    "can't get interface flags on %s\n",
4230Sstevel@tonic-gate 					    myself, cifname);
4240Sstevel@tonic-gate 					error = 7;
4250Sstevel@tonic-gate 				}
4260Sstevel@tonic-gate 				ifr.ifr_flags &= ~IFF_UP;
4270Sstevel@tonic-gate 				if (ioctl(ms, SIOCSIFFLAGS,
4280Sstevel@tonic-gate 				    (caddr_t)&ifr) < 0) {
4290Sstevel@tonic-gate 					(void) fprintf(stderr, "Client %04d - "
4300Sstevel@tonic-gate 					"can't set interface flags on %s\n",
4310Sstevel@tonic-gate 					myself, cifname);
4320Sstevel@tonic-gate 					error = 7;
4330Sstevel@tonic-gate 				}
4340Sstevel@tonic-gate 				myip.sin_addr.s_addr = htonl(INADDR_ANY);
4350Sstevel@tonic-gate 				ifr.ifr_addr = *(struct sockaddr *)&myip;
4360Sstevel@tonic-gate 				if (ioctl(ms, SIOCSIFADDR, (caddr_t)&ifr)) {
4370Sstevel@tonic-gate 					(void) fprintf(stderr, "Client %04d - "
4380Sstevel@tonic-gate 					    "Can't unset address on %s\n",
4390Sstevel@tonic-gate 					    myself, cifname);
4400Sstevel@tonic-gate 					error = 8;
4410Sstevel@tonic-gate 				}
4420Sstevel@tonic-gate 				(void) close(ms);
4430Sstevel@tonic-gate 			}
4440Sstevel@tonic-gate 			if (release_time || avg) {
4450Sstevel@tonic-gate 				done = B_FALSE;
4460Sstevel@tonic-gate 				mep->state = nstate = 0;
4470Sstevel@tonic-gate 				sleep_time = 0;
4480Sstevel@tonic-gate 				if (bp) {
4490Sstevel@tonic-gate 					(void) free(bp->pkt);
4500Sstevel@tonic-gate 					(void) free(bp);
4510Sstevel@tonic-gate 					bp = NULL;
4520Sstevel@tonic-gate 				}
4530Sstevel@tonic-gate 				goto forever;
4540Sstevel@tonic-gate 			}
4550Sstevel@tonic-gate 			break;
4560Sstevel@tonic-gate 		}
4570Sstevel@tonic-gate 		/* await reply */
4580Sstevel@tonic-gate moldy:
4590Sstevel@tonic-gate 		(void) mutex_lock(&mep->mtx);
4600Sstevel@tonic-gate 		ts.tv_sec = time(NULL) + retry_time;
4610Sstevel@tonic-gate 		ts.tv_nsec = 0;
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate 		while (mep->pktlistp == NULL)
4640Sstevel@tonic-gate 			if (cond_timedwait(&mep->cv, &mep->mtx, &ts) == ETIME) {
4650Sstevel@tonic-gate 				timeout = B_TRUE;
4660Sstevel@tonic-gate 				if (retry_time > 64)
4670Sstevel@tonic-gate 					retry_time = 2;
4680Sstevel@tonic-gate 				else if (fast)
4690Sstevel@tonic-gate 					retry_time += 2;
4700Sstevel@tonic-gate 				else
4710Sstevel@tonic-gate 					retry_time *= 2;
4720Sstevel@tonic-gate 				break;
4730Sstevel@tonic-gate 			} else {
4740Sstevel@tonic-gate 				if (time_to_go)
4750Sstevel@tonic-gate 					break;
4760Sstevel@tonic-gate 			}
4770Sstevel@tonic-gate 		(void) mutex_unlock(&mep->mtx);
4780Sstevel@tonic-gate 
4790Sstevel@tonic-gate 		if (time_to_go || timeout)
4800Sstevel@tonic-gate 			continue;
4810Sstevel@tonic-gate 
4820Sstevel@tonic-gate 		(void) mutex_lock(&mep->mtx);
4830Sstevel@tonic-gate 		moldy = 0;
4840Sstevel@tonic-gate 		if (bp) {
4850Sstevel@tonic-gate 			(void) free(bp->pkt);
4860Sstevel@tonic-gate 			(void) free(bp);
4870Sstevel@tonic-gate 		}
4880Sstevel@tonic-gate 		bp = NULL;
4890Sstevel@tonic-gate 		wbp = mep->pktlistp;
4900Sstevel@tonic-gate 		while (wbp != NULL) {
4910Sstevel@tonic-gate 			irequestp = wbp->pkt;
4920Sstevel@tonic-gate 			if (bp == NULL && irequestp->op == BOOTREPLY &&
4930Sstevel@tonic-gate 			    memcmp(&crequest.xid, &irequestp->xid,
4940Sstevel@tonic-gate 			    sizeof (crequest.xid)) == 0) {
4950Sstevel@tonic-gate 				bp = wbp;
4960Sstevel@tonic-gate 				wbp = wbp->next;
4970Sstevel@tonic-gate 				continue;
4980Sstevel@tonic-gate 			}
4990Sstevel@tonic-gate 			(void) free(wbp->pkt);
5000Sstevel@tonic-gate 			twbp = wbp;
5010Sstevel@tonic-gate 			wbp = wbp->next;
5020Sstevel@tonic-gate 			(void) free(twbp);
5030Sstevel@tonic-gate 			if (verbose == 1)
5040Sstevel@tonic-gate 				(void) fprintf(stderr,
5050Sstevel@tonic-gate 				"Client %04d - Moldy xid\n", myself);
5060Sstevel@tonic-gate 			moldy++;
5070Sstevel@tonic-gate 		}
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate 		mep->pktlistp = NULL;
5100Sstevel@tonic-gate 		(void) mutex_unlock(&mep->mtx);
5110Sstevel@tonic-gate 
5120Sstevel@tonic-gate 		if (bp == NULL) {
5130Sstevel@tonic-gate 			if (moldy > 0)
5140Sstevel@tonic-gate 				goto moldy;
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate 			continue;
5170Sstevel@tonic-gate 		}
5180Sstevel@tonic-gate 		irequestp = bp->pkt;
5190Sstevel@tonic-gate 
5200Sstevel@tonic-gate 		if (mep->proto) {
5210Sstevel@tonic-gate 			/*
5220Sstevel@tonic-gate 			 * Scan for CD_DHCP_TYPE, CD_SERVER_ID, and
5230Sstevel@tonic-gate 			 * CD_LEASE_TIME if proto.
5240Sstevel@tonic-gate 			 */
5250Sstevel@tonic-gate 			nstate = 0;
5260Sstevel@tonic-gate 			maskip.sin_addr.s_addr = serverip.s_addr = INADDR_ANY;
5270Sstevel@tonic-gate 			maskip.sin_family = AF_INET;
5280Sstevel@tonic-gate 			lease = (time_t)0;
5290Sstevel@tonic-gate 			optp = (DHCP_OPT *) irequestp->options;
5300Sstevel@tonic-gate 			endp = (uchar_t *)irequestp + bp->len;
5310Sstevel@tonic-gate 			host[0] = NULL;
5320Sstevel@tonic-gate 			while ((uchar_t *)optp < (uchar_t *)endp) {
5330Sstevel@tonic-gate 				switch (optp->code) {
5340Sstevel@tonic-gate 				case CD_HOSTNAME:
5350Sstevel@tonic-gate 					(void) strncpy(host,
5360Sstevel@tonic-gate 					    (const char *)optp->value,
5370Sstevel@tonic-gate 					    optp->len);
5380Sstevel@tonic-gate 					host[optp->len] = '\0';
5390Sstevel@tonic-gate 					break;
5400Sstevel@tonic-gate 				case CD_DNSDOMAIN:
5410Sstevel@tonic-gate 					(void) strncpy(domain,
5420Sstevel@tonic-gate 					    (const char *)optp->value,
5430Sstevel@tonic-gate 					    optp->len);
5440Sstevel@tonic-gate 					domain[optp->len] = '\0';
5450Sstevel@tonic-gate 					break;
5460Sstevel@tonic-gate 				case CD_DHCP_TYPE:
5470Sstevel@tonic-gate 					nstate = optp->value[0];
5480Sstevel@tonic-gate 					break;
5490Sstevel@tonic-gate 				case CD_SUBNETMASK:
5500Sstevel@tonic-gate 					(void) memcpy(&maskip.sin_addr,
5510Sstevel@tonic-gate 					    optp->value,
5520Sstevel@tonic-gate 					    sizeof (struct in_addr));
5530Sstevel@tonic-gate 					break;
5540Sstevel@tonic-gate 				case CD_SERVER_ID:
5550Sstevel@tonic-gate 					(void) memcpy(&serverip, optp->value,
5560Sstevel@tonic-gate 					    sizeof (struct in_addr));
5570Sstevel@tonic-gate 					break;
5580Sstevel@tonic-gate 				case CD_LEASE_TIME:
5590Sstevel@tonic-gate 					(void) memcpy(&lease, optp->value,
5600Sstevel@tonic-gate 					    sizeof (time_t));
5610Sstevel@tonic-gate 					lease = htonl(lease);
5620Sstevel@tonic-gate 					break;
5630Sstevel@tonic-gate 				}
5640Sstevel@tonic-gate 				optp = (DHCP_OPT *) & optp->value[optp->len];
5650Sstevel@tonic-gate 			}
5660Sstevel@tonic-gate 			if (mep->state == DISCOVER && nstate == OFFER) {
5670Sstevel@tonic-gate 				mep->state = REQUEST;
5680Sstevel@tonic-gate 				expired = time(NULL) + 60;
5690Sstevel@tonic-gate 				/*
5700Sstevel@tonic-gate 				 * Add in the requested IP address option and
5710Sstevel@tonic-gate 				 * server ID.
5720Sstevel@tonic-gate 				 */
5730Sstevel@tonic-gate 				optp = (DHCP_OPT *) crequest.options;
5740Sstevel@tonic-gate 				optp->value[0] = REQUEST;
5750Sstevel@tonic-gate 				optp = unused_optp; /* step over CD_DHCP_TYPE */
5760Sstevel@tonic-gate 				optp->code = CD_REQUESTED_IP_ADDR;
5770Sstevel@tonic-gate 				optp->len = sizeof (struct in_addr);
5780Sstevel@tonic-gate 				(void) memcpy(optp->value, &irequestp->yiaddr,
5790Sstevel@tonic-gate 				    sizeof (struct in_addr));
5800Sstevel@tonic-gate 				optp = (DHCP_OPT *) & optp->value[
5810Sstevel@tonic-gate 				    sizeof (struct in_addr)];
5820Sstevel@tonic-gate 				optp->code = CD_SERVER_ID;
5830Sstevel@tonic-gate 				optp->len = sizeof (struct in_addr);
5840Sstevel@tonic-gate 				(void) memcpy(optp->value, &serverip,
5850Sstevel@tonic-gate 				    sizeof (struct in_addr));
5860Sstevel@tonic-gate 				optp = (DHCP_OPT *) & optp->value[
5870Sstevel@tonic-gate 				    sizeof (struct in_addr)];
5880Sstevel@tonic-gate 				if (dohost == 0) {
5890Sstevel@tonic-gate 					if (bp) {
5900Sstevel@tonic-gate 						(void) free(bp->pkt);
5910Sstevel@tonic-gate 						(void) free(bp);
5920Sstevel@tonic-gate 						bp = NULL;
5930Sstevel@tonic-gate 					}
5940Sstevel@tonic-gate 					continue;
5950Sstevel@tonic-gate 				}
5960Sstevel@tonic-gate 
5970Sstevel@tonic-gate 				if (domain[0] == '\0' && host[0] != '\0' &&
5980Sstevel@tonic-gate 				    (domainp = strchr(host, '.')) != NULL) {
5990Sstevel@tonic-gate 					(void) snprintf(domain, sizeof (domain),
6000Sstevel@tonic-gate 					    "%s", domainp);
6010Sstevel@tonic-gate 				}
6020Sstevel@tonic-gate 
6030Sstevel@tonic-gate 				if (dohost & 0x2) {
6040Sstevel@tonic-gate 					cidlen = sizeof (cid);
6050Sstevel@tonic-gate 					(void) octet_to_hexascii(mep->chaddr,
6060Sstevel@tonic-gate 					    mep->hlen, host, &cidlen);
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 					if (domain[0])
6090Sstevel@tonic-gate 						(void) snprintf(host,
6100Sstevel@tonic-gate 						    sizeof (host), "%s.%s",
6110Sstevel@tonic-gate 						    cid, domain);
6120Sstevel@tonic-gate 					else
6130Sstevel@tonic-gate 						(void) snprintf(host,
6140Sstevel@tonic-gate 						    sizeof (host), "%s", cid);
6150Sstevel@tonic-gate 				}
6160Sstevel@tonic-gate 
6170Sstevel@tonic-gate 				optp->code = CD_HOSTNAME;
6180Sstevel@tonic-gate 				optp->len = strlen(host);
6190Sstevel@tonic-gate 				(void) memcpy(optp->value, host, strlen(host));
6200Sstevel@tonic-gate 				optp->value[strlen(host)] = '\0';
6210Sstevel@tonic-gate 				if (randcl && (random() & 0x1)) {
6220Sstevel@tonic-gate 					/* create a random name */
6230Sstevel@tonic-gate 					for (i = 0; i < optp->len &&
6240Sstevel@tonic-gate 						optp->value[i] != '.'; i++)
6250Sstevel@tonic-gate 						if (i & 1)
6260Sstevel@tonic-gate 						    optp->value[i] = '0' +
6270Sstevel@tonic-gate 							(mep->chaddr[i] & 0x7);
6280Sstevel@tonic-gate 						else
6290Sstevel@tonic-gate 						    optp->value[i] = 'a' +
6300Sstevel@tonic-gate 							(mep->chaddr[i] & 0x7);
6310Sstevel@tonic-gate 						strcpy((char *)mep->chost,
6320Sstevel@tonic-gate 						    (const char *)optp->value);
6330Sstevel@tonic-gate 				} else if (randcl && mep->chost[0]) {
6340Sstevel@tonic-gate 					/* use the previous one */
6350Sstevel@tonic-gate 					optp->len = strlen(mep->chost);
6360Sstevel@tonic-gate 					(void) memcpy(optp->value, mep->chost,
6370Sstevel@tonic-gate 					    strlen(mep->chost));
6380Sstevel@tonic-gate 					optp->value[strlen(mep->chost)] = '\0';
6390Sstevel@tonic-gate 				}
6400Sstevel@tonic-gate 				if (bp) {
6410Sstevel@tonic-gate 					(void) free(bp->pkt);
6420Sstevel@tonic-gate 					(void) free(bp);
6430Sstevel@tonic-gate 					bp = NULL;
6440Sstevel@tonic-gate 				}
6450Sstevel@tonic-gate 				continue;
6460Sstevel@tonic-gate 			} else if ((mep->state == REQUEST ||
6470Sstevel@tonic-gate 			    mep->state == ACK) && nstate == ACK) {
6480Sstevel@tonic-gate 				/*
6490Sstevel@tonic-gate 				 * we're bound. defend the lease. Add the
6500Sstevel@tonic-gate 				 * address to our interface. Due to the
6510Sstevel@tonic-gate 				 * service architecture of this program, we
6520Sstevel@tonic-gate 				 * can't unset the broadcast bit..
6530Sstevel@tonic-gate 				 */
6540Sstevel@tonic-gate 				mep->state = ACK;
6550Sstevel@tonic-gate 				nstate = 0;
6560Sstevel@tonic-gate 				retry_time = 2;
6570Sstevel@tonic-gate 				myip.sin_family = AF_INET;
6580Sstevel@tonic-gate 				myip.sin_addr.s_addr = irequestp->yiaddr.s_addr;
6590Sstevel@tonic-gate 				crequest.ciaddr.s_addr = myip.sin_addr.s_addr;
6600Sstevel@tonic-gate 				optp = unused_optp;
6610Sstevel@tonic-gate 				optp->code = CD_LEASE_TIME;
6620Sstevel@tonic-gate 				optp->len = sizeof (time_t);
6630Sstevel@tonic-gate 				(void) memcpy(optp->value, &lease,
6640Sstevel@tonic-gate 				    sizeof (time_t));
6650Sstevel@tonic-gate 				optp = (DHCP_OPT *)
6660Sstevel@tonic-gate 					& optp->value[sizeof (time_t)];
6670Sstevel@tonic-gate 				(void) memset((char *)optp, 0, (int)((char *)
6680Sstevel@tonic-gate 				    &crequest.options[
6690Sstevel@tonic-gate 				    sizeof (crequest.options)] -
6700Sstevel@tonic-gate 				    (char *)optp));
6710Sstevel@tonic-gate 				to.sin_addr.s_addr = serverip.s_addr;
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate 				if (lease == -1) {
6740Sstevel@tonic-gate 					done = B_TRUE;	/* permanent lease */
6750Sstevel@tonic-gate 					sleep_time = 0;
6760Sstevel@tonic-gate 				} else {
6770Sstevel@tonic-gate 					sleep_time = lease / 2;
6780Sstevel@tonic-gate 					lease = time(NULL) + lease;
6790Sstevel@tonic-gate 				}
6800Sstevel@tonic-gate 
6810Sstevel@tonic-gate 				if (release_time || avg) {
6820Sstevel@tonic-gate 					sleep_time = release_time;
6830Sstevel@tonic-gate 					done = B_FALSE;
6840Sstevel@tonic-gate 				}
6850Sstevel@tonic-gate 				if (verbose == 1)
6860Sstevel@tonic-gate 					(void) fprintf(stdout,
6870Sstevel@tonic-gate 					    "Client %04d(%s) - DHCP: %s == %s",
6880Sstevel@tonic-gate 					    myself, cid,
6890Sstevel@tonic-gate 					    inet_ntoa(myip.sin_addr),
6900Sstevel@tonic-gate 					    (lease == -1) ? "Forever\n" :
6910Sstevel@tonic-gate 					    ctime(&lease));
6920Sstevel@tonic-gate 				else if (verbose == 2)
6930Sstevel@tonic-gate 					fprintf(stderr, "(%d %s)", mep->id,
6940Sstevel@tonic-gate 						cid);
6950Sstevel@tonic-gate 				if (!config && !avg) {
6960Sstevel@tonic-gate 					/* Add mask and address */
6970Sstevel@tonic-gate 					if ((ms = socket(AF_INET, SOCK_DGRAM,
6980Sstevel@tonic-gate 					    0)) < 0) {
6990Sstevel@tonic-gate 						(void) fprintf(stderr,
7000Sstevel@tonic-gate 						    "Client %04d - can't open "
7010Sstevel@tonic-gate 						    "DGRAM socket.\n", myself);
7020Sstevel@tonic-gate 						error = 7;
7030Sstevel@tonic-gate 						break;
7040Sstevel@tonic-gate 					}
7050Sstevel@tonic-gate 					(void) strcpy(ifr.ifr_name, cifname);
7060Sstevel@tonic-gate 					ifr.ifr_addr =
7070Sstevel@tonic-gate 					    *(struct sockaddr *)&myip;
7080Sstevel@tonic-gate 					/*
7090Sstevel@tonic-gate 					 * XXXX: needed in on81
7100Sstevel@tonic-gate 					 * for initial
7110Sstevel@tonic-gate 					 * interface creation
7120Sstevel@tonic-gate 					 */
7130Sstevel@tonic-gate 					(void) (ioctl(ms, SIOCLIFADDIF,
7140Sstevel@tonic-gate 					    (caddr_t)&ifr));
7150Sstevel@tonic-gate 					(void) strcpy(ifr.ifr_name, cifname);
7160Sstevel@tonic-gate 					ifr.ifr_addr =
7170Sstevel@tonic-gate 					    *(struct sockaddr *)&maskip;
7180Sstevel@tonic-gate 					if (ioctl(ms, SIOCSIFNETMASK,
7190Sstevel@tonic-gate 					    (caddr_t)&ifr)) {
7200Sstevel@tonic-gate 						(void) fprintf(stderr,
7210Sstevel@tonic-gate 						    "Client %04d - Can't set "
7220Sstevel@tonic-gate 						    "netmask: %s on %s\n",
7230Sstevel@tonic-gate 						    myself,
7240Sstevel@tonic-gate 						    inet_ntoa(maskip.sin_addr),
7250Sstevel@tonic-gate 						    cifname);
7260Sstevel@tonic-gate 						error = 7;
7270Sstevel@tonic-gate 						(void) close(ms);
7280Sstevel@tonic-gate 						break;
7290Sstevel@tonic-gate 					}
7300Sstevel@tonic-gate 					if (ioctl(ms, SIOCGIFFLAGS,
7310Sstevel@tonic-gate 					    (caddr_t)&ifr) < 0) {
7320Sstevel@tonic-gate 						(void) fprintf(stderr,
7330Sstevel@tonic-gate 						    "Client %04d - can't get "
7340Sstevel@tonic-gate 						    "interface flags on %s\n",
7350Sstevel@tonic-gate 						    myself, cifname);
7360Sstevel@tonic-gate 						error = 7;
7370Sstevel@tonic-gate 						(void) close(ms);
7380Sstevel@tonic-gate 						break;
7390Sstevel@tonic-gate 					}
7400Sstevel@tonic-gate 					ifr.ifr_flags |= IFF_UP;
7410Sstevel@tonic-gate 					if (ioctl(ms, SIOCSIFFLAGS,
7420Sstevel@tonic-gate 					    (caddr_t)&ifr) < 0) {
7430Sstevel@tonic-gate 						(void) fprintf(stderr,
7440Sstevel@tonic-gate 						    "Client %04d - can't set "
7450Sstevel@tonic-gate 						    "interface flags on %s\n",
7460Sstevel@tonic-gate 						    myself, cifname);
7470Sstevel@tonic-gate 						error = 7;
7480Sstevel@tonic-gate 						(void) close(ms);
7490Sstevel@tonic-gate 						break;
7500Sstevel@tonic-gate 					}
7510Sstevel@tonic-gate 					ifr.ifr_addr =
7520Sstevel@tonic-gate 					    *(struct sockaddr *)&myip;
7530Sstevel@tonic-gate 					if (ioctl(ms, SIOCSIFADDR,
7540Sstevel@tonic-gate 					    (caddr_t)&ifr)) {
7550Sstevel@tonic-gate 						(void) fprintf(stderr,
7560Sstevel@tonic-gate 						    "Client %04d - Can't set "
7570Sstevel@tonic-gate 						    "address on %s\n",
7580Sstevel@tonic-gate 						    myself, cifname);
7590Sstevel@tonic-gate 						error = 8;
7600Sstevel@tonic-gate 						(void) close(ms);
7610Sstevel@tonic-gate 						break;
7620Sstevel@tonic-gate 					}
7630Sstevel@tonic-gate 					config = B_TRUE;
7640Sstevel@tonic-gate 				}
7650Sstevel@tonic-gate 				if (sleep_time != 0) {
7660Sstevel@tonic-gate 					/* Go to sleep for 50% of lease time. */
7670Sstevel@tonic-gate 					tr.tv_sec = time(NULL) + sleep_time;
7680Sstevel@tonic-gate 					if (verbose == 1)
7690Sstevel@tonic-gate 						(void) fprintf(stderr,
7700Sstevel@tonic-gate 						    "Client %04d - sleeping "
7710Sstevel@tonic-gate 						    "until %s", myself,
7720Sstevel@tonic-gate 						    ctime(&tr.tv_sec));
7730Sstevel@tonic-gate 					tr.tv_nsec = 0;
7740Sstevel@tonic-gate 					(void) mutex_lock(&go_mtx);
7750Sstevel@tonic-gate 					while (!time_to_go) {
7760Sstevel@tonic-gate 						if (cond_timedwait(&go_cv,
7770Sstevel@tonic-gate 						    &go_mtx, &tr) == ETIME)
7780Sstevel@tonic-gate 							break;
7790Sstevel@tonic-gate 					}
7800Sstevel@tonic-gate 					(void) mutex_unlock(&go_mtx);
7810Sstevel@tonic-gate 					if (verbose == 1)
7820Sstevel@tonic-gate 						(void) fprintf(stderr,
7830Sstevel@tonic-gate 						    "Client %04d - awake\n",
7840Sstevel@tonic-gate 						    myself);
7850Sstevel@tonic-gate 				}
7860Sstevel@tonic-gate 			} else if (mep->state == ACK && nstate == NAK) {
7870Sstevel@tonic-gate 				/* drop back to INIT state. */
7880Sstevel@tonic-gate 				if (verbose == 1) {
7890Sstevel@tonic-gate 					(void) fprintf(stdout, "Client %04d - "
7900Sstevel@tonic-gate 					    "DHCP: we got NAKed.\n", myself);
7910Sstevel@tonic-gate 					(void) fprintf(stderr, "Client %04d - "
7920Sstevel@tonic-gate 					    "Dropping back to INIT.\n", myself);
7930Sstevel@tonic-gate 				}
7940Sstevel@tonic-gate 				if (!avg)
7950Sstevel@tonic-gate 					(void) closeif(ms, cifname,
7960Sstevel@tonic-gate 						&myip, myself);
7970Sstevel@tonic-gate 				done = B_FALSE;
7980Sstevel@tonic-gate 				mep->state = nstate = 0;
7990Sstevel@tonic-gate 				sleep_time = 0;
8000Sstevel@tonic-gate 				if (bp) {
8010Sstevel@tonic-gate 					(void) free(bp->pkt);
8020Sstevel@tonic-gate 					(void) free(bp);
8030Sstevel@tonic-gate 					bp = NULL;
8040Sstevel@tonic-gate 				}
8050Sstevel@tonic-gate 				goto forever;
8060Sstevel@tonic-gate 			} else {
8070Sstevel@tonic-gate 				dhcpmsgtype(nstate, np);
8080Sstevel@tonic-gate 				dhcpmsgtype(mep->state, p);
8090Sstevel@tonic-gate 				(void) fprintf(stderr, "Client %04d - "
8100Sstevel@tonic-gate 				    "unexpected mesg: %s, when I'm in state: "
8110Sstevel@tonic-gate 				    "%s.\n", myself, np, p);
8120Sstevel@tonic-gate 				error = 9;
8130Sstevel@tonic-gate 				break;
8140Sstevel@tonic-gate 			}
8150Sstevel@tonic-gate 		} else {
8160Sstevel@tonic-gate 			done = B_TRUE;	/* BOOTP is done */
8170Sstevel@tonic-gate 			if (verbose == 1)
8180Sstevel@tonic-gate 				(void) fprintf(stdout,
8190Sstevel@tonic-gate 				    "Client %04d(%s) - BOOTP: %s\n", myself,
8200Sstevel@tonic-gate 				    cid, inet_ntoa(irequestp->yiaddr));
8210Sstevel@tonic-gate 			if (release_time || avg) {
8220Sstevel@tonic-gate 				done = B_FALSE;
8230Sstevel@tonic-gate 				mep->state = nstate = 0;
8240Sstevel@tonic-gate 				sleep_time = 0;
8250Sstevel@tonic-gate 				if (bp) {
8260Sstevel@tonic-gate 					(void) free(bp->pkt);
8270Sstevel@tonic-gate 					(void) free(bp);
8280Sstevel@tonic-gate 					bp = NULL;
8290Sstevel@tonic-gate 				}
8300Sstevel@tonic-gate 				goto forever;
8310Sstevel@tonic-gate 			}
8320Sstevel@tonic-gate 		}
8330Sstevel@tonic-gate 		if (bp) {
8340Sstevel@tonic-gate 			(void) free(bp->pkt);
8350Sstevel@tonic-gate 			(void) free(bp);
8360Sstevel@tonic-gate 			bp = NULL;
8370Sstevel@tonic-gate 		}
8380Sstevel@tonic-gate 	} while (!done);
8390Sstevel@tonic-gate 
8400Sstevel@tonic-gate 	if (!done) {
8410Sstevel@tonic-gate 		(void) fprintf(stderr,
8420Sstevel@tonic-gate 		    "Client %04d - %s: configuration failed.\n",
8430Sstevel@tonic-gate 		    myself, (mep->proto) ? "DHCP" : "BOOTP");
8440Sstevel@tonic-gate 	}
8450Sstevel@tonic-gate 	wbp = mep->pktlistp;
8460Sstevel@tonic-gate 	while (wbp != NULL) {
8470Sstevel@tonic-gate 		twbp = wbp->next;
8480Sstevel@tonic-gate 		if (wbp->pkt != NULL)
8490Sstevel@tonic-gate 			(void) free(wbp->pkt);
8500Sstevel@tonic-gate 		(void) free(wbp);
8510Sstevel@tonic-gate 		wbp = twbp;
8520Sstevel@tonic-gate 	}
8530Sstevel@tonic-gate 
8540Sstevel@tonic-gate 	thr_exit(&error);
8550Sstevel@tonic-gate 	return (NULL);		/* NOTREACHED */
8560Sstevel@tonic-gate }
8570Sstevel@tonic-gate 
8580Sstevel@tonic-gate /*
8590Sstevel@tonic-gate  * Never returns. Just loads client lists.
8600Sstevel@tonic-gate  */
8610Sstevel@tonic-gate static void *
service(void * args)8620Sstevel@tonic-gate service(void *args)
8630Sstevel@tonic-gate {
8640Sstevel@tonic-gate 	struct client *clientp = (struct client *)args;
8650Sstevel@tonic-gate 	PKT_LIST *bp, *wbp;
8660Sstevel@tonic-gate 	PKT *irequestp;
8670Sstevel@tonic-gate 	int error = 0;
8680Sstevel@tonic-gate 	struct pollfd pfd[2];
8690Sstevel@tonic-gate 	ulong_t *bufp;	/* ulong_t to force alignment */
8700Sstevel@tonic-gate 	int len, i;
8710Sstevel@tonic-gate 
8720Sstevel@tonic-gate 	pfd[0].fd = s;
8730Sstevel@tonic-gate 	pfd[0].events = POLLIN | POLLPRI;
8740Sstevel@tonic-gate 	if (relay.s_addr != INADDR_ANY) {
8750Sstevel@tonic-gate 		pfd[1].fd = srelay;
8760Sstevel@tonic-gate 		pfd[1].events = POLLIN | POLLPRI;
8770Sstevel@tonic-gate 	} else {
8780Sstevel@tonic-gate 		pfd[1].fd = -1;
8790Sstevel@tonic-gate 		pfd[1].events = 0;
8800Sstevel@tonic-gate 	}
8810Sstevel@tonic-gate 
8820Sstevel@tonic-gate 	for (;;) {
8830Sstevel@tonic-gate 		pfd[0].revents = 0;
8840Sstevel@tonic-gate 		pfd[1].revents = 0;
8850Sstevel@tonic-gate 		if (poll(pfd, (nfds_t)2, INFTIM) < 0) {
8860Sstevel@tonic-gate 			(void) fprintf(stderr, "Service - can't poll...\n");
8870Sstevel@tonic-gate 			error = 5;
8880Sstevel@tonic-gate 			break;
8890Sstevel@tonic-gate 		}
8900Sstevel@tonic-gate 		(void) mutex_lock(&go_mtx);
8910Sstevel@tonic-gate 		if (time_to_go) {
8920Sstevel@tonic-gate 			(void) fprintf(stderr, "Service - exiting...\n");
8930Sstevel@tonic-gate 			error = 0;
8940Sstevel@tonic-gate 			break;
8950Sstevel@tonic-gate 		}
8960Sstevel@tonic-gate 		(void) mutex_unlock(&go_mtx);
8970Sstevel@tonic-gate 		len = BUFSIZ * 2;
8980Sstevel@tonic-gate 		bufp = malloc(len);
8990Sstevel@tonic-gate 		if (pfd[0].revents)
9000Sstevel@tonic-gate 			len = recv(s, (char *)bufp, len, 0);
9010Sstevel@tonic-gate 		else {
9020Sstevel@tonic-gate 			len = recv(srelay, (char *)bufp, len, 0);
9030Sstevel@tonic-gate 		}
9040Sstevel@tonic-gate 
9050Sstevel@tonic-gate 		if (len < 0) {
9060Sstevel@tonic-gate 			(void) fprintf(stderr,
9070Sstevel@tonic-gate 			    "Service - can't receive - %s\n", strerror(errno));
9080Sstevel@tonic-gate 			error = 6;
9090Sstevel@tonic-gate 			break;
9100Sstevel@tonic-gate 		} else {
9110Sstevel@tonic-gate 			irequestp = (PKT *) bufp;
9120Sstevel@tonic-gate 			for (i = 0; i < clients; i++) {
9130Sstevel@tonic-gate 				if (memcmp(clientp[i].chaddr, irequestp->chaddr,
9140Sstevel@tonic-gate 				    clientp[i].hlen) == 0) {
9150Sstevel@tonic-gate 					(void) mutex_lock(&clientp[i].mtx);
9160Sstevel@tonic-gate 					bp = malloc(sizeof (PKT_LIST));
9170Sstevel@tonic-gate 					bp->pkt = irequestp;
9180Sstevel@tonic-gate 					bp->len = len;
9190Sstevel@tonic-gate 					if (verbose == 1)
9200Sstevel@tonic-gate 						(void) fprintf(stderr,
9210Sstevel@tonic-gate 						    "Service - received packet "
9220Sstevel@tonic-gate 						    "for thread %04d...\n",
9230Sstevel@tonic-gate 						    clientp[i].id);
9240Sstevel@tonic-gate 					if (clientp[i].pktlistp == NULL) {
9250Sstevel@tonic-gate 						clientp[i].pktlistp = bp;
9260Sstevel@tonic-gate 						bp->prev = NULL;
9270Sstevel@tonic-gate 					} else {
9280Sstevel@tonic-gate 						for (wbp = clientp[i].pktlistp;
9290Sstevel@tonic-gate 						    wbp->next != NULL;
9300Sstevel@tonic-gate 						    wbp = wbp->next)
9310Sstevel@tonic-gate 							/* null */;
9320Sstevel@tonic-gate 						wbp->next = bp;
9330Sstevel@tonic-gate 						bp->prev = wbp;
9340Sstevel@tonic-gate 					}
9350Sstevel@tonic-gate 					bp->next = NULL;
9360Sstevel@tonic-gate 					(void) cond_signal(&clientp[i].cv);
9370Sstevel@tonic-gate 					(void) mutex_unlock(&clientp[i].mtx);
9380Sstevel@tonic-gate 					break;
9390Sstevel@tonic-gate 				}
9400Sstevel@tonic-gate 			}
9410Sstevel@tonic-gate 			if (i >= clients)
9420Sstevel@tonic-gate 				free(bufp);
9430Sstevel@tonic-gate 		}
9440Sstevel@tonic-gate 	}
9450Sstevel@tonic-gate 	thr_exit(&error);
9460Sstevel@tonic-gate 	return (NULL);		/* NOTREACHED */
9470Sstevel@tonic-gate }
9480Sstevel@tonic-gate 
9490Sstevel@tonic-gate /* ARGSUSED */
9500Sstevel@tonic-gate static void *
sig_handle(void * arg)9510Sstevel@tonic-gate sig_handle(void *arg)
9520Sstevel@tonic-gate {
9530Sstevel@tonic-gate 	boolean_t leave = B_FALSE;
9540Sstevel@tonic-gate 	int sig;
9550Sstevel@tonic-gate 	sigset_t set;
9560Sstevel@tonic-gate 	char buf[SIG2STR_MAX];
9570Sstevel@tonic-gate 	int old, new, unstarted;
9580Sstevel@tonic-gate 	int i;
9590Sstevel@tonic-gate 	int oldi;
9600Sstevel@tonic-gate 	uint_t cidlen;
9610Sstevel@tonic-gate 	char cid[BUFSIZ];
9620Sstevel@tonic-gate 	int discover, offer, req, decline, ack, nak;
9630Sstevel@tonic-gate 	int release, inform, unknown;
9640Sstevel@tonic-gate 	int kicked;
9650Sstevel@tonic-gate 	ulong_t		minavg;
9660Sstevel@tonic-gate 	time_t		minstime;
9670Sstevel@tonic-gate 
9680Sstevel@tonic-gate 	(void) sigfillset(&set);
9690Sstevel@tonic-gate 
9700Sstevel@tonic-gate 	if (avg == 0) {
9710Sstevel@tonic-gate 		avgslp.tv_sec = sample_time;
9720Sstevel@tonic-gate 		avgslp.tv_nsec = 0L;
9730Sstevel@tonic-gate 	}
9740Sstevel@tonic-gate 	while (!leave) {
9750Sstevel@tonic-gate 		discover = offer = req = decline = ack = nak = 0;
9760Sstevel@tonic-gate 		release = inform = unknown = 0;
9770Sstevel@tonic-gate 		switch (sig = sigtimedwait(&set, NULL, &avgslp)) {
9780Sstevel@tonic-gate 		case SIGHUP:
9790Sstevel@tonic-gate 		case -1:
9800Sstevel@tonic-gate 			old = time(NULL);
9810Sstevel@tonic-gate 			new = unstarted = 0;
9820Sstevel@tonic-gate 			kicked = 0;
9830Sstevel@tonic-gate 			for (i = 0; i < clients; i++) {
9840Sstevel@tonic-gate 				/* Start next client at avgslp offset */
9850Sstevel@tonic-gate 				if (avg && kicked == 0 &&
9860Sstevel@tonic-gate 				    (clientsp[i].flags &
9870Sstevel@tonic-gate 				    (CLIENT_FIRSTTIME | CLIENT_BUSY)) == 0) {
9880Sstevel@tonic-gate 					(void) mutex_lock(&clientsp[i].mtx);
9890Sstevel@tonic-gate 					(void) cond_signal(&clientsp[i].acv);
9900Sstevel@tonic-gate 					(void) mutex_unlock(&clientsp[i].mtx);
9910Sstevel@tonic-gate 					kicked++;
9920Sstevel@tonic-gate 				}
9930Sstevel@tonic-gate 				switch (clientsp[i].state) {
9940Sstevel@tonic-gate 				case DISCOVER:
9950Sstevel@tonic-gate 					discover++;
9960Sstevel@tonic-gate 					break;
9970Sstevel@tonic-gate 				case OFFER:
9980Sstevel@tonic-gate 					offer++;
9990Sstevel@tonic-gate 					break;
10000Sstevel@tonic-gate 				case REQUEST:
10010Sstevel@tonic-gate 					req++;
10020Sstevel@tonic-gate 					break;
10030Sstevel@tonic-gate 				case DECLINE:
10040Sstevel@tonic-gate 					decline++;
10050Sstevel@tonic-gate 					break;
10060Sstevel@tonic-gate 				case ACK:
10070Sstevel@tonic-gate 					ack++;
10080Sstevel@tonic-gate 					break;
10090Sstevel@tonic-gate 				case NAK:
10100Sstevel@tonic-gate 					nak++;
10110Sstevel@tonic-gate 					break;
10120Sstevel@tonic-gate 				case RELEASE:
10130Sstevel@tonic-gate 					release++;
10140Sstevel@tonic-gate 					break;
10150Sstevel@tonic-gate 				case INFORM:
10160Sstevel@tonic-gate 					inform++;
10170Sstevel@tonic-gate 					break;
10180Sstevel@tonic-gate 				default:
10190Sstevel@tonic-gate 					unknown++;
10200Sstevel@tonic-gate 					break;
10210Sstevel@tonic-gate 				}
10220Sstevel@tonic-gate 				if (clientsp[i].ltime == NULL ||
10230Sstevel@tonic-gate 				    (clientsp[i].flags & CLIENT_BUSY) == 0)
10240Sstevel@tonic-gate 					unstarted++;
10250Sstevel@tonic-gate 				if (clientsp[i].ltime &&
10260Sstevel@tonic-gate 				    clientsp[i].ltime < old) {
10270Sstevel@tonic-gate 					old = clientsp[i].ltime;
10280Sstevel@tonic-gate 					oldi = i;
10290Sstevel@tonic-gate 				}
10300Sstevel@tonic-gate 				if (clientsp[i].ltime &&
10310Sstevel@tonic-gate 				    clientsp[i].ltime > new) {
10320Sstevel@tonic-gate 					new = clientsp[i].ltime;
10330Sstevel@tonic-gate 				}
10340Sstevel@tonic-gate 			}
10350Sstevel@tonic-gate 
10360Sstevel@tonic-gate 			if (time(NULL) < ltime + sample_time)
10370Sstevel@tonic-gate 				continue;
10380Sstevel@tonic-gate 			ltime = time(NULL);
10390Sstevel@tonic-gate 
10400Sstevel@tonic-gate 			if (start == 0) {
10410Sstevel@tonic-gate 				/* toss initial sample */
10420Sstevel@tonic-gate 				ostart = start = time(NULL);
10430Sstevel@tonic-gate 				otops = tops = 0;
10440Sstevel@tonic-gate 				minind = 0;
10450Sstevel@tonic-gate 			} else {
10460Sstevel@tonic-gate 				minops[minind] = tops - otops;
10470Sstevel@tonic-gate 				mintim[minind] = ostart;
10480Sstevel@tonic-gate 				otops = tops;
10490Sstevel@tonic-gate 				ostart = time(NULL);
10500Sstevel@tonic-gate 				minind = minind + 1 > nsamples - 1 ? 0 :
10510Sstevel@tonic-gate 				    minind + 1;
10520Sstevel@tonic-gate 				minstime = 0;
10530Sstevel@tonic-gate 				minavg = 0;
10540Sstevel@tonic-gate 				for (i = 0; i < nsamples; i++) {
10550Sstevel@tonic-gate 					if (mintim[i])
10560Sstevel@tonic-gate 						minavg += minops[i];
10570Sstevel@tonic-gate 					if (minstime == 0)
10580Sstevel@tonic-gate 						minstime = mintim[i];
10590Sstevel@tonic-gate 					else if (mintim[i] &&
10600Sstevel@tonic-gate 					    mintim[i] < minstime)
10610Sstevel@tonic-gate 						minstime = mintim[i];
10620Sstevel@tonic-gate 				}
10630Sstevel@tonic-gate 
10640Sstevel@tonic-gate 				cidlen = sizeof (cid);
10650Sstevel@tonic-gate 				(void) octet_to_hexascii(clientsp[oldi].chaddr,
10660Sstevel@tonic-gate 				clientsp[oldi].hlen, cid, &cidlen);
10670Sstevel@tonic-gate 				fprintf(stderr, "%9.9d: Totops %d Curr %d "
10680Sstevel@tonic-gate 				    "Persec %4.2f (%4.2f) Oldest %d (%d) "
10690Sstevel@tonic-gate 				    "Gap %d Free %d\n", time(NULL), tops,
10700Sstevel@tonic-gate 				    ops_outstanding,
10710Sstevel@tonic-gate 				    (double)tops / (double)(time(NULL) - start),
10720Sstevel@tonic-gate 				    (double)minavg / (double)(time(NULL)
10730Sstevel@tonic-gate 				    - minstime),
10740Sstevel@tonic-gate 				    time(NULL) - old, clientsp[oldi].id, cid,
10750Sstevel@tonic-gate 				    new - old, unstarted);
10760Sstevel@tonic-gate 				fprintf(stderr, "\tdiscov %d off %d req %d "
10770Sstevel@tonic-gate 				    "decl %d ack %d nak %d rel %d inf %d "
10780Sstevel@tonic-gate 				    "free/unknown %d\n", discover, offer, req,
10790Sstevel@tonic-gate 				    decline, ack, nak, release, inform,
10800Sstevel@tonic-gate 				    unknown);
10810Sstevel@tonic-gate 			}
10820Sstevel@tonic-gate 			break;
10830Sstevel@tonic-gate 		case SIGINT:
10840Sstevel@tonic-gate 			/* FALLTHRU */
10850Sstevel@tonic-gate 		case SIGTERM:
10860Sstevel@tonic-gate 			(void) sig2str(sig, buf);
10870Sstevel@tonic-gate 			(void) fprintf(stderr,
10880Sstevel@tonic-gate 			    "Signal: %s received...Exiting\n", buf);
10890Sstevel@tonic-gate 			(void) mutex_lock(&go_mtx);
10900Sstevel@tonic-gate 			time_to_go = B_TRUE;
10910Sstevel@tonic-gate 			(void) cond_broadcast(&go_cv);
10920Sstevel@tonic-gate 			(void) mutex_unlock(&go_mtx);
10930Sstevel@tonic-gate 			for (i = 0; i < clients; i++) {
10940Sstevel@tonic-gate 				(void) mutex_lock(&clientsp[i].mtx);
10950Sstevel@tonic-gate 				(void) cond_signal(&clientsp[i].acv);
10960Sstevel@tonic-gate 				(void) mutex_unlock(&clientsp[i].mtx);
10970Sstevel@tonic-gate 			}
10980Sstevel@tonic-gate 			leave = B_TRUE;
10990Sstevel@tonic-gate 			break;
11000Sstevel@tonic-gate 		default:
11010Sstevel@tonic-gate 			(void) sig2str(sig, buf);
11020Sstevel@tonic-gate 			(void) fprintf(stderr,
11030Sstevel@tonic-gate 			    "Signal: %s received...Ignoring\n", buf);
11040Sstevel@tonic-gate 			leave = B_FALSE;
11050Sstevel@tonic-gate 			break;
11060Sstevel@tonic-gate 		}
11070Sstevel@tonic-gate 	}
11080Sstevel@tonic-gate 	thr_exit((void *) NULL);
11090Sstevel@tonic-gate 	return (NULL);		/* NOTREACHED */
11100Sstevel@tonic-gate }
11110Sstevel@tonic-gate 
11120Sstevel@tonic-gate int
main(int argc,char * argv[])11130Sstevel@tonic-gate main(int argc, char *argv[])
11140Sstevel@tonic-gate {
11150Sstevel@tonic-gate 	boolean_t proto;
11160Sstevel@tonic-gate 	int i, j, threrror = 0, *threrrorp;
11170Sstevel@tonic-gate 	int sockoptbuf = 1;
11180Sstevel@tonic-gate 	register char *endp, *octet;
11190Sstevel@tonic-gate 	thread_t service_id, sig_id;
11200Sstevel@tonic-gate 	sigset_t set;
11210Sstevel@tonic-gate 	uint_t buf;
11220Sstevel@tonic-gate 	int slen;
11230Sstevel@tonic-gate 	socklen_t sslen = sizeof (slen);
11240Sstevel@tonic-gate 	unsigned int ifceno;
11250Sstevel@tonic-gate 	char cifname[IFNAMSIZ];
11260Sstevel@tonic-gate 	struct rlimit rl;
11270Sstevel@tonic-gate 
11280Sstevel@tonic-gate 	if (randcl)
11290Sstevel@tonic-gate 		srandom(time(NULL));
11300Sstevel@tonic-gate 
11310Sstevel@tonic-gate 	if (dofork) {
11320Sstevel@tonic-gate 		if (fork() != 0)
11330Sstevel@tonic-gate 			exit(0);
11340Sstevel@tonic-gate 	}
11350Sstevel@tonic-gate 	if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
11360Sstevel@tonic-gate 		(void) fprintf(stderr, "Cannot get open file limit: %s\n",
11370Sstevel@tonic-gate 		    strerror(errno));
11380Sstevel@tonic-gate 	}
11390Sstevel@tonic-gate 	/* handle cases where limit is infinity */
11400Sstevel@tonic-gate 	if (rl.rlim_cur == RLIM_INFINITY) {
11410Sstevel@tonic-gate 		rl.rlim_cur = (rl.rlim_max == RLIM_INFINITY) ?
11420Sstevel@tonic-gate 			OPEN_MAX : rl.rlim_max;
11430Sstevel@tonic-gate 	}
11440Sstevel@tonic-gate 	/* set NOFILE to unlimited */
11450Sstevel@tonic-gate 	rl.rlim_cur = rl.rlim_max = RLIM_INFINITY;
11460Sstevel@tonic-gate 	if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
11470Sstevel@tonic-gate 		(void) fprintf(stderr, "Cannot set open file limit: %s\n",
11480Sstevel@tonic-gate 		    strerror(errno));
11490Sstevel@tonic-gate 	}
1150*1914Scasper 	(void) enable_extended_FILE_stdio(-1, -1);
1151*1914Scasper 
11520Sstevel@tonic-gate 	if (argc < 5) {
11530Sstevel@tonic-gate 		(void) fprintf(stderr, "%s <interface> <ether_addr> <protocol> "
11540Sstevel@tonic-gate 		    "<clients> [time] [desynch] [avg] [relayaddr]\n", argv[0]);
11550Sstevel@tonic-gate 		return (1);
11560Sstevel@tonic-gate 	}
11570Sstevel@tonic-gate 	(void) strcpy(ifname, argv[1]);
11580Sstevel@tonic-gate 	(void) strcpy(cifname, argv[1]);
11590Sstevel@tonic-gate 	if ((endp = strchr(ifname, ':')) != NULL) {
11600Sstevel@tonic-gate 		*endp = '\0';
11610Sstevel@tonic-gate 		startindex = strtol(endp + 1, 0L, 0L);
11620Sstevel@tonic-gate 	}
11630Sstevel@tonic-gate 	if (strcasecmp(argv[3], "dhcp") == 0)
11640Sstevel@tonic-gate 		proto = B_TRUE;
11650Sstevel@tonic-gate 	else
11660Sstevel@tonic-gate 		proto = B_FALSE;
11670Sstevel@tonic-gate 
11680Sstevel@tonic-gate 	clients = atoi(argv[4]);
11690Sstevel@tonic-gate 
11700Sstevel@tonic-gate 	if (argc >= 6) {
11710Sstevel@tonic-gate 		release_time = atoi(argv[5]);
11720Sstevel@tonic-gate 	}
11730Sstevel@tonic-gate 	if (argc >= 7)
11740Sstevel@tonic-gate 		desynch = atoi(argv[6]);
11750Sstevel@tonic-gate 
11760Sstevel@tonic-gate 	if (argc >= 8) {
11770Sstevel@tonic-gate 		avg = atof(argv[7]);
11780Sstevel@tonic-gate 		if (avg > 0.0) {
11790Sstevel@tonic-gate 			avgslp.tv_sec = avg;
11800Sstevel@tonic-gate 			avgslp.tv_nsec = (avg -
11810Sstevel@tonic-gate 			    (double)((int)avg)) * 1000000000.0;
11820Sstevel@tonic-gate 		} else if (avg < 0.0) {
11830Sstevel@tonic-gate 			avgslp.tv_sec = abs((int)avg);
11840Sstevel@tonic-gate 			avgslp.tv_nsec = (avg + abs((double)((int)avg))) *
11850Sstevel@tonic-gate 			    1000000000.0;
11860Sstevel@tonic-gate 		}
11870Sstevel@tonic-gate 	}
11880Sstevel@tonic-gate 	if (argc >= 9)
11890Sstevel@tonic-gate 		relay.s_addr = inet_addr(argv[8]);
11900Sstevel@tonic-gate 
11910Sstevel@tonic-gate 	if (argc >= 10)
11920Sstevel@tonic-gate 		slen = strtol(argv[0], 0L, 0L);
11930Sstevel@tonic-gate 	else
11940Sstevel@tonic-gate 		slen = 1024 * 64;
11950Sstevel@tonic-gate 
11960Sstevel@tonic-gate 	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
11970Sstevel@tonic-gate 		perror("Socket");
11980Sstevel@tonic-gate 		return (1);
11990Sstevel@tonic-gate 	}
12000Sstevel@tonic-gate 	(void) setsockopt(s, SOL_SOCKET, SO_SNDBUF, &slen, sslen);
12010Sstevel@tonic-gate 	(void) setsockopt(s, SOL_SOCKET, SO_RCVBUF, &slen, sslen);
12020Sstevel@tonic-gate 
12030Sstevel@tonic-gate 	if (relay.s_addr == INADDR_ANY)
12040Sstevel@tonic-gate 		if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char *)&sockoptbuf,
12050Sstevel@tonic-gate 		    (int)sizeof (sockoptbuf)) < 0) {
12060Sstevel@tonic-gate 			perror("Setsockopt");
12070Sstevel@tonic-gate 			return (2);
12080Sstevel@tonic-gate 		}
12090Sstevel@tonic-gate 	if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
12100Sstevel@tonic-gate 	    (char *)&sockoptbuf, (int)sizeof (sockoptbuf)) < 0) {
12110Sstevel@tonic-gate 		perror("Setsockopt: REUSEADDR");
12120Sstevel@tonic-gate 		return (2);
12130Sstevel@tonic-gate 	}
12140Sstevel@tonic-gate 	if (relay.s_addr != INADDR_ANY) {
12150Sstevel@tonic-gate 		relfrom.sin_port = htons(IPPORT_BOOTPS + port_offset);
12160Sstevel@tonic-gate 		relfrom.sin_family = AF_INET;
12170Sstevel@tonic-gate 		relfrom.sin_addr.s_addr = INADDR_ANY;
12180Sstevel@tonic-gate 		relfrom.sin_port = htons(IPPORT_BOOTPS + port_offset);
12190Sstevel@tonic-gate 
12200Sstevel@tonic-gate 		(void) strncpy(lifr.lifr_name, cifname,
12210Sstevel@tonic-gate 		    sizeof (lifr.lifr_name));
12220Sstevel@tonic-gate 		if (lrecv) {
12230Sstevel@tonic-gate 			if (ioctl(s, SIOCGLIFADDR, (char *)&lifr) < 0) {
12240Sstevel@tonic-gate 			    (void) fprintf(stderr, "Warning: SIOCGLIFADDR: %s",
12250Sstevel@tonic-gate 				strerror(errno));
12260Sstevel@tonic-gate 			} else {
12270Sstevel@tonic-gate 				relfrom.sin_addr.s_addr =
12280Sstevel@tonic-gate 				    ((struct sockaddr_in *)
12290Sstevel@tonic-gate 				    &lifr.lifr_addr)->sin_addr.s_addr;
12300Sstevel@tonic-gate 			}
12310Sstevel@tonic-gate 		}
12320Sstevel@tonic-gate 
12330Sstevel@tonic-gate 		if ((srelay = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
12340Sstevel@tonic-gate 			perror("Socket");
12350Sstevel@tonic-gate 			return (1);
12360Sstevel@tonic-gate 		}
12370Sstevel@tonic-gate 		(void) setsockopt(srelay, SOL_SOCKET, SO_SNDBUF, &slen, sslen);
12380Sstevel@tonic-gate 		(void) setsockopt(srelay, SOL_SOCKET, SO_RCVBUF, &slen, sslen);
12390Sstevel@tonic-gate 
12400Sstevel@tonic-gate 		if (setsockopt(srelay, SOL_SOCKET, SO_REUSEADDR,
12410Sstevel@tonic-gate 		    (char *)&sockoptbuf, (int)sizeof (sockoptbuf)) < 0) {
12420Sstevel@tonic-gate 			perror("Setsockopt: REUSEADDR");
12430Sstevel@tonic-gate 			return (2);
12440Sstevel@tonic-gate 		}
12450Sstevel@tonic-gate 		if (bind(srelay, (struct sockaddr *)&relfrom,
12460Sstevel@tonic-gate 		    sizeof (relfrom)) < 0) {
12470Sstevel@tonic-gate 			perror("Bind");
12480Sstevel@tonic-gate 			return (3);
12490Sstevel@tonic-gate 		}
12500Sstevel@tonic-gate 		ifceno = if_nametoindex(cifname);
12510Sstevel@tonic-gate 		if (bound) {
12520Sstevel@tonic-gate 			if (setsockopt(s, IPPROTO_IP, IP_BOUND_IF,
12530Sstevel@tonic-gate 			    (char *)&ifceno, (int)sizeof (char *)) < 0) {
12540Sstevel@tonic-gate 				perror("Setsockopt bind");
12550Sstevel@tonic-gate 				return (3);
12560Sstevel@tonic-gate 			}
12570Sstevel@tonic-gate 		}
12580Sstevel@tonic-gate 	}
12590Sstevel@tonic-gate 	from.sin_family = AF_INET;
12600Sstevel@tonic-gate 	if (relay.s_addr != INADDR_ANY) {
12610Sstevel@tonic-gate 		from.sin_addr.s_addr =
12620Sstevel@tonic-gate 		    ((struct sockaddr_in *)&lifr.lifr_addr)->sin_addr.s_addr;
12630Sstevel@tonic-gate 	} else {
12640Sstevel@tonic-gate 		from.sin_addr.s_addr = INADDR_ANY;
12650Sstevel@tonic-gate 	}
12660Sstevel@tonic-gate 	from.sin_port = htons(IPPORT_BOOTPC + port_offset);
12670Sstevel@tonic-gate 
12680Sstevel@tonic-gate 	if (bind(s, (struct sockaddr *)&from, sizeof (from)) < 0) {
12690Sstevel@tonic-gate 		perror("Bind");
12700Sstevel@tonic-gate 		return (3);
12710Sstevel@tonic-gate 	}
12720Sstevel@tonic-gate 	ifceno = if_nametoindex(cifname);
12730Sstevel@tonic-gate 	if (bound) {
12740Sstevel@tonic-gate 		if (setsockopt(s, IPPROTO_IP, IP_BOUND_IF,
12750Sstevel@tonic-gate 		    (char *)&ifceno, (int)sizeof (char *)) < 0) {
12760Sstevel@tonic-gate 			perror("Setsockopt bind");
12770Sstevel@tonic-gate 			return (3);
12780Sstevel@tonic-gate 		}
12790Sstevel@tonic-gate 	}
12800Sstevel@tonic-gate 	request.op = 1;		/* BOOTP request */
12810Sstevel@tonic-gate 	request.htype = 1;	/* Ethernet */
12820Sstevel@tonic-gate 	request.hlen = 6;	/* Ethernet addr len */
12830Sstevel@tonic-gate 
12840Sstevel@tonic-gate 	endp = octet = argv[2];
12850Sstevel@tonic-gate 	for (i = 0; i < (int)request.hlen && octet != NULL; i++) {
12860Sstevel@tonic-gate 		if ((endp = (char *)strchr(endp, ':')) != NULL)
12870Sstevel@tonic-gate 			*endp++ = '\0';
12880Sstevel@tonic-gate 		(void) sscanf(octet, "%x", &buf);
12890Sstevel@tonic-gate 		request.chaddr[i] = (uchar_t)buf;
12900Sstevel@tonic-gate 		octet = endp;
12910Sstevel@tonic-gate 	}
12920Sstevel@tonic-gate 
12930Sstevel@tonic-gate 	/* broadcast bit */
12940Sstevel@tonic-gate 	if (relay.s_addr == INADDR_ANY)
12950Sstevel@tonic-gate 		request.flags = htons(0x8000);
12960Sstevel@tonic-gate 
12970Sstevel@tonic-gate 	/* magic cookie */
12980Sstevel@tonic-gate 	request.cookie[0] = 99;
12990Sstevel@tonic-gate 	request.cookie[1] = 130;
13000Sstevel@tonic-gate 	request.cookie[2] = 83;
13010Sstevel@tonic-gate 	request.cookie[3] = 99;
13020Sstevel@tonic-gate 
13030Sstevel@tonic-gate 	if (proto) {
13040Sstevel@tonic-gate 		/* Pretend to be a discover packet */
13050Sstevel@tonic-gate 		request.options[0] = CD_DHCP_TYPE;
13060Sstevel@tonic-gate 		request.options[1] = 1;
13070Sstevel@tonic-gate 		request.options[2] = DISCOVER;
13080Sstevel@tonic-gate 		request.options[3] = 0xff;
13090Sstevel@tonic-gate 
13100Sstevel@tonic-gate 		(void) cond_init(&go_cv, USYNC_THREAD, NULL);
13110Sstevel@tonic-gate 		(void) mutex_init(&go_mtx, USYNC_THREAD, NULL);
13120Sstevel@tonic-gate 	}
13130Sstevel@tonic-gate 	if (relay.s_addr != INADDR_ANY)
13140Sstevel@tonic-gate 		request.giaddr.s_addr = from.sin_addr.s_addr;
13150Sstevel@tonic-gate 
13160Sstevel@tonic-gate 	(void) sigfillset(&set);
13170Sstevel@tonic-gate 
13180Sstevel@tonic-gate 	(void) sigdelset(&set, SIGABRT);	/* allow for user abort */
13190Sstevel@tonic-gate 
13200Sstevel@tonic-gate 	(void) thr_sigsetmask(SIG_SETMASK, &set, NULL);
13210Sstevel@tonic-gate 
13220Sstevel@tonic-gate 	/*
13230Sstevel@tonic-gate 	 * Create the client threads
13240Sstevel@tonic-gate 	 */
13250Sstevel@tonic-gate 	clientsp = malloc(sizeof (struct client) * clients);
13260Sstevel@tonic-gate 	(void) memset(clientsp, 0, sizeof (struct client) * clients);
13270Sstevel@tonic-gate 	if (clientsp == NULL)
13280Sstevel@tonic-gate 		return (1);
13290Sstevel@tonic-gate 
13300Sstevel@tonic-gate 	for (i = 0; i < clients; i++) {
13310Sstevel@tonic-gate 		(void) memcpy(clientsp[i].chaddr, request.chaddr, request.hlen);
13320Sstevel@tonic-gate 		clientsp[i].hlen = request.hlen;
13330Sstevel@tonic-gate 		if (i > 100)
13340Sstevel@tonic-gate 			j = 3;
13350Sstevel@tonic-gate 		else if (i > 50)
13360Sstevel@tonic-gate 			j = 2;
13370Sstevel@tonic-gate 		else
13380Sstevel@tonic-gate 			j = 1;
13390Sstevel@tonic-gate 
13400Sstevel@tonic-gate 		if (i) {
13410Sstevel@tonic-gate 			clientsp[i].chaddr[j] = (unsigned char) i;
13420Sstevel@tonic-gate 			clientsp[i].chaddr[3] += (unsigned char) j;
13430Sstevel@tonic-gate 			clientsp[i].chaddr[4] = (unsigned char) (i * j);
13440Sstevel@tonic-gate 		}
13450Sstevel@tonic-gate 		if (printid)
13460Sstevel@tonic-gate 			fprintf(stderr, "ID %x:%x:%x:%x:%x:%x\n",
13470Sstevel@tonic-gate 				clientsp[i].chaddr[0],
13480Sstevel@tonic-gate 				clientsp[i].chaddr[1],
13490Sstevel@tonic-gate 				clientsp[i].chaddr[2],
13500Sstevel@tonic-gate 				clientsp[i].chaddr[3],
13510Sstevel@tonic-gate 				clientsp[i].chaddr[4],
13520Sstevel@tonic-gate 				clientsp[i].chaddr[5]);
13530Sstevel@tonic-gate 
13540Sstevel@tonic-gate 		(void) cond_init(&clientsp[i].cv, USYNC_THREAD, 0);
13550Sstevel@tonic-gate 		(void) mutex_init(&clientsp[i].mtx, USYNC_THREAD, 0);
13560Sstevel@tonic-gate 		clientsp[i].proto = proto;
13570Sstevel@tonic-gate 		clientsp[i].flags = CLIENT_FIRSTTIME;
13580Sstevel@tonic-gate 		if (thr_create(NULL, NULL, client, (void *) &clientsp[i],
13590Sstevel@tonic-gate 		    THR_BOUND | THR_SUSPENDED, &clientsp[i].id) != 0) {
13600Sstevel@tonic-gate 			(void) fprintf(stderr, "Error starting Client %04d\n",
13610Sstevel@tonic-gate 			    clientsp[i].id);
13620Sstevel@tonic-gate 		}
13630Sstevel@tonic-gate 	}
13640Sstevel@tonic-gate 
13650Sstevel@tonic-gate 	/*
13660Sstevel@tonic-gate 	 * Create signal handling thread.
13670Sstevel@tonic-gate 	 */
13680Sstevel@tonic-gate 	if (thr_create(NULL, 0, sig_handle, NULL,
13690Sstevel@tonic-gate 	THR_BOUND | THR_DAEMON | THR_DETACHED, &sig_id) != 0) {
13700Sstevel@tonic-gate 		(void) fprintf(stderr, "Error starting signal handler.\n");
13710Sstevel@tonic-gate 		return (1);
13720Sstevel@tonic-gate 	} else
13730Sstevel@tonic-gate 		(void) fprintf(stderr, "Started Signal handler: %04d...\n",
13740Sstevel@tonic-gate 		    sig_id);
13750Sstevel@tonic-gate 
13760Sstevel@tonic-gate 	/*
13770Sstevel@tonic-gate 	 * Create/start the service thread.
13780Sstevel@tonic-gate 	 */
13790Sstevel@tonic-gate 	if (thr_create(NULL, NULL, service, (void *) clientsp, THR_BOUND,
13800Sstevel@tonic-gate 	    &service_id) != 0) {
13810Sstevel@tonic-gate 		(void) fprintf(stderr, "Error starting Service %d\n",
13820Sstevel@tonic-gate 		    service_id);
13830Sstevel@tonic-gate 		exit(1);
13840Sstevel@tonic-gate 	} else
13850Sstevel@tonic-gate 		(void) fprintf(stderr, "Started Service %04d...\n",
13860Sstevel@tonic-gate 		    service_id);
13870Sstevel@tonic-gate 
13880Sstevel@tonic-gate 	/*
13890Sstevel@tonic-gate 	 * Continue the client threads.
13900Sstevel@tonic-gate 	 */
13910Sstevel@tonic-gate 	for (i = 0; i < clients; i++) {
13920Sstevel@tonic-gate 		(void) thr_continue(clientsp[i].id);
13930Sstevel@tonic-gate 	}
13940Sstevel@tonic-gate 
13950Sstevel@tonic-gate 	/*
13960Sstevel@tonic-gate 	 * join them
13970Sstevel@tonic-gate 	 */
13980Sstevel@tonic-gate 	threrrorp = &threrror;
13990Sstevel@tonic-gate 	for (i = 0; i < clients; i++) {
14000Sstevel@tonic-gate 		if (thr_join(clientsp[i].id, NULL, (void **) &threrrorp) == 0) {
14010Sstevel@tonic-gate 			if (threrror != 0) {
14020Sstevel@tonic-gate 				(void) fprintf(stdout,
14030Sstevel@tonic-gate 				    "Client %04d - exited with %d\n",
14040Sstevel@tonic-gate 				    clientsp[i].id, threrror);
14050Sstevel@tonic-gate 			}
14060Sstevel@tonic-gate 			(void) cond_destroy(&clientsp[i].cv);
14070Sstevel@tonic-gate 			(void) mutex_destroy(&clientsp[i].mtx);
14080Sstevel@tonic-gate 		}
14090Sstevel@tonic-gate 	}
14100Sstevel@tonic-gate 
14110Sstevel@tonic-gate 	(void) close(s);	/* force service out of poll */
14120Sstevel@tonic-gate 
14130Sstevel@tonic-gate 	if (thr_join(service_id, NULL, (void **) &threrrorp) == 0) {
14140Sstevel@tonic-gate 		if (threrror != 0) {
14150Sstevel@tonic-gate 			(void) fprintf(stdout, "Service - exited with %d\n",
14160Sstevel@tonic-gate 			    threrror);
14170Sstevel@tonic-gate 		}
14180Sstevel@tonic-gate 	}
14190Sstevel@tonic-gate 	(void) free((char *)clientsp);
14200Sstevel@tonic-gate 	(void) fprintf(stdout, "Exiting...\n");
14210Sstevel@tonic-gate 
14220Sstevel@tonic-gate 	return (0);
14230Sstevel@tonic-gate }
14240Sstevel@tonic-gate 
14250Sstevel@tonic-gate /*
14260Sstevel@tonic-gate  * corrupt: simulate packet corruption for debugging server
14270Sstevel@tonic-gate  */
14280Sstevel@tonic-gate static void
corrupt(char * pktp,int size)14290Sstevel@tonic-gate corrupt(char *pktp, int size)
14300Sstevel@tonic-gate {
14310Sstevel@tonic-gate 	int c;
14320Sstevel@tonic-gate 	int i;
14330Sstevel@tonic-gate 	int p;
14340Sstevel@tonic-gate 	char *pp;
14350Sstevel@tonic-gate 	char *pe = pktp + size;
14360Sstevel@tonic-gate 	int li = rand() % (size - 1) + 1;
14370Sstevel@tonic-gate 
14380Sstevel@tonic-gate 	for (pp = pktp; pp < pe; pp += li) {
14390Sstevel@tonic-gate 		c = ((pe - pp) < li ? pe - pp : li);
14400Sstevel@tonic-gate 		i = (rand() % c)>>1;
14410Sstevel@tonic-gate 		while (--i > 0) {
14420Sstevel@tonic-gate 			p = (rand() % c);
14430Sstevel@tonic-gate 			pp[p] = (unsigned char)(rand() & 0xFF);
14440Sstevel@tonic-gate 		}
14450Sstevel@tonic-gate 	}
14460Sstevel@tonic-gate }
1447