1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 #pragma ident   "%Z%%M% %I%     %E% SMI"
  27 
  28 #include <stdio.h>
  29 #include <stdio_ext.h>
  30 #include <stdlib.h>
  31 #include <unistd.h>
  32 #include <ctype.h>
  33 #include <string.h>
  34 #include <syslog.h>
  35 #include <signal.h>
  36 #include <time.h>
  37 #include <limits.h>
  38 #include <sys/resource.h>
  39 #include <sys/fcntl.h>
  40 #include <sys/types.h>
  41 #include <fcntl.h>
  42 #include <sys/resource.h>
  43 #include <sys/stat.h>
  44 #include <sys/systeminfo.h>
  45 #include <sys/socket.h>
  46 #include <sys/sockio.h>
  47 #include <net/if.h>
  48 #include <netinet/in.h>
  49 #include <arpa/inet.h>
  50 #include <errno.h>
  51 #include <sys/stropts.h>
  52 #include <netinet/dhcp.h>
  53 #include <dhcp_impl.h>
  54 #include <synch.h>
  55 #include <netdb.h>
  56 #include <locale.h>
  57 #include <mtmalloc.h>
  58 #include <tnf/probe.h>
  59 #include <libinetutil.h>
  60 
  61 struct client {
  62         thread_t        id;
  63         PKT_LIST        *pktlistp;
  64         cond_t          cv;
  65         cond_t          acv;
  66         mutex_t         mtx;
  67         int             proto;
  68         uchar_t         chaddr[20];
  69         char            chost[40];
  70         int             hlen;
  71         uint_t          xid;
  72         int             flags;
  73         time_t          ltime;
  74         int             state;
  75 };
  76 
  77 #define CLIENT_BUSY             0x1
  78 #define CLIENT_FIRSTTIME        0x2
  79 
  80 ushort_t        port_offset = 0;        /* offset to port for multiple server */
  81 int             fast = 0;               /* higher load */
  82 int             bound = 0;              /* only broadcast on given interface */
  83 int             lrecv = 1;              /* only receive on given interface */
  84 static struct in_addr relay;            /* spoof being a relay agent */
  85 static struct sockaddr_in from, relfrom;
  86 static int clients, s, srelay = -1;
  87 static struct client *clientsp;
  88 
  89 static PKT request;
  90 static char ifname[IFNAMSIZ];
  91 static int startindex;
  92 static mutex_t go_mtx;
  93 static cond_t go_cv;
  94 static boolean_t time_to_go;
  95 static int release_time = 0;
  96 static int desynch = 1;
  97 static double avg = 0;
  98 static timespec_t avgslp;
  99 static volatile ulong_t tops, otops;
 100 static volatile ulong_t minops[6];
 101 static volatile time_t mintim[6];
 102 static volatile int minind;
 103 long sample_time = 10L;
 104 long nsamples = 2;
 105 
 106 static volatile ulong_t ops_outstanding;
 107 static time_t start, ostart;
 108 int verbose = 0;
 109 int dohost = 0;
 110 int randcl = 0;
 111 int randhlen = 0;
 112 int randerr = 0;
 113 int dos = 0;
 114 int dofork = 0;
 115 int printid = 0;
 116 
 117 static time_t ltime;
 118 static struct lifreq lifr;
 119 
 120 static void corrupt(char *, int);
 121 
 122 static void
 123 dhcpmsgtype(uchar_t pkt, char *buf)
 124 {
 125         char    *p;
 126 
 127         switch (pkt) {
 128         case DISCOVER:
 129                 p = "DISCOVER";
 130                 break;
 131         case OFFER:
 132                 p = "OFFER";
 133                 break;
 134         case REQUEST:
 135                 p = "REQUEST";
 136                 break;
 137         case DECLINE:
 138                 p = "DECLINE";
 139                 break;
 140         case ACK:
 141                 p = "ACK";
 142                 break;
 143         case NAK:
 144                 p = "NAK";
 145                 break;
 146         case RELEASE:
 147                 p = "RELEASE";
 148                 break;
 149         case INFORM:
 150                 p = "INFORM";
 151                 break;
 152         default:
 153                 p = "UNKNOWN";
 154                 break;
 155         }
 156 
 157         (void) strcpy(buf, p);
 158 }
 159 
 160 static int
 161 closeif(int ms, char *cifname, struct sockaddr_in *myip, thread_t myself)
 162 {
 163         struct ifreq ifr;
 164         int error = 0;
 165 
 166         (void) strcpy(ifr.ifr_name, cifname);
 167         if (ioctl(ms, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
 168                 (void) fprintf(stderr,
 169                     "Client %04d - can't get interface flags on %s\n", myself,
 170                     cifname);
 171                 error = 7;
 172         }
 173         ifr.ifr_flags &= ~IFF_UP;
 174         if (ioctl(ms, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) {
 175                 (void) fprintf(stderr,
 176                     "Client %04d - can't set interface flags on %s\n", myself,
 177                     cifname);
 178                 error = 7;
 179         }
 180         myip->sin_addr.s_addr = htonl(INADDR_ANY);
 181         ifr.ifr_addr = *(struct sockaddr *)myip;
 182         if (ioctl(ms, SIOCSIFADDR, (caddr_t)&ifr)) {
 183                 (void) fprintf(stderr,
 184                     "Client %04d - Can't unset address on %s\n", myself,
 185                     cifname);
 186                 error = 8;
 187         }
 188         (void) close(ms);
 189         return (error);
 190 }
 191 
 192 static void *
 193 client(void *args)
 194 {
 195         PKT crequest, *irequestp;
 196         PKT_LIST *bp = NULL, *wbp, *twbp;
 197         struct client *mep = (struct client *)args;
 198         time_t retry_time = 2, lease, sleep_time = 0;
 199         uchar_t *endp;
 200         boolean_t       done, config, timeout;
 201         int nstate, ms = -1;
 202         DHCP_OPT *optp, *unused_optp;
 203         timespec_t ts, tr;
 204         int error = 0;
 205         thread_t myself = thr_self();
 206         struct sockaddr_in to, myip, maskip;
 207         struct in_addr serverip;
 208         time_t start_time, expired = 0;
 209         char    cid[BUFSIZ];
 210         char    cifname[IFNAMSIZ];
 211         char            host[40];
 212         char            domain[40];
 213         char p[30], np[30];
 214         struct ifreq ifr;
 215         int moldy;
 216         int i;
 217         uint_t cidlen;
 218         char            *domainp;
 219 
 220 forever:
 221         if (bp) {
 222                 (void) free(bp->pkt);
 223                 (void) free(bp);
 224                 bp = NULL;
 225         }
 226         if (!time_to_go) {
 227                 (void) mutex_lock(&mep->mtx);
 228                 mep->flags &= ~CLIENT_BUSY;
 229                 if (mep->flags & CLIENT_FIRSTTIME) {
 230                         mep->flags &= ~CLIENT_FIRSTTIME;
 231                 } else {
 232                         tops++;
 233                         ops_outstanding--;
 234                 }
 235                 if (avg)
 236                         (void) cond_wait(&mep->acv, &mep->mtx);
 237                 mep->flags |= CLIENT_BUSY;
 238                 mep->ltime = time(NULL);
 239                 ops_outstanding++;
 240                 (void) mutex_unlock(&mep->mtx);
 241         }
 242         if (desynch)
 243                 (void) sleep((desynch & myself) + 3);       /* desynch clients */
 244         if (verbose == 1)
 245                 (void) fprintf(stdout, "Client %04d - started.\n", myself);
 246         start_time = time(NULL);
 247         (void) sprintf(cifname, "%s:%d", ifname, startindex + myself);
 248 
 249         /* reset client addr each time */
 250         if (relay.s_addr != INADDR_ANY) {
 251                 to.sin_addr.s_addr = relay.s_addr;
 252         } else {
 253                 to.sin_addr.s_addr = INADDR_BROADCAST;
 254         }
 255         to.sin_port = htons(IPPORT_BOOTPS + port_offset);
 256         to.sin_family = AF_INET;
 257 
 258         domain[0] = host[0] = NULL;
 259         if (randcl) {
 260                 /* Further randomize. */
 261                 if (randhlen > 0) {
 262                         mep->hlen = randhlen;
 263                 }
 264 
 265                 for (i = 3; i < mep->hlen; i++) {
 266                         mep->chaddr[i] = random() & 0xff;
 267                 }
 268         }
 269 
 270         (void) memcpy(&crequest, &request, sizeof (request));
 271         (void) memcpy(crequest.chaddr, mep->chaddr, mep->hlen);
 272         crequest.hlen = mep->hlen;
 273 
 274 
 275         if (mep->proto) {
 276                 mep->state = DISCOVER;
 277                 optp = (DHCP_OPT *) & crequest.options[3];  /* skip TYPE */
 278                 optp->code = CD_CLIENT_ID;
 279                 optp->len = mep->hlen + 1;
 280                 optp->value[0] = 0x01;
 281                 (void) memcpy(&optp->value[1], mep->chaddr, mep->hlen);
 282                 cidlen = sizeof (cid);
 283                 (void) octet_to_hexascii(optp->value, mep->hlen + 1, cid,
 284                     &cidlen);
 285                 unused_optp = (DHCP_OPT *) & optp->value[mep->hlen + 1];
 286         } else {
 287                 mep->state = 0;
 288                 cidlen = sizeof (cid);
 289                 (void) octet_to_hexascii(mep->chaddr, mep->hlen, cid, &cidlen);
 290                 unused_optp = (DHCP_OPT *)&crequest.options[3]; /* skip TYPE */
 291         }
 292 
 293         /* Use global descriptor at first */
 294         ms = s;
 295 
 296         myip.sin_addr.s_addr = htonl(INADDR_ANY);
 297         done = B_FALSE;
 298         config = B_FALSE;
 299         do {
 300                 timeout = B_FALSE;
 301 
 302                 TNF_PROBE_2(client,
 303                             "client",
 304                             "client%debug 'in func client'",
 305                             tnf_ulong, state, mep->state,
 306                             tnf_string, cid, (char *)cid);
 307 
 308                 if (time_to_go) {
 309                         if (mep->state == ACK) {
 310                                 mep->state = RELEASE;
 311                                 if (verbose == 1)
 312                                         (void) fprintf(stderr,
 313                                             "Client %04d - RELEASEing %s\n",
 314                                             myself, inet_ntoa(myip.sin_addr));
 315                                 else if (verbose == 2)
 316                                         fprintf(stderr, "[%d %s]",
 317                                                 clientsp[i].id,
 318                                                 inet_ntoa(myip.sin_addr));
 319                                 optp = (DHCP_OPT *) crequest.options;
 320                                 (void) memset((char *)unused_optp, 0,
 321                                     (int)((char *)&crequest.options[
 322                                     sizeof (crequest.options)] -
 323                                     (char *)unused_optp));
 324                                 optp->value[0] = RELEASE;
 325                         } else {
 326                                 done = B_TRUE;
 327                                 if (verbose == 1)
 328                                         (void) fprintf(stderr,
 329                                             "Client %04d - terminated.\n",
 330                                             myself);
 331                                 break;
 332                         }
 333                 } else if (release_time || avg) {
 334                         if (mep->state == ACK) {
 335 
 336                                 /* lru testing: don't release lease */
 337                                 if (randcl & 0x2) {
 338                                         done = B_FALSE;
 339                                         mep->state = nstate = 0;
 340                                         sleep_time = 0;
 341                                         if (bp) {
 342                                                 (void) free(bp->pkt);
 343                                                 (void) free(bp);
 344                                                 bp = NULL;
 345                                         }
 346                                         goto forever;
 347                                 }
 348                                 mep->state = RELEASE;
 349                                 if (verbose == 1)
 350                                         (void) fprintf(stderr,
 351                                             "Client %04d - RELEASEing %s\n",
 352                                             myself, inet_ntoa(myip.sin_addr));
 353                                 else if (verbose == 2)
 354                                         fprintf(stderr, "[%d %s]",
 355                                                 clientsp[i].id,
 356                                                 inet_ntoa(myip.sin_addr));
 357                                 optp = (DHCP_OPT *) crequest.options;
 358                                 (void) memset((char *)unused_optp, 0,
 359                                     (int)((char *)&crequest.options[
 360                                     sizeof (crequest.options)] -
 361                                     (char *)unused_optp));
 362                                 optp->value[0] = RELEASE;
 363                         }
 364                 }
 365                 if (mep->state == REQUEST && expired < time(NULL)) {
 366                         /* drop back to INIT state. */
 367                         if (verbose == 1)
 368                                 (void) fprintf(stderr,
 369                                     "Client %04d - Dropping back to INIT.\n",
 370                                     myself);
 371                         done = B_FALSE;
 372                         mep->state = nstate = 0;
 373                         sleep_time = 0;
 374                         if (bp) {
 375                                 (void) free(bp->pkt);
 376                                 (void) free(bp);
 377                                 bp = NULL;
 378                         }
 379                         goto forever;
 380                 }
 381                 if (mep->state == RELEASE && !time_to_go) {
 382                         (void) mutex_lock(&mep->mtx);
 383                         tops++;
 384                         ops_outstanding--;
 385                         mep->flags &= ~CLIENT_BUSY;
 386                         if (avg)
 387                                 (void) cond_wait(&mep->acv, &mep->mtx);
 388                         mep->ltime = time(NULL);
 389                         ops_outstanding++;
 390                         mep->flags |= CLIENT_BUSY;
 391                         (void) mutex_unlock(&mep->mtx);
 392                 }
 393                 /* Send request... */
 394                 crequest.secs = htons((ushort_t)(time(NULL) - start_time));
 395                 crequest.xid = htonl((myself << 2) + mep->xid++);
 396 
 397                 /* Randomly corrupt packets of a certain type. */
 398                 if ((randerr & 0xF) == mep->state || (randerr & 0xF) == 0xF) {
 399                         if (randerr & 0x10) {
 400                                 /* Randomly corrupt entire request. */
 401                                 corrupt((char *)&crequest, sizeof (crequest));
 402                         } else {
 403                                 /* Randomly corrupt options. */
 404                                 corrupt((char *)&crequest.options[3],
 405                                     sizeof (crequest.options) - 3);
 406                         }
 407                 }
 408 
 409                 if (sendto(ms, (char *)&crequest, sizeof (PKT), 0,
 410                     (struct sockaddr *)&to, sizeof (struct sockaddr)) < 0) {
 411                         perror("Sendto");
 412                         error = 4;
 413                         thr_exit(&error);
 414                 }
 415                 if (mep->state == RELEASE) {
 416                         done = B_TRUE;
 417                         if (!avg) {
 418                                 (void) strcpy(ifr.ifr_name, cifname);
 419                                 if (ioctl(ms, SIOCGIFFLAGS,
 420                                     (caddr_t)&ifr) < 0) {
 421                                         (void) fprintf(stderr, "Client %04d - "
 422                                             "can't get interface flags on %s\n",
 423                                             myself, cifname);
 424                                         error = 7;
 425                                 }
 426                                 ifr.ifr_flags &= ~IFF_UP;
 427                                 if (ioctl(ms, SIOCSIFFLAGS,
 428                                     (caddr_t)&ifr) < 0) {
 429                                         (void) fprintf(stderr, "Client %04d - "
 430                                         "can't set interface flags on %s\n",
 431                                         myself, cifname);
 432                                         error = 7;
 433                                 }
 434                                 myip.sin_addr.s_addr = htonl(INADDR_ANY);
 435                                 ifr.ifr_addr = *(struct sockaddr *)&myip;
 436                                 if (ioctl(ms, SIOCSIFADDR, (caddr_t)&ifr)) {
 437                                         (void) fprintf(stderr, "Client %04d - "
 438                                             "Can't unset address on %s\n",
 439                                             myself, cifname);
 440                                         error = 8;
 441                                 }
 442                                 (void) close(ms);
 443                         }
 444                         if (release_time || avg) {
 445                                 done = B_FALSE;
 446                                 mep->state = nstate = 0;
 447                                 sleep_time = 0;
 448                                 if (bp) {
 449                                         (void) free(bp->pkt);
 450                                         (void) free(bp);
 451                                         bp = NULL;
 452                                 }
 453                                 goto forever;
 454                         }
 455                         break;
 456                 }
 457                 /* await reply */
 458 moldy:
 459                 (void) mutex_lock(&mep->mtx);
 460                 ts.tv_sec = time(NULL) + retry_time;
 461                 ts.tv_nsec = 0;
 462 
 463                 while (mep->pktlistp == NULL)
 464                         if (cond_timedwait(&mep->cv, &mep->mtx, &ts) == ETIME) {
 465                                 timeout = B_TRUE;
 466                                 if (retry_time > 64)
 467                                         retry_time = 2;
 468                                 else if (fast)
 469                                         retry_time += 2;
 470                                 else
 471                                         retry_time *= 2;
 472                                 break;
 473                         } else {
 474                                 if (time_to_go)
 475                                         break;
 476                         }
 477                 (void) mutex_unlock(&mep->mtx);
 478 
 479                 if (time_to_go || timeout)
 480                         continue;
 481 
 482                 (void) mutex_lock(&mep->mtx);
 483                 moldy = 0;
 484                 if (bp) {
 485                         (void) free(bp->pkt);
 486                         (void) free(bp);
 487                 }
 488                 bp = NULL;
 489                 wbp = mep->pktlistp;
 490                 while (wbp != NULL) {
 491                         irequestp = wbp->pkt;
 492                         if (bp == NULL && irequestp->op == BOOTREPLY &&
 493                             memcmp(&crequest.xid, &irequestp->xid,
 494                             sizeof (crequest.xid)) == 0) {
 495                                 bp = wbp;
 496                                 wbp = wbp->next;
 497                                 continue;
 498                         }
 499                         (void) free(wbp->pkt);
 500                         twbp = wbp;
 501                         wbp = wbp->next;
 502                         (void) free(twbp);
 503                         if (verbose == 1)
 504                                 (void) fprintf(stderr,
 505                                 "Client %04d - Moldy xid\n", myself);
 506                         moldy++;
 507                 }
 508 
 509                 mep->pktlistp = NULL;
 510                 (void) mutex_unlock(&mep->mtx);
 511 
 512                 if (bp == NULL) {
 513                         if (moldy > 0)
 514                                 goto moldy;
 515 
 516                         continue;
 517                 }
 518                 irequestp = bp->pkt;
 519 
 520                 if (mep->proto) {
 521                         /*
 522                          * Scan for CD_DHCP_TYPE, CD_SERVER_ID, and
 523                          * CD_LEASE_TIME if proto.
 524                          */
 525                         nstate = 0;
 526                         maskip.sin_addr.s_addr = serverip.s_addr = INADDR_ANY;
 527                         maskip.sin_family = AF_INET;
 528                         lease = (time_t)0;
 529                         optp = (DHCP_OPT *) irequestp->options;
 530                         endp = (uchar_t *)irequestp + bp->len;
 531                         host[0] = NULL;
 532                         while ((uchar_t *)optp < (uchar_t *)endp) {
 533                                 switch (optp->code) {
 534                                 case CD_HOSTNAME:
 535                                         (void) strncpy(host,
 536                                             (const char *)optp->value,
 537                                             optp->len);
 538                                         host[optp->len] = '\0';
 539                                         break;
 540                                 case CD_DNSDOMAIN:
 541                                         (void) strncpy(domain,
 542                                             (const char *)optp->value,
 543                                             optp->len);
 544                                         domain[optp->len] = '\0';
 545                                         break;
 546                                 case CD_DHCP_TYPE:
 547                                         nstate = optp->value[0];
 548                                         break;
 549                                 case CD_SUBNETMASK:
 550                                         (void) memcpy(&maskip.sin_addr,
 551                                             optp->value,
 552                                             sizeof (struct in_addr));
 553                                         break;
 554                                 case CD_SERVER_ID:
 555                                         (void) memcpy(&serverip, optp->value,
 556                                             sizeof (struct in_addr));
 557                                         break;
 558                                 case CD_LEASE_TIME:
 559                                         (void) memcpy(&lease, optp->value,
 560                                             sizeof (time_t));
 561                                         lease = htonl(lease);
 562                                         break;
 563                                 }
 564                                 optp = (DHCP_OPT *) & optp->value[optp->len];
 565                         }
 566                         if (mep->state == DISCOVER && nstate == OFFER) {
 567                                 mep->state = REQUEST;
 568                                 expired = time(NULL) + 60;
 569                                 /*
 570                                  * Add in the requested IP address option and
 571                                  * server ID.
 572                                  */
 573                                 optp = (DHCP_OPT *) crequest.options;
 574                                 optp->value[0] = REQUEST;
 575                                 optp = unused_optp; /* step over CD_DHCP_TYPE */
 576                                 optp->code = CD_REQUESTED_IP_ADDR;
 577                                 optp->len = sizeof (struct in_addr);
 578                                 (void) memcpy(optp->value, &irequestp->yiaddr,
 579                                     sizeof (struct in_addr));
 580                                 optp = (DHCP_OPT *) & optp->value[
 581                                     sizeof (struct in_addr)];
 582                                 optp->code = CD_SERVER_ID;
 583                                 optp->len = sizeof (struct in_addr);
 584                                 (void) memcpy(optp->value, &serverip,
 585                                     sizeof (struct in_addr));
 586                                 optp = (DHCP_OPT *) & optp->value[
 587                                     sizeof (struct in_addr)];
 588                                 if (dohost == 0) {
 589                                         if (bp) {
 590                                                 (void) free(bp->pkt);
 591                                                 (void) free(bp);
 592                                                 bp = NULL;
 593                                         }
 594                                         continue;
 595                                 }
 596 
 597                                 if (domain[0] == '\0' && host[0] != '\0' &&
 598                                     (domainp = strchr(host, '.')) != NULL) {
 599                                         (void) snprintf(domain, sizeof (domain),
 600                                             "%s", domainp);
 601                                 }
 602 
 603                                 if (dohost & 0x2) {
 604                                         cidlen = sizeof (cid);
 605                                         (void) octet_to_hexascii(mep->chaddr,
 606                                             mep->hlen, host, &cidlen);
 607 
 608                                         if (domain[0])
 609                                                 (void) snprintf(host,
 610                                                     sizeof (host), "%s.%s",
 611                                                     cid, domain);
 612                                         else
 613                                                 (void) snprintf(host,
 614                                                     sizeof (host), "%s", cid);
 615                                 }
 616 
 617                                 optp->code = CD_HOSTNAME;
 618                                 optp->len = strlen(host);
 619                                 (void) memcpy(optp->value, host, strlen(host));
 620                                 optp->value[strlen(host)] = '\0';
 621                                 if (randcl && (random() & 0x1)) {
 622                                         /* create a random name */
 623                                         for (i = 0; i < optp->len &&
 624                                                 optp->value[i] != '.'; i++)
 625                                                 if (i & 1)
 626                                                     optp->value[i] = '0' +
 627                                                         (mep->chaddr[i] & 0x7);
 628                                                 else
 629                                                     optp->value[i] = 'a' +
 630                                                         (mep->chaddr[i] & 0x7);
 631                                                 strcpy((char *)mep->chost,
 632                                                     (const char *)optp->value);
 633                                 } else if (randcl && mep->chost[0]) {
 634                                         /* use the previous one */
 635                                         optp->len = strlen(mep->chost);
 636                                         (void) memcpy(optp->value, mep->chost,
 637                                             strlen(mep->chost));
 638                                         optp->value[strlen(mep->chost)] = '\0';
 639                                 }
 640                                 if (bp) {
 641                                         (void) free(bp->pkt);
 642                                         (void) free(bp);
 643                                         bp = NULL;
 644                                 }
 645                                 continue;
 646                         } else if ((mep->state == REQUEST ||
 647                             mep->state == ACK) && nstate == ACK) {
 648                                 /*
 649                                  * we're bound. defend the lease. Add the
 650                                  * address to our interface. Due to the
 651                                  * service architecture of this program, we
 652                                  * can't unset the broadcast bit..
 653                                  */
 654                                 mep->state = ACK;
 655                                 nstate = 0;
 656                                 retry_time = 2;
 657                                 myip.sin_family = AF_INET;
 658                                 myip.sin_addr.s_addr = irequestp->yiaddr.s_addr;
 659                                 crequest.ciaddr.s_addr = myip.sin_addr.s_addr;
 660                                 optp = unused_optp;
 661                                 optp->code = CD_LEASE_TIME;
 662                                 optp->len = sizeof (time_t);
 663                                 (void) memcpy(optp->value, &lease,
 664                                     sizeof (time_t));
 665                                 optp = (DHCP_OPT *)
 666                                         & optp->value[sizeof (time_t)];
 667                                 (void) memset((char *)optp, 0, (int)((char *)
 668                                     &crequest.options[
 669                                     sizeof (crequest.options)] -
 670                                     (char *)optp));
 671                                 to.sin_addr.s_addr = serverip.s_addr;
 672 
 673                                 if (lease == -1) {
 674                                         done = B_TRUE;  /* permanent lease */
 675                                         sleep_time = 0;
 676                                 } else {
 677                                         sleep_time = lease / 2;
 678                                         lease = time(NULL) + lease;
 679                                 }
 680 
 681                                 if (release_time || avg) {
 682                                         sleep_time = release_time;
 683                                         done = B_FALSE;
 684                                 }
 685                                 if (verbose == 1)
 686                                         (void) fprintf(stdout,
 687                                             "Client %04d(%s) - DHCP: %s == %s",
 688                                             myself, cid,
 689                                             inet_ntoa(myip.sin_addr),
 690                                             (lease == -1) ? "Forever\n" :
 691                                             ctime(&lease));
 692                                 else if (verbose == 2)
 693                                         fprintf(stderr, "(%d %s)", mep->id,
 694                                                 cid);
 695                                 if (!config && !avg) {
 696                                         /* Add mask and address */
 697                                         if ((ms = socket(AF_INET, SOCK_DGRAM,
 698                                             0)) < 0) {
 699                                                 (void) fprintf(stderr,
 700                                                     "Client %04d - can't open "
 701                                                     "DGRAM socket.\n", myself);
 702                                                 error = 7;
 703                                                 break;
 704                                         }
 705                                         (void) strcpy(ifr.ifr_name, cifname);
 706                                         ifr.ifr_addr =
 707                                             *(struct sockaddr *)&myip;
 708                                         /*
 709                                          * XXXX: needed in on81
 710                                          * for initial
 711                                          * interface creation
 712                                          */
 713                                         (void) (ioctl(ms, SIOCLIFADDIF,
 714                                             (caddr_t)&ifr));
 715                                         (void) strcpy(ifr.ifr_name, cifname);
 716                                         ifr.ifr_addr =
 717                                             *(struct sockaddr *)&maskip;
 718                                         if (ioctl(ms, SIOCSIFNETMASK,
 719                                             (caddr_t)&ifr)) {
 720                                                 (void) fprintf(stderr,
 721                                                     "Client %04d - Can't set "
 722                                                     "netmask: %s on %s\n",
 723                                                     myself,
 724                                                     inet_ntoa(maskip.sin_addr),
 725                                                     cifname);
 726                                                 error = 7;
 727                                                 (void) close(ms);
 728                                                 break;
 729                                         }
 730                                         if (ioctl(ms, SIOCGIFFLAGS,
 731                                             (caddr_t)&ifr) < 0) {
 732                                                 (void) fprintf(stderr,
 733                                                     "Client %04d - can't get "
 734                                                     "interface flags on %s\n",
 735                                                     myself, cifname);
 736                                                 error = 7;
 737                                                 (void) close(ms);
 738                                                 break;
 739                                         }
 740                                         ifr.ifr_flags |= IFF_UP;
 741                                         if (ioctl(ms, SIOCSIFFLAGS,
 742                                             (caddr_t)&ifr) < 0) {
 743                                                 (void) fprintf(stderr,
 744                                                     "Client %04d - can't set "
 745                                                     "interface flags on %s\n",
 746                                                     myself, cifname);
 747                                                 error = 7;
 748                                                 (void) close(ms);
 749                                                 break;
 750                                         }
 751                                         ifr.ifr_addr =
 752                                             *(struct sockaddr *)&myip;
 753                                         if (ioctl(ms, SIOCSIFADDR,
 754                                             (caddr_t)&ifr)) {
 755                                                 (void) fprintf(stderr,
 756                                                     "Client %04d - Can't set "
 757                                                     "address on %s\n",
 758                                                     myself, cifname);
 759                                                 error = 8;
 760                                                 (void) close(ms);
 761                                                 break;
 762                                         }
 763                                         config = B_TRUE;
 764                                 }
 765                                 if (sleep_time != 0) {
 766                                         /* Go to sleep for 50% of lease time. */
 767                                         tr.tv_sec = time(NULL) + sleep_time;
 768                                         if (verbose == 1)
 769                                                 (void) fprintf(stderr,
 770                                                     "Client %04d - sleeping "
 771                                                     "until %s", myself,
 772                                                     ctime(&tr.tv_sec));
 773                                         tr.tv_nsec = 0;
 774                                         (void) mutex_lock(&go_mtx);
 775                                         while (!time_to_go) {
 776                                                 if (cond_timedwait(&go_cv,
 777                                                     &go_mtx, &tr) == ETIME)
 778                                                         break;
 779                                         }
 780                                         (void) mutex_unlock(&go_mtx);
 781                                         if (verbose == 1)
 782                                                 (void) fprintf(stderr,
 783                                                     "Client %04d - awake\n",
 784                                                     myself);
 785                                 }
 786                         } else if (mep->state == ACK && nstate == NAK) {
 787                                 /* drop back to INIT state. */
 788                                 if (verbose == 1) {
 789                                         (void) fprintf(stdout, "Client %04d - "
 790                                             "DHCP: we got NAKed.\n", myself);
 791                                         (void) fprintf(stderr, "Client %04d - "
 792                                             "Dropping back to INIT.\n", myself);
 793                                 }
 794                                 if (!avg)
 795                                         (void) closeif(ms, cifname,
 796                                                 &myip, myself);
 797                                 done = B_FALSE;
 798                                 mep->state = nstate = 0;
 799                                 sleep_time = 0;
 800                                 if (bp) {
 801                                         (void) free(bp->pkt);
 802                                         (void) free(bp);
 803                                         bp = NULL;
 804                                 }
 805                                 goto forever;
 806                         } else {
 807                                 dhcpmsgtype(nstate, np);
 808                                 dhcpmsgtype(mep->state, p);
 809                                 (void) fprintf(stderr, "Client %04d - "
 810                                     "unexpected mesg: %s, when I'm in state: "
 811                                     "%s.\n", myself, np, p);
 812                                 error = 9;
 813                                 break;
 814                         }
 815                 } else {
 816                         done = B_TRUE;  /* BOOTP is done */
 817                         if (verbose == 1)
 818                                 (void) fprintf(stdout,
 819                                     "Client %04d(%s) - BOOTP: %s\n", myself,
 820                                     cid, inet_ntoa(irequestp->yiaddr));
 821                         if (release_time || avg) {
 822                                 done = B_FALSE;
 823                                 mep->state = nstate = 0;
 824                                 sleep_time = 0;
 825                                 if (bp) {
 826                                         (void) free(bp->pkt);
 827                                         (void) free(bp);
 828                                         bp = NULL;
 829                                 }
 830                                 goto forever;
 831                         }
 832                 }
 833                 if (bp) {
 834                         (void) free(bp->pkt);
 835                         (void) free(bp);
 836                         bp = NULL;
 837                 }
 838         } while (!done);
 839 
 840         if (!done) {
 841                 (void) fprintf(stderr,
 842                     "Client %04d - %s: configuration failed.\n",
 843                     myself, (mep->proto) ? "DHCP" : "BOOTP");
 844         }
 845         wbp = mep->pktlistp;
 846         while (wbp != NULL) {
 847                 twbp = wbp->next;
 848                 if (wbp->pkt != NULL)
 849                         (void) free(wbp->pkt);
 850                 (void) free(wbp);
 851                 wbp = twbp;
 852         }
 853 
 854         thr_exit(&error);
 855         return (NULL);          /* NOTREACHED */
 856 }
 857 
 858 /*
 859  * Never returns. Just loads client lists.
 860  */
 861 static void *
 862 service(void *args)
 863 {
 864         struct client *clientp = (struct client *)args;
 865         PKT_LIST *bp, *wbp;
 866         PKT *irequestp;
 867         int error = 0;
 868         struct pollfd pfd[2];
 869         ulong_t *bufp;  /* ulong_t to force alignment */
 870         int len, i;
 871 
 872         pfd[0].fd = s;
 873         pfd[0].events = POLLIN | POLLPRI;
 874         if (relay.s_addr != INADDR_ANY) {
 875                 pfd[1].fd = srelay;
 876                 pfd[1].events = POLLIN | POLLPRI;
 877         } else {
 878                 pfd[1].fd = -1;
 879                 pfd[1].events = 0;
 880         }
 881 
 882         for (;;) {
 883                 pfd[0].revents = 0;
 884                 pfd[1].revents = 0;
 885                 if (poll(pfd, (nfds_t)2, INFTIM) < 0) {
 886                         (void) fprintf(stderr, "Service - can't poll...\n");
 887                         error = 5;
 888                         break;
 889                 }
 890                 (void) mutex_lock(&go_mtx);
 891                 if (time_to_go) {
 892                         (void) fprintf(stderr, "Service - exiting...\n");
 893                         error = 0;
 894                         break;
 895                 }
 896                 (void) mutex_unlock(&go_mtx);
 897                 len = BUFSIZ * 2;
 898                 bufp = malloc(len);
 899                 if (pfd[0].revents)
 900                         len = recv(s, (char *)bufp, len, 0);
 901                 else {
 902                         len = recv(srelay, (char *)bufp, len, 0);
 903                 }
 904 
 905                 if (len < 0) {
 906                         (void) fprintf(stderr,
 907                             "Service - can't receive - %s\n", strerror(errno));
 908                         error = 6;
 909                         break;
 910                 } else {
 911                         irequestp = (PKT *) bufp;
 912                         for (i = 0; i < clients; i++) {
 913                                 if (memcmp(clientp[i].chaddr, irequestp->chaddr,
 914                                     clientp[i].hlen) == 0) {
 915                                         (void) mutex_lock(&clientp[i].mtx);
 916                                         bp = malloc(sizeof (PKT_LIST));
 917                                         bp->pkt = irequestp;
 918                                         bp->len = len;
 919                                         if (verbose == 1)
 920                                                 (void) fprintf(stderr,
 921                                                     "Service - received packet "
 922                                                     "for thread %04d...\n",
 923                                                     clientp[i].id);
 924                                         if (clientp[i].pktlistp == NULL) {
 925                                                 clientp[i].pktlistp = bp;
 926                                                 bp->prev = NULL;
 927                                         } else {
 928                                                 for (wbp = clientp[i].pktlistp;
 929                                                     wbp->next != NULL;
 930                                                     wbp = wbp->next)
 931                                                         /* null */;
 932                                                 wbp->next = bp;
 933                                                 bp->prev = wbp;
 934                                         }
 935                                         bp->next = NULL;
 936                                         (void) cond_signal(&clientp[i].cv);
 937                                         (void) mutex_unlock(&clientp[i].mtx);
 938                                         break;
 939                                 }
 940                         }
 941                         if (i >= clients)
 942                                 free(bufp);
 943                 }
 944         }
 945         thr_exit(&error);
 946         return (NULL);          /* NOTREACHED */
 947 }
 948 
 949 /* ARGSUSED */
 950 static void *
 951 sig_handle(void *arg)
 952 {
 953         boolean_t leave = B_FALSE;
 954         int sig;
 955         sigset_t set;
 956         char buf[SIG2STR_MAX];
 957         int old, new, unstarted;
 958         int i;
 959         int oldi;
 960         uint_t cidlen;
 961         char cid[BUFSIZ];
 962         int discover, offer, req, decline, ack, nak;
 963         int release, inform, unknown;
 964         int kicked;
 965         ulong_t         minavg;
 966         time_t          minstime;
 967 
 968         (void) sigfillset(&set);
 969 
 970         if (avg == 0) {
 971                 avgslp.tv_sec = sample_time;
 972                 avgslp.tv_nsec = 0L;
 973         }
 974         while (!leave) {
 975                 discover = offer = req = decline = ack = nak = 0;
 976                 release = inform = unknown = 0;
 977                 switch (sig = sigtimedwait(&set, NULL, &avgslp)) {
 978                 case SIGHUP:
 979                 case -1:
 980                         old = time(NULL);
 981                         new = unstarted = 0;
 982                         kicked = 0;
 983                         for (i = 0; i < clients; i++) {
 984                                 /* Start next client at avgslp offset */
 985                                 if (avg && kicked == 0 &&
 986                                     (clientsp[i].flags &
 987                                     (CLIENT_FIRSTTIME | CLIENT_BUSY)) == 0) {
 988                                         (void) mutex_lock(&clientsp[i].mtx);
 989                                         (void) cond_signal(&clientsp[i].acv);
 990                                         (void) mutex_unlock(&clientsp[i].mtx);
 991                                         kicked++;
 992                                 }
 993                                 switch (clientsp[i].state) {
 994                                 case DISCOVER:
 995                                         discover++;
 996                                         break;
 997                                 case OFFER:
 998                                         offer++;
 999                                         break;
1000                                 case REQUEST:
1001                                         req++;
1002                                         break;
1003                                 case DECLINE:
1004                                         decline++;
1005                                         break;
1006                                 case ACK:
1007                                         ack++;
1008                                         break;
1009                                 case NAK:
1010                                         nak++;
1011                                         break;
1012                                 case RELEASE:
1013                                         release++;
1014                                         break;
1015                                 case INFORM:
1016                                         inform++;
1017                                         break;
1018                                 default:
1019                                         unknown++;
1020                                         break;
1021                                 }
1022                                 if (clientsp[i].ltime == NULL ||
1023                                     (clientsp[i].flags & CLIENT_BUSY) == 0)
1024                                         unstarted++;
1025                                 if (clientsp[i].ltime &&
1026                                     clientsp[i].ltime < old) {
1027                                         old = clientsp[i].ltime;
1028                                         oldi = i;
1029                                 }
1030                                 if (clientsp[i].ltime &&
1031                                     clientsp[i].ltime > new) {
1032                                         new = clientsp[i].ltime;
1033                                 }
1034                         }
1035 
1036                         if (time(NULL) < ltime + sample_time)
1037                                 continue;
1038                         ltime = time(NULL);
1039 
1040                         if (start == 0) {
1041                                 /* toss initial sample */
1042                                 ostart = start = time(NULL);
1043                                 otops = tops = 0;
1044                                 minind = 0;
1045                         } else {
1046                                 minops[minind] = tops - otops;
1047                                 mintim[minind] = ostart;
1048                                 otops = tops;
1049                                 ostart = time(NULL);
1050                                 minind = minind + 1 > nsamples - 1 ? 0 :
1051                                     minind + 1;
1052                                 minstime = 0;
1053                                 minavg = 0;
1054                                 for (i = 0; i < nsamples; i++) {
1055                                         if (mintim[i])
1056                                                 minavg += minops[i];
1057                                         if (minstime == 0)
1058                                                 minstime = mintim[i];
1059                                         else if (mintim[i] &&
1060                                             mintim[i] < minstime)
1061                                                 minstime = mintim[i];
1062                                 }
1063 
1064                                 cidlen = sizeof (cid);
1065                                 (void) octet_to_hexascii(clientsp[oldi].chaddr,
1066                                 clientsp[oldi].hlen, cid, &cidlen);
1067                                 fprintf(stderr, "%9.9d: Totops %d Curr %d "
1068                                     "Persec %4.2f (%4.2f) Oldest %d (%d) "
1069                                     "Gap %d Free %d\n", time(NULL), tops,
1070                                     ops_outstanding,
1071                                     (double)tops / (double)(time(NULL) - start),
1072                                     (double)minavg / (double)(time(NULL)
1073                                     - minstime),
1074                                     time(NULL) - old, clientsp[oldi].id, cid,
1075                                     new - old, unstarted);
1076                                 fprintf(stderr, "\tdiscov %d off %d req %d "
1077                                     "decl %d ack %d nak %d rel %d inf %d "
1078                                     "free/unknown %d\n", discover, offer, req,
1079                                     decline, ack, nak, release, inform,
1080                                     unknown);
1081                         }
1082                         break;
1083                 case SIGINT:
1084                         /* FALLTHRU */
1085                 case SIGTERM:
1086                         (void) sig2str(sig, buf);
1087                         (void) fprintf(stderr,
1088                             "Signal: %s received...Exiting\n", buf);
1089                         (void) mutex_lock(&go_mtx);
1090                         time_to_go = B_TRUE;
1091                         (void) cond_broadcast(&go_cv);
1092                         (void) mutex_unlock(&go_mtx);
1093                         for (i = 0; i < clients; i++) {
1094                                 (void) mutex_lock(&clientsp[i].mtx);
1095                                 (void) cond_signal(&clientsp[i].acv);
1096                                 (void) mutex_unlock(&clientsp[i].mtx);
1097                         }
1098                         leave = B_TRUE;
1099                         break;
1100                 default:
1101                         (void) sig2str(sig, buf);
1102                         (void) fprintf(stderr,
1103                             "Signal: %s received...Ignoring\n", buf);
1104                         leave = B_FALSE;
1105                         break;
1106                 }
1107         }
1108         thr_exit((void *) NULL);
1109         return (NULL);          /* NOTREACHED */
1110 }
1111 
1112 int
1113 main(int argc, char *argv[])
1114 {
1115         boolean_t proto;
1116         int i, j, threrror = 0, *threrrorp;
1117         int sockoptbuf = 1;
1118         register char *endp, *octet;
1119         thread_t service_id, sig_id;
1120         sigset_t set;
1121         uint_t buf;
1122         int slen;
1123         socklen_t sslen = sizeof (slen);
1124         unsigned int ifceno;
1125         char cifname[IFNAMSIZ];
1126         struct rlimit rl;
1127 
1128         if (randcl)
1129                 srandom(time(NULL));
1130 
1131         if (dofork) {
1132                 if (fork() != 0)
1133                         exit(0);
1134         }
1135         if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
1136                 (void) fprintf(stderr, "Cannot get open file limit: %s\n",
1137                     strerror(errno));
1138         }
1139         /* handle cases where limit is infinity */
1140         if (rl.rlim_cur == RLIM_INFINITY) {
1141                 rl.rlim_cur = (rl.rlim_max == RLIM_INFINITY) ?
1142                         OPEN_MAX : rl.rlim_max;
1143         }
1144         /* set NOFILE to unlimited */
1145         rl.rlim_cur = rl.rlim_max = RLIM_INFINITY;
1146         if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
1147                 (void) fprintf(stderr, "Cannot set open file limit: %s\n",
1148                     strerror(errno));
1149         }
1150         (void) enable_extended_FILE_stdio(-1, -1);
1151 
1152         if (argc < 5) {
1153                 (void) fprintf(stderr, "%s <interface> <ether_addr> <protocol> "
1154                     "<clients> [time] [desynch] [avg] [relayaddr]\n", argv[0]);
1155                 return (1);
1156         }
1157         (void) strcpy(ifname, argv[1]);
1158         (void) strcpy(cifname, argv[1]);
1159         if ((endp = strchr(ifname, ':')) != NULL) {
1160                 *endp = '\0';
1161                 startindex = strtol(endp + 1, 0L, 0L);
1162         }
1163         if (strcasecmp(argv[3], "dhcp") == 0)
1164                 proto = B_TRUE;
1165         else
1166                 proto = B_FALSE;
1167 
1168         clients = atoi(argv[4]);
1169 
1170         if (argc >= 6) {
1171                 release_time = atoi(argv[5]);
1172         }
1173         if (argc >= 7)
1174                 desynch = atoi(argv[6]);
1175 
1176         if (argc >= 8) {
1177                 avg = atof(argv[7]);
1178                 if (avg > 0.0) {
1179                         avgslp.tv_sec = avg;
1180                         avgslp.tv_nsec = (avg -
1181                             (double)((int)avg)) * 1000000000.0;
1182                 } else if (avg < 0.0) {
1183                         avgslp.tv_sec = abs((int)avg);
1184                         avgslp.tv_nsec = (avg + abs((double)((int)avg))) *
1185                             1000000000.0;
1186                 }
1187         }
1188         if (argc >= 9)
1189                 relay.s_addr = inet_addr(argv[8]);
1190 
1191         if (argc >= 10)
1192                 slen = strtol(argv[0], 0L, 0L);
1193         else
1194                 slen = 1024 * 64;
1195 
1196         if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
1197                 perror("Socket");
1198                 return (1);
1199         }
1200         (void) setsockopt(s, SOL_SOCKET, SO_SNDBUF, &slen, sslen);
1201         (void) setsockopt(s, SOL_SOCKET, SO_RCVBUF, &slen, sslen);
1202 
1203         if (relay.s_addr == INADDR_ANY)
1204                 if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char *)&sockoptbuf,
1205                     (int)sizeof (sockoptbuf)) < 0) {
1206                         perror("Setsockopt");
1207                         return (2);
1208                 }
1209         if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
1210             (char *)&sockoptbuf, (int)sizeof (sockoptbuf)) < 0) {
1211                 perror("Setsockopt: REUSEADDR");
1212                 return (2);
1213         }
1214         if (relay.s_addr != INADDR_ANY) {
1215                 relfrom.sin_port = htons(IPPORT_BOOTPS + port_offset);
1216                 relfrom.sin_family = AF_INET;
1217                 relfrom.sin_addr.s_addr = INADDR_ANY;
1218                 relfrom.sin_port = htons(IPPORT_BOOTPS + port_offset);
1219 
1220                 (void) strncpy(lifr.lifr_name, cifname,
1221                     sizeof (lifr.lifr_name));
1222                 if (lrecv) {
1223                         if (ioctl(s, SIOCGLIFADDR, (char *)&lifr) < 0) {
1224                             (void) fprintf(stderr, "Warning: SIOCGLIFADDR: %s",
1225                                 strerror(errno));
1226                         } else {
1227                                 relfrom.sin_addr.s_addr =
1228                                     ((struct sockaddr_in *)
1229                                     &lifr.lifr_addr)->sin_addr.s_addr;
1230                         }
1231                 }
1232 
1233                 if ((srelay = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
1234                         perror("Socket");
1235                         return (1);
1236                 }
1237                 (void) setsockopt(srelay, SOL_SOCKET, SO_SNDBUF, &slen, sslen);
1238                 (void) setsockopt(srelay, SOL_SOCKET, SO_RCVBUF, &slen, sslen);
1239 
1240                 if (setsockopt(srelay, SOL_SOCKET, SO_REUSEADDR,
1241                     (char *)&sockoptbuf, (int)sizeof (sockoptbuf)) < 0) {
1242                         perror("Setsockopt: REUSEADDR");
1243                         return (2);
1244                 }
1245                 if (bind(srelay, (struct sockaddr *)&relfrom,
1246                     sizeof (relfrom)) < 0) {
1247                         perror("Bind");
1248                         return (3);
1249                 }
1250                 ifceno = if_nametoindex(cifname);
1251                 if (bound) {
1252                         if (setsockopt(s, IPPROTO_IP, IP_BOUND_IF,
1253                             (char *)&ifceno, (int)sizeof (char *)) < 0) {
1254                                 perror("Setsockopt bind");
1255                                 return (3);
1256                         }
1257                 }
1258         }
1259         from.sin_family = AF_INET;
1260         if (relay.s_addr != INADDR_ANY) {
1261                 from.sin_addr.s_addr =
1262                     ((struct sockaddr_in *)&lifr.lifr_addr)->sin_addr.s_addr;
1263         } else {
1264                 from.sin_addr.s_addr = INADDR_ANY;
1265         }
1266         from.sin_port = htons(IPPORT_BOOTPC + port_offset);
1267 
1268         if (bind(s, (struct sockaddr *)&from, sizeof (from)) < 0) {
1269                 perror("Bind");
1270                 return (3);
1271         }
1272         ifceno = if_nametoindex(cifname);
1273         if (bound) {
1274                 if (setsockopt(s, IPPROTO_IP, IP_BOUND_IF,
1275                     (char *)&ifceno, (int)sizeof (char *)) < 0) {
1276                         perror("Setsockopt bind");
1277                         return (3);
1278                 }
1279         }
1280         request.op = 1;         /* BOOTP request */
1281         request.htype = 1;      /* Ethernet */
1282         request.hlen = 6;       /* Ethernet addr len */
1283 
1284         endp = octet = argv[2];
1285         for (i = 0; i < (int)request.hlen && octet != NULL; i++) {
1286                 if ((endp = (char *)strchr(endp, ':')) != NULL)
1287                         *endp++ = '\0';
1288                 (void) sscanf(octet, "%x", &buf);
1289                 request.chaddr[i] = (uchar_t)buf;
1290                 octet = endp;
1291         }
1292 
1293         /* broadcast bit */
1294         if (relay.s_addr == INADDR_ANY)
1295                 request.flags = htons(0x8000);
1296 
1297         /* magic cookie */
1298         request.cookie[0] = 99;
1299         request.cookie[1] = 130;
1300         request.cookie[2] = 83;
1301         request.cookie[3] = 99;
1302 
1303         if (proto) {
1304                 /* Pretend to be a discover packet */
1305                 request.options[0] = CD_DHCP_TYPE;
1306                 request.options[1] = 1;
1307                 request.options[2] = DISCOVER;
1308                 request.options[3] = 0xff;
1309 
1310                 (void) cond_init(&go_cv, USYNC_THREAD, NULL);
1311                 (void) mutex_init(&go_mtx, USYNC_THREAD, NULL);
1312         }
1313         if (relay.s_addr != INADDR_ANY)
1314                 request.giaddr.s_addr = from.sin_addr.s_addr;
1315 
1316         (void) sigfillset(&set);
1317 
1318         (void) sigdelset(&set, SIGABRT);    /* allow for user abort */
1319 
1320         (void) thr_sigsetmask(SIG_SETMASK, &set, NULL);
1321 
1322         /*
1323          * Create the client threads
1324          */
1325         clientsp = malloc(sizeof (struct client) * clients);
1326         (void) memset(clientsp, 0, sizeof (struct client) * clients);
1327         if (clientsp == NULL)
1328                 return (1);
1329 
1330         for (i = 0; i < clients; i++) {
1331                 (void) memcpy(clientsp[i].chaddr, request.chaddr, request.hlen);
1332                 clientsp[i].hlen = request.hlen;
1333                 if (i > 100)
1334                         j = 3;
1335                 else if (i > 50)
1336                         j = 2;
1337                 else
1338                         j = 1;
1339 
1340                 if (i) {
1341                         clientsp[i].chaddr[j] = (unsigned char) i;
1342                         clientsp[i].chaddr[3] += (unsigned char) j;
1343                         clientsp[i].chaddr[4] = (unsigned char) (i * j);
1344                 }
1345                 if (printid)
1346                         fprintf(stderr, "ID %x:%x:%x:%x:%x:%x\n",
1347                                 clientsp[i].chaddr[0],
1348                                 clientsp[i].chaddr[1],
1349                                 clientsp[i].chaddr[2],
1350                                 clientsp[i].chaddr[3],
1351                                 clientsp[i].chaddr[4],
1352                                 clientsp[i].chaddr[5]);
1353 
1354                 (void) cond_init(&clientsp[i].cv, USYNC_THREAD, 0);
1355                 (void) mutex_init(&clientsp[i].mtx, USYNC_THREAD, 0);
1356                 clientsp[i].proto = proto;
1357                 clientsp[i].flags = CLIENT_FIRSTTIME;
1358                 if (thr_create(NULL, NULL, client, (void *) &clientsp[i],
1359                     THR_BOUND | THR_SUSPENDED, &clientsp[i].id) != 0) {
1360                         (void) fprintf(stderr, "Error starting Client %04d\n",
1361                             clientsp[i].id);
1362                 }
1363         }
1364 
1365         /*
1366          * Create signal handling thread.
1367          */
1368         if (thr_create(NULL, 0, sig_handle, NULL,
1369         THR_BOUND | THR_DAEMON | THR_DETACHED, &sig_id) != 0) {
1370                 (void) fprintf(stderr, "Error starting signal handler.\n");
1371                 return (1);
1372         } else
1373                 (void) fprintf(stderr, "Started Signal handler: %04d...\n",
1374                     sig_id);
1375 
1376         /*
1377          * Create/start the service thread.
1378          */
1379         if (thr_create(NULL, NULL, service, (void *) clientsp, THR_BOUND,
1380             &service_id) != 0) {
1381                 (void) fprintf(stderr, "Error starting Service %d\n",
1382                     service_id);
1383                 exit(1);
1384         } else
1385                 (void) fprintf(stderr, "Started Service %04d...\n",
1386                     service_id);
1387 
1388         /*
1389          * Continue the client threads.
1390          */
1391         for (i = 0; i < clients; i++) {
1392                 (void) thr_continue(clientsp[i].id);
1393         }
1394 
1395         /*
1396          * join them
1397          */
1398         threrrorp = &threrror;
1399         for (i = 0; i < clients; i++) {
1400                 if (thr_join(clientsp[i].id, NULL, (void **) &threrrorp) == 0) {
1401                         if (threrror != 0) {
1402                                 (void) fprintf(stdout,
1403                                     "Client %04d - exited with %d\n",
1404                                     clientsp[i].id, threrror);
1405                         }
1406                         (void) cond_destroy(&clientsp[i].cv);
1407                         (void) mutex_destroy(&clientsp[i].mtx);
1408                 }
1409         }
1410 
1411         (void) close(s);        /* force service out of poll */
1412 
1413         if (thr_join(service_id, NULL, (void **) &threrrorp) == 0) {
1414                 if (threrror != 0) {
1415                         (void) fprintf(stdout, "Service - exited with %d\n",
1416                             threrror);
1417                 }
1418         }
1419         (void) free((char *)clientsp);
1420         (void) fprintf(stdout, "Exiting...\n");
1421 
1422         return (0);
1423 }
1424 
1425 /*
1426  * corrupt: simulate packet corruption for debugging server
1427  */
1428 static void
1429 corrupt(char *pktp, int size)
1430 {
1431         int c;
1432         int i;
1433         int p;
1434         char *pp;
1435         char *pe = pktp + size;
1436         int li = rand() % (size - 1) + 1;
1437 
1438         for (pp = pktp; pp < pe; pp += li) {
1439                 c = ((pe - pp) < li ? pe - pp : li);
1440                 i = (rand() % c)>>1;
1441                 while (--i > 0) {
1442                         p = (rand() % c);
1443                         pp[p] = (unsigned char)(rand() & 0xFF);
1444                 }
1445         }
1446 }