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