00001
00002
00003
00004
00005 #include <sys/types.h>
00006 #include <stdio.h>
00007 #include <stddef.h>
00008 #include <stdlib.h>
00009 #include <unistd.h>
00010 #include <fcntl.h>
00011 #include <errno.h>
00012 #include <signal.h>
00013 #include <string.h>
00014 #include <time.h>
00015 #include <limits.h>
00016 #include <configfile.h>
00017 #include <sys/ioctl.h>
00018 #include <sys/asynchio.h>
00019 #include <net/hton.h>
00020 #include <net/gen/socket.h>
00021 #include <net/gen/netdb.h>
00022 #include <net/gen/in.h>
00023 #include <net/gen/inet.h>
00024 #include <net/gen/ether.h>
00025 #include <net/gen/if_ether.h>
00026 #include <net/gen/eth_hdr.h>
00027 #include <net/gen/ip_hdr.h>
00028 #include <net/gen/udp.h>
00029 #include <net/gen/udp_hdr.h>
00030 #include <net/gen/udp_io.h>
00031 #include <net/gen/dhcp.h>
00032 #include "arp.h"
00033 #define EXTERN
00034 #include "dhcpd.h"
00035
00036 char *configfile= PATH_DHCPCONF;
00037 char *poolfile= PATH_DHCPPOOL;
00038 static char *cachefile= PATH_DHCPCACHE;
00039 static int qflag;
00040 static int aflag, rflag;
00041
00042 #define BCAST_IP HTONL(0xFFFFFFFFUL)
00043
00044
00045 #define N_NETS 32
00046 static unsigned n_nets;
00047
00048 void report(const char *label)
00049 {
00050 static FILE *logfp;
00051 if(!logfp)
00052 logfp = fopen("/usr/log/dhcp.log", "w");
00053 if(logfp)
00054 fprintf(logfp, "%s: %s: %s\n", program, label, strerror(errno));
00055 }
00056
00057 void fatal(const char *label)
00058 {
00059 report(label);
00060 exit(1);
00061 }
00062
00063 void *allocate(size_t size)
00064 {
00065 void *mem;
00066
00067 if ((mem= malloc(size)) == nil) fatal("Can't allocate memory");
00068 return mem;
00069 }
00070
00071
00072
00073
00074 #define XID(np) htonl(((u32_t) (np)->start << 8) | (np)->n)
00075
00076 static network_t *network[N_NETS];
00077
00078 int ifname2if(const char *name)
00079 {
00080
00081 char *end;
00082 unsigned long n;
00083
00084 if (*name++ != 'i' || *name++ != 'p') return -1;
00085 n= strtoul(name, &end, 10);
00086 if (end == name || *end != 0) return -1;
00087 if (n >= N_NETS) return -1;
00088 return n;
00089 }
00090
00091 network_t *if2net(int n)
00092 {
00093
00094 int i;
00095
00096 for (i= 0; i < n_nets; i++) {
00097 if (network[i]->n == n) return network[i];
00098 }
00099 return nil;
00100 }
00101
00102 static ipaddr_t defaultmask(ipaddr_t ip)
00103 {
00104
00105 if (B(&ip)[0] < 0x80) return HTONL(0xFF000000UL);
00106 if (B(&ip)[0] < 0xC0) return HTONL(0xFFFF0000UL);
00107 if (B(&ip)[0] < 0xE0) return HTONL(0xFFFFFF00UL);
00108 return HTONL(0xFFFFFFFFUL);
00109 }
00110
00111 #define POOL_MAGIC HTONL(0x81F85D00UL)
00112
00113 typedef struct pool {
00114 u32_t magic;
00115 ipaddr_t ip;
00116 u32_t expire;
00117 u8_t len;
00118 u8_t unused[19];
00119 u8_t clid[CLID_MAX];
00120 } pool_t;
00121
00122 static int openpool(int mode)
00123 {
00124
00125 int fd;
00126 struct flock lck;
00127
00128 if ((fd= open(poolfile, mode, 0644)) < 0) {
00129 if (errno != ENOENT) fatal(poolfile);
00130 return -1;
00131 }
00132 if (mode != O_RDONLY) {
00133 lck.l_type= F_WRLCK;
00134 lck.l_whence= SEEK_SET;
00135 lck.l_start= 0;
00136 lck.l_len= 0;
00137 if (fcntl(fd, F_SETLKW, &lck) < 0) fatal(poolfile);
00138 }
00139 return fd;
00140 }
00141
00142 static int readpool(int fd, pool_t *entry)
00143 {
00144
00145 ssize_t r;
00146
00147 if ((r= read(fd, entry, sizeof(*entry))) < 0) fatal(poolfile);
00148 if (r == 0) return 0;
00149
00150 if (r != sizeof(*entry) || entry->magic != POOL_MAGIC) {
00151 fprintf(stderr, "%s: %s: Pool table is corrupt\n",
00152 program, poolfile);
00153 close(fd);
00154 return 0;
00155 }
00156 return 1;
00157 }
00158
00159 #if !__minix_vmd
00160 #define fsync(fd) sync()
00161 #endif
00162
00163 static void writepool(int fd, pool_t *entry)
00164 {
00165
00166 if (write(fd, entry, sizeof(*entry)) < 0
00167 || (entry->expire > now && fsync(fd) < 0)
00168 ) {
00169 fatal(poolfile);
00170 }
00171 }
00172
00173 static ipaddr_t findpool(u8_t *client, size_t len, ipaddr_t ifip)
00174 {
00175
00176
00177
00178
00179 int fd, found;
00180 pool_t entry, oldest;
00181 dhcp_t dhcp;
00182 u8_t *pmask;
00183 ipaddr_t mask;
00184
00185
00186 if (!makedhcp(&dhcp, nil, 0, nil, 0, ifip, ifip, nil)) return 0;
00187
00188 if ((fd= openpool(O_RDWR)) < 0) return 0;
00189
00190 (void) gettag(&dhcp, DHCP_TAG_NETMASK, &pmask, nil);
00191 memcpy(&mask, pmask, sizeof(mask));
00192
00193 oldest.expire= NEVER;
00194 while ((found= readpool(fd, &entry))) {
00195
00196 if (entry.ip == 0) continue;
00197
00198
00199 if (((entry.ip ^ ifip) & mask) != 0) continue;
00200
00201
00202 if (entry.len == len && memcmp(entry.clid, client, len) == 0) break;
00203
00204
00205 entry.expire= ntohl(entry.expire);
00206 if (entry.expire < oldest.expire) oldest= entry;
00207 }
00208 close(fd);
00209
00210 if (found) return entry.ip;
00211 if (oldest.expire <= now) return oldest.ip;
00212 return 0;
00213 }
00214
00215 static int commitpool(ipaddr_t ip, u8_t *client, size_t len, time_t expire)
00216 {
00217
00218 int fd;
00219 pool_t entry;
00220
00221 if ((fd= openpool(O_RDWR)) < 0) return 0;
00222
00223 do {
00224 if (!readpool(fd, &entry)) {
00225 close(fd);
00226 return 0;
00227 }
00228 } while (entry.ip != ip);
00229
00230 entry.expire= htonl(expire);
00231 entry.len= len;
00232 memcpy(entry.clid, client, len);
00233 if (lseek(fd, -(off_t)sizeof(entry), SEEK_CUR) == -1) fatal(poolfile);
00234 writepool(fd, &entry);
00235 close(fd);
00236 return 1;
00237 }
00238
00239 static void updatepool(int add, const char *name)
00240 {
00241
00242 ipaddr_t ip;
00243 int fd, i;
00244 pool_t entry;
00245 struct hostent *he;
00246 off_t off, off0;
00247
00248 if ((he= gethostbyname(name)) == nil || he->h_addrtype != AF_INET) {
00249 fprintf(stderr, "%s: %s: Unknown host\n", program, name);
00250 exit(1);
00251 }
00252 for (i= 0; he->h_addr_list[i] != nil; i++) {}
00253 if (i != 1) {
00254 fprintf(stderr, "%s: %s has %d addresses\n", program, name, i);
00255 exit(1);
00256 }
00257 memcpy(&ip, he->h_addr_list[0], sizeof(ip));
00258
00259 if ((fd= openpool(O_RDWR|O_CREAT)) < 0) fatal(poolfile);
00260
00261 off= 0;
00262 off0= -1;
00263 while (readpool(fd, &entry)) {
00264 if (add) {
00265 if (entry.ip == ip) {
00266 fprintf(stderr, "%s: %s: %s is already present\n",
00267 program, poolfile, name);
00268 exit(1);
00269 }
00270 if (entry.ip == 0 && off0 == -1) off0= off;
00271 } else {
00272 if (entry.ip == ip) {
00273 memset(&entry, 0, sizeof(entry));
00274 entry.magic= POOL_MAGIC;
00275 entry.ip= 0;
00276 if (lseek(fd, off, SEEK_SET) == -1) fatal(poolfile);
00277 writepool(fd, &entry);
00278 }
00279 }
00280 off+= sizeof(entry);
00281 }
00282
00283 if (add) {
00284 if (off0 != -1 && lseek(fd, off0, SEEK_SET) == -1) fatal(poolfile);
00285 memset(&entry, 0, sizeof(entry));
00286 entry.magic= POOL_MAGIC;
00287 entry.ip= ip;
00288 writepool(fd, &entry);
00289 }
00290 close(fd);
00291 }
00292
00293 static void cachedhcp(int n, dhcp_t *dp)
00294 {
00295
00296 static int inited;
00297 FILE *fp;
00298 int fd;
00299 int mode;
00300
00301 if (test > 0) return;
00302
00303 if (!inited) {
00304
00305 if ((fp= fopen(PATH_DHCPPID, "w")) != nil) {
00306 if (fprintf(fp, "%d\n", getpid()) == EOF || fclose(fp) == EOF) {
00307 fatal(PATH_DHCPPID);
00308 }
00309 }
00310 inited= 1;
00311 mode= O_WRONLY | O_CREAT | O_TRUNC;
00312 } else {
00313 mode= O_WRONLY;
00314 }
00315
00316 dp->xid= htonl(now);
00317
00318 if ((fd= open(cachefile, mode, 0666)) < 0
00319 || lseek(fd, (off_t) n * sizeof(*dp), SEEK_SET) == -1
00320 || write(fd, dp, sizeof(*dp)) < 0
00321 || close(fd) < 0
00322 ) {
00323 if (errno != ENOENT) fatal(cachefile);
00324 }
00325 }
00326
00327 static void printdata(void)
00328 {
00329
00330 int fd;
00331 dhcp_t d;
00332 ssize_t r;
00333 int i;
00334 pool_t entry;
00335 unsigned long expire;
00336 char delta[3*sizeof(u32_t)];
00337
00338 initdhcpconf();
00339
00340 if ((fd= open(cachefile, O_RDONLY)) < 0) fatal(cachefile);
00341 i= 0;
00342 while ((r= read(fd, &d, sizeof(d))) == sizeof(d)) {
00343 if (d.yiaddr != 0) {
00344 printf("DHCP data for network %d:\n", i);
00345 printdhcp(&d);
00346 }
00347 i++;
00348 }
00349 if (r < 0) fatal(cachefile);
00350 close(fd);
00351
00352 if ((fd= openpool(O_RDONLY)) >= 0) {
00353 printf("Dynamic address pool since %ld:\n", (long) now);
00354 while (readpool(fd, &entry)) {
00355 if (entry.ip == 0) continue;
00356 expire= ntohl(entry.expire);
00357 if (expire == 0) {
00358 strcpy(delta, "unused");
00359 } else
00360 if (expire == 0xFFFFFFFFUL) {
00361 strcpy(delta, "infinite");
00362 } else
00363 if (expire < now) {
00364 sprintf(delta, "-%lu", now - expire);
00365 } else {
00366 sprintf(delta, "+%lu", expire - now);
00367 }
00368 printf("\t%-15s %8s ", inet_ntoa(entry.ip), delta);
00369 for (i= 0; i < entry.len; i++) {
00370 printf("%02X", entry.clid[i]);
00371 }
00372 fputc('\n', stdout);
00373 }
00374 close(fd);
00375 }
00376 }
00377
00378 static udpport_t portbyname(const char *name)
00379 {
00380 struct servent *se;
00381
00382 if ((se= getservbyname(name, "udp")) == nil) {
00383 fprintf(stderr, "%s: Unknown port \"%s\"\n", program, name);
00384 exit(1);
00385 }
00386 return se->s_port;
00387 }
00388
00389 static int send(network_t *np, void *data, size_t len)
00390 {
00391
00392
00393
00394 int fd;
00395 ssize_t r;
00396
00397 if ((fd= dup(np->fdp->fd)) < 0) fatal("Can't dup()");
00398 if ((r= write(fd, data, len)) < 0) {
00399 report(np->fdp->device);
00400 sleep(10);
00401 }
00402 close(fd);
00403 return r >= 0;
00404 }
00405
00406 static size_t servdhcp(network_t *np, buf_t *bp, size_t dlen)
00407 {
00408 buf_t *abp= nil;
00409 ipaddr_t cip, ifip;
00410 u8_t defclid[1+sizeof(bp->dhcp->chaddr)];
00411 u8_t *pdata, *client, *class, *server, *reqip, *lease;
00412 u32_t expire;
00413 size_t len, cilen, calen;
00414 int type, dyn;
00415 u8_t atype;
00416 static char NAKMESS[] = "IP address requested isn't yours";
00417
00418 if (test > 0) return 0;
00419
00420
00421 ifip= bp->dhcp->giaddr != 0 ? bp->dhcp->giaddr : np->ip;
00422
00423
00424 if (gettag(bp->dhcp, DHCP_TAG_TYPE, &pdata, nil)) {
00425 type= *pdata;
00426 } else {
00427 type= -1;
00428 }
00429
00430 if (!gettag(bp->dhcp, DHCP_TAG_CLIENTID, &client, &cilen)) {
00431 defclid[0]= bp->dhcp->htype;
00432 memcpy(defclid+1, bp->dhcp->chaddr, bp->dhcp->hlen);
00433 client= defclid;
00434 cilen= 1+bp->dhcp->hlen;
00435 }
00436
00437 if (!gettag(bp->dhcp, DHCP_TAG_CLASSID, &class, &calen)) {
00438 calen= 0;
00439 }
00440
00441 if (!gettag(bp->dhcp, DHCP_TAG_SERVERID, &server, nil)) {
00442 server= B(&np->ip);
00443 }
00444
00445 if (!gettag(bp->dhcp, DHCP_TAG_REQIP, &reqip, nil)) {
00446 reqip= nil;
00447 }
00448
00449
00450 if ((np->flags & NF_SERVING)
00451 && bp->dhcp->op == DHCP_BOOTREQUEST
00452 && between(1, bp->dhcp->hlen, sizeof(bp->dhcp->chaddr))
00453 && (server == nil || memcmp(server, &np->ip, sizeof(np->ip)) == 0)
00454 ) {
00455 get_buf(&abp);
00456
00457
00458 (void) makedhcp(abp->dhcp, class, calen, client, cilen, 0, ifip, nil);
00459 cip= abp->dhcp->yiaddr;
00460
00461 dyn= 0;
00462
00463 if (cip == 0 && (cip= findpool(client, cilen, ifip)) != 0) dyn= 1;
00464
00465 if (type == DHCP_INFORM) {
00466
00467
00468
00469
00470 if (cip != 0 || (np->flags & NF_INFORM)) cip= bp->dhcp->ciaddr;
00471 }
00472
00473 if (cip == 0 || !makedhcp(abp->dhcp, class, calen,
00474 client, cilen, cip, ifip, nil)) {
00475 put_buf(&abp);
00476 }
00477
00478 if (abp != nil) {
00479 if (gettag(abp->dhcp, DHCP_TAG_LEASE, &lease, nil)) {
00480 memcpy(&expire, lease, sizeof(expire));
00481 expire= now + ntohl(expire);
00482 if (expire < now) expire= 0xFFFFFFFFUL;
00483 } else {
00484 if (dyn) {
00485
00486 fprintf(stderr, "%s: No lease set for address %s\n",
00487 program, inet_ntoa(cip));
00488 exit(1);
00489 }
00490 lease= nil;
00491 expire= 0xFFFFFFFFUL;
00492 }
00493
00494
00495 switch (type) {
00496 case DHCP_DISCOVER:
00497 atype= DHCP_OFFER;
00498
00499
00500 if (dyn && !commitpool(cip, client, cilen, now + DELTA_FAST)) {
00501 put_buf(&abp);
00502 }
00503 break;
00504
00505 case -1:
00506 case DHCP_REQUEST:
00507 case DHCP_INFORM:
00508 atype= DHCP_ACK;
00509
00510 if ((reqip != nil && memcmp(reqip, &cip, sizeof(cip)) != 0)
00511 || (bp->dhcp->ciaddr != 0 && bp->dhcp->ciaddr != cip)
00512 ) {
00513 atype= DHCP_NAK;
00514 } else
00515 if (dyn && type == DHCP_REQUEST) {
00516
00517 if (!commitpool(cip, client, cilen, expire)) put_buf(&abp);
00518 }
00519 break;
00520
00521 case DHCP_DECLINE:
00522
00523 if (dyn
00524 && reqip != nil
00525 && memcmp(reqip, &cip, sizeof(cip)) == 0
00526 ) {
00527 int i;
00528
00529 fprintf(stderr, "%s: ", program);
00530 for (i= 0; i < cilen; i++) {
00531 fprintf(stderr, "%02X", client[i]);
00532 }
00533 fprintf(stderr, " declines %s", inet_ntoa(cip));
00534 if (gettag(bp->dhcp, DHCP_TAG_MESSAGE, &pdata, &len)) {
00535 fprintf(stderr, " saying: \"%.*s\"", (int)len, pdata);
00536 }
00537 fputc('\n', stderr);
00538
00539
00540 (void) commitpool(cip, nil, 0, expire);
00541 }
00542 put_buf(&abp);
00543 break;
00544
00545 case DHCP_RELEASE:
00546
00547 if (dyn) (void) commitpool(cip, client, cilen, now);
00548 put_buf(&abp);
00549 break;
00550
00551 default:
00552 put_buf(&abp);
00553 }
00554 }
00555
00556 if (abp != nil) {
00557
00558 abp->dhcp->htype= bp->dhcp->htype;
00559 abp->dhcp->hlen= bp->dhcp->hlen;
00560 abp->dhcp->hops= 0;
00561 abp->dhcp->xid= bp->dhcp->xid;
00562 abp->dhcp->secs= 0;
00563 abp->dhcp->flags= bp->dhcp->flags;
00564 abp->dhcp->ciaddr= 0;
00565 abp->dhcp->yiaddr= atype == DHCP_NAK ? 0 : cip;
00566 if (atype == DHCP_NAK) abp->dhcp->siaddr= 0;
00567 abp->dhcp->giaddr= bp->dhcp->giaddr;
00568 memcpy(abp->dhcp->chaddr,bp->dhcp->chaddr,sizeof(bp->dhcp->chaddr));
00569
00570 settag(abp->dhcp, DHCP_TAG_SERVERID, &np->ip, sizeof(np->ip));
00571
00572 if (lease == nil) {
00573
00574 settag(abp->dhcp, DHCP_TAG_LEASE, &expire, sizeof(expire));
00575 }
00576
00577 if (type == DHCP_INFORM) {
00578
00579 abp->dhcp->yiaddr= 0;
00580 settag(abp->dhcp, DHCP_TAG_LEASE, nil, 0);
00581 settag(abp->dhcp, DHCP_TAG_RENEWAL, nil, 0);
00582 settag(abp->dhcp, DHCP_TAG_REBINDING, nil, 0);
00583 }
00584
00585 if (atype == DHCP_NAK) {
00586
00587 memset(abp->dhcp->sname, 0, sizeof(abp->dhcp->sname));
00588 memset(abp->dhcp->file, 0, sizeof(abp->dhcp->file));
00589 memset(abp->dhcp->options, 255, sizeof(abp->dhcp->options));
00590 settag(abp->dhcp, DHCP_TAG_MESSAGE, NAKMESS, sizeof(NAKMESS));
00591 }
00592
00593 settag(abp->dhcp, DHCP_TAG_TYPE, &atype, sizeof(atype));
00594
00595
00596 abp->udpio->uih_src_addr= np->ip;
00597 abp->udpio->uih_src_port= port_server;
00598 if (bp->dhcp->giaddr != 0) {
00599 abp->udpio->uih_dst_addr= bp->dhcp->giaddr;
00600 abp->udpio->uih_dst_port= port_server;
00601 } else
00602 if (bp->dhcp->flags & DHCP_FLAGS_BCAST) {
00603 abp->udpio->uih_dst_addr= BCAST_IP;
00604 abp->udpio->uih_dst_port= port_client;
00605 } else
00606 if (bp->udpio->uih_src_addr != 0
00607 && bp->udpio->uih_dst_addr == np->ip
00608 ) {
00609 abp->udpio->uih_dst_addr= bp->udpio->uih_src_addr;
00610 abp->udpio->uih_dst_port= port_client;
00611 } else {
00612 abp->udpio->uih_dst_addr= BCAST_IP;
00613 abp->udpio->uih_dst_port= port_client;
00614 }
00615 abp->udpio->uih_ip_opt_len= 0;
00616 abp->udpio->uih_data_len= sizeof(dhcp_t);
00617
00618
00619 memcpy(bp->buf, abp->buf, sizeof(bp->buf));
00620 put_buf(&abp);
00621 return sizeof(udp_io_hdr_t) + sizeof(dhcp_t);
00622 }
00623 }
00624
00625
00626 if ((np->flags & NF_RELAYING)
00627 && bp->dhcp->op == DHCP_BOOTREQUEST
00628 && bp->dhcp->giaddr == 0
00629 ) {
00630 bp->dhcp->giaddr= np->ip;
00631 bp->udpio->uih_src_addr= np->ip;
00632 bp->udpio->uih_src_port= port_server;
00633 bp->udpio->uih_dst_addr= np->server;
00634 bp->udpio->uih_dst_port= port_server;
00635 return dlen;
00636 }
00637
00638
00639 if ((np->flags & NF_RELAYING)
00640 && bp->dhcp->op == DHCP_BOOTREPLY
00641 && bp->dhcp->giaddr == np->ip
00642 ) {
00643 bp->dhcp->giaddr= 0;
00644 bp->udpio->uih_src_addr= np->ip;
00645 bp->udpio->uih_src_port= port_server;
00646 bp->udpio->uih_dst_addr= BCAST_IP;
00647 bp->udpio->uih_dst_port= port_client;
00648 return dlen;
00649 }
00650
00651
00652 return 0;
00653 }
00654
00655 static void onsig(int sig)
00656 {
00657 switch (sig) {
00658 case SIGUSR1: debug++; break;
00659 case SIGUSR2: debug= 0; break;
00660 }
00661 }
00662
00663 static void usage(void)
00664 {
00665 fprintf(stderr,
00666 "Usage: %s [-qar] [-t[L]] [-d[L]] [-f config] [-c cache] [-p pool] [host ...]\n",
00667 program);
00668 exit(1);
00669 }
00670
00671 int main(int argc, char **argv)
00672 {
00673 int i;
00674 network_t *np;
00675 struct sigaction sa;
00676 ssize_t r= -1;
00677 buf_t *bp= nil;
00678 static struct timeval eventtv;
00679
00680 program= argv[0];
00681 start= now= time(nil);
00682
00683 debug= 0;
00684 i= 1;
00685 while (i < argc && argv[i][0] == '-') {
00686 char *opt= argv[i++]+1;
00687
00688 if (opt[0] == '-' && opt[1] == 0) break;
00689
00690 while (*opt != 0) switch (*opt++) {
00691 case 'f':
00692 if (*opt == 0) {
00693 if (i == argc) usage();
00694 opt= argv[i++];
00695 }
00696 configfile= opt;
00697 opt= "";
00698 break;
00699 case 'c':
00700 if (*opt == 0) {
00701 if (i == argc) usage();
00702 opt= argv[i++];
00703 }
00704 cachefile= opt;
00705 opt= "";
00706 break;
00707 case 'p':
00708 if (*opt == 0) {
00709 if (i == argc) usage();
00710 opt= argv[i++];
00711 }
00712 poolfile= opt;
00713 opt= "";
00714 break;
00715 case 't':
00716 test= 1;
00717 if (between('0', *opt, '9')) test= strtoul(opt, &opt, 10);
00718 break;
00719 case 'd':
00720 debug= 1;
00721 if (between('0', *opt, '9')) debug= strtoul(opt, &opt, 10);
00722 break;
00723 case 'q':
00724 qflag= 1;
00725 break;
00726 case 'a':
00727 aflag= 1;
00728 break;
00729 case 'r':
00730 rflag= 1;
00731 break;
00732 default:
00733 usage();
00734 }
00735 }
00736 if (aflag + rflag + qflag > 1) usage();
00737
00738 if (aflag || rflag) {
00739
00740 while (i < argc) updatepool(aflag, argv[i++]);
00741 exit(0);
00742 }
00743
00744 if (i != argc) usage();
00745
00746 if (qflag) {
00747
00748 printdata();
00749 exit(0);
00750 }
00751
00752
00753 port_server= portbyname("bootps");
00754 port_client= portbyname("bootpc");
00755
00756 sa.sa_handler= onsig;
00757 sigemptyset(&sa.sa_mask);
00758 sa.sa_flags= 0;
00759 sigaction(SIGUSR1, &sa, nil);
00760 sigaction(SIGUSR2, &sa, nil);
00761
00762
00763 for (i= 0; i < N_NETS; i++) {
00764 int fd;
00765 ipaddr_t ip, mask;
00766
00767
00768 if ((fd= open(ipdev(i), O_RDWR|O_NONBLOCK)) < 0) {
00769 if (errno != ENOENT && errno != ENODEV && errno != ENXIO) {
00770 fatal(ipdev(i));
00771 }
00772 continue;
00773 }
00774 close(fd);
00775
00776 network[n_nets++]= np= newnetwork();
00777 np->n= i;
00778
00779
00780 if (opendev(np, FT_ETHERNET, 1)) {
00781 np->type= B(&np->eth)[0] != 'Z' ? NT_ETHERNET : NT_SINK;
00782 if (debug >= 1) {
00783 printf("%s: Ethernet address is %s%s\n",
00784 np->fdp->device, ether_ntoa(&np->eth),
00785 np->type == NT_SINK ? " (sink)" : "");
00786 }
00787 closedev(np, FT_ETHERNET);
00788 }
00789
00790
00791 if (np->type != NT_ETHERNET) np->renew= np->rebind= np->lease= NEVER;
00792 }
00793
00794
00795 for (i= 0; i < n_nets; i++) {
00796 ipaddr_t cip;
00797 u8_t clid[1+DHCP_HLEN_ETH];
00798 size_t cilen;
00799
00800 np= network[i];
00801 if (np->flags & NF_BOUND) continue;
00802
00803 if (np->type == NT_IP) {
00804 cilen= 0;
00805 } else {
00806 ether2clid(clid, &np->eth);
00807 cilen= 1+DHCP_HLEN_ETH;
00808 }
00809
00810
00811
00812
00813 get_buf(&bp);
00814 (void) makedhcp(bp->dhcp, (u8_t *) "Minix", 5,
00815 clid, cilen, np->ip, 0, np);
00816 cip= bp->dhcp->yiaddr;
00817
00818
00819 if (cip != 0
00820 && makedhcp(bp->dhcp, (u8_t *) "Minix", 5,
00821 clid, cilen, cip, cip, np)
00822 && test < 2
00823 ) {
00824 u8_t *pdata;
00825 u16_t mtu;
00826
00827 cachedhcp(np->n, bp->dhcp);
00828 np->ip= cip;
00829 (void) gettag(bp->dhcp, DHCP_TAG_NETMASK, &pdata, nil);
00830 memcpy(&np->mask, pdata, sizeof(np->mask));
00831 if (gettag(bp->dhcp, DHCP_TAG_GATEWAY, &pdata, nil)) {
00832 memcpy(&np->gateway, pdata, sizeof(np->gateway));
00833 } else {
00834 np->gateway= 0;
00835 }
00836 if (gettag(bp->dhcp, DHCP_TAG_IPMTU, &pdata, nil)) {
00837 memcpy(&mtu, pdata, sizeof(mtu));
00838 mtu= ntohs(mtu);
00839 } else {
00840 mtu= 0;
00841 }
00842 set_ipconf(ipdev(np->n), np->ip, np->mask, mtu);
00843 if (debug >= 1) {
00844 printf("%s: IP address is %s\n",
00845 ipdev(np->n), cidr_ntoa(np->ip, np->mask));
00846 }
00847 np->flags |= NF_BOUND;
00848 np->renew= np->rebind= np->lease= NEVER;
00849 np->sol_ct= N_SOLICITS;
00850 np->solicit= 0;
00851
00852
00853 i= 0;
00854 }
00855 put_buf(&bp);
00856 }
00857
00858 for (;;) {
00859 now= time(nil);
00860 event= NEVER;
00861
00862
00863 for (i= 0; i < n_nets; i++) {
00864 np= network[i];
00865
00866 if (np->renew <= now) {
00867 u8_t type;
00868 static u8_t taglist[] = {
00869 DHCP_TAG_NETMASK, DHCP_TAG_GATEWAY, DHCP_TAG_DNS,
00870 DHCP_TAG_HOSTNAME
00871 };
00872 u8_t ethclid[1+DHCP_HLEN_ETH];
00873
00874
00875 if (np->rebind <= now) np->server= BCAST_IP;
00876
00877 if (np->lease <= now) {
00878 if (np->flags & NF_BOUND) closedev(np, FT_ALL);
00879
00880 if ((np->flags & (NF_BOUND | NF_POSSESSIVE)) == NF_BOUND) {
00881 set_ipconf(ipdev(np->n), np->ip= 0, np->mask= 0, 0);
00882 if (debug >= 1) {
00883 printf("%s: Interface disabled (lease expired)\n",
00884 ipdev(np->n));
00885 }
00886 }
00887 np->flags &= ~NF_BOUND;
00888 }
00889
00890
00891 if (!(np->flags & NF_BOUND)) {
00892 if (!opendev(np, FT_ETHERNET, 1)) continue;
00893 } else {
00894 if (!opendev(np, FT_BOOTPC, 1)) continue;
00895 }
00896
00897 if (!(np->flags & NF_NEGOTIATING)) {
00898
00899 np->start= now;
00900 np->delta= DELTA_FIRST;
00901 np->flags |= NF_NEGOTIATING;
00902 }
00903
00904
00905 get_buf(&bp);
00906 dhcp_init(bp->dhcp);
00907 bp->dhcp->op= DHCP_BOOTREQUEST;
00908 bp->dhcp->htype= DHCP_HTYPE_ETH;
00909 bp->dhcp->hlen= DHCP_HLEN_ETH;
00910 bp->dhcp->xid= XID(np);
00911 bp->dhcp->secs= htons(now - np->start > 0xFFFF
00912 ? 0xFFFF : now - np->start);
00913 memcpy(bp->dhcp->chaddr, &np->eth, sizeof(np->eth));
00914
00915 if (np->lease <= now) {
00916
00917 type= DHCP_DISCOVER;
00918 } else {
00919
00920 type= DHCP_REQUEST;
00921 if (np->flags & NF_BOUND) {
00922
00923 bp->dhcp->ciaddr= np->ip;
00924 } else {
00925
00926 settag(bp->dhcp, DHCP_TAG_REQIP, &np->ip,
00927 sizeof(np->ip));
00928 settag(bp->dhcp, DHCP_TAG_SERVERID, &np->server,
00929 sizeof(np->server));
00930 }
00931 }
00932 settag(bp->dhcp, DHCP_TAG_TYPE, &type, 1);
00933
00934
00935 ether2clid(ethclid, &np->eth);
00936 settag(bp->dhcp, DHCP_TAG_CLIENTID, ethclid, sizeof(ethclid));
00937
00938
00939 settag(bp->dhcp, DHCP_TAG_CLASSID, "Minix", 5);
00940
00941
00942 settag(bp->dhcp, DHCP_TAG_REQPAR, taglist, sizeof(taglist));
00943
00944
00945 if (np->hostname != nil) {
00946 settag(bp->dhcp, DHCP_TAG_HOSTNAME,
00947 np->hostname, strlen(np->hostname));
00948 }
00949
00950 bp->udpio->uih_src_addr= np->ip;
00951 bp->udpio->uih_dst_addr= np->server;
00952 bp->udpio->uih_src_port= port_client;
00953 bp->udpio->uih_dst_port= port_server;
00954 bp->udpio->uih_ip_opt_len= 0;
00955 bp->udpio->uih_data_len= sizeof(dhcp_t);
00956
00957 if (!(np->flags & NF_BOUND)) {
00958
00959 udp2ether(bp, np);
00960 if (send(np, bp->eth, sizeof(eth_hdr_t) + sizeof(ip_hdr_t)
00961 + sizeof(udp_hdr_t) + sizeof(dhcp_t))) {
00962 if (debug >= 1) {
00963 printf("%s: Broadcast DHCP %s\n",
00964 np->fdp->device, dhcptypename(type));
00965 if (debug >= 2) printdhcp(bp->dhcp);
00966 }
00967 }
00968 } else {
00969
00970 if (send(np, bp->udpio, sizeof(udp_io_hdr_t)
00971 + sizeof(dhcp_t))) {
00972 if (debug >= 1) {
00973 printf("%s: Sent DHCP %s to %s\n",
00974 np->fdp->device,
00975 dhcptypename(type),
00976 inet_ntoa(np->server));
00977 if (debug >= 2) printdhcp(bp->dhcp);
00978 }
00979 }
00980 }
00981 put_buf(&bp);
00982
00983
00984 if (np->flags & NF_BOUND) {
00985
00986 time_t e, d;
00987
00988 e= now < np->rebind ? np->rebind : np->lease;
00989 d= (e - now) / 2;
00990 if (d < DELTA_SLOW) d= DELTA_SLOW;
00991 np->renew= now + d;
00992 if (np->renew > e) np->renew= e;
00993 } else {
00994
00995 np->renew= now + np->delta;
00996 if ((np->delta *= 2) > DELTA_FAST) np->delta= DELTA_FAST;
00997 }
00998 }
00999 if (np->renew < event) event= np->renew;
01000 }
01001
01002
01003 for (i= 0; i < n_nets; i++) {
01004 np= network[i];
01005 if (!(np->flags & NF_NEGOTIATING)) continue;
01006
01007 if (!(np->flags & NF_BOUND)) {
01008 if (!opendev(np, FT_ETHERNET, 0)) continue;
01009 get_buf(&np->fdp->bp);
01010 r= asyn_read(&asyn, np->fdp->fd, np->fdp->bp->eth,
01011 BUF_ETH_SIZE);
01012 } else {
01013 if (!opendev(np, FT_BOOTPC, 0)) continue;
01014 get_buf(&np->fdp->bp);
01015 r= asyn_read(&asyn, np->fdp->fd, np->fdp->bp->udpio,
01016 BUF_UDP_SIZE);
01017 }
01018 if (r != -1) break;
01019 if (errno != ASYN_INPROGRESS && errno != EPACKSIZE) {
01020 report(np->fdp->device);
01021 sleep(10);
01022 }
01023 }
01024
01025
01026 if (i < n_nets) {
01027 give_buf(&bp, &np->fdp->bp);
01028 if (((!(np->flags & NF_BOUND)
01029 && r >= (sizeof(eth_hdr_t) + sizeof(ip_hdr_t)
01030 + sizeof(udp_hdr_t) + offsetof(dhcp_t, options))
01031 && ether2udp(bp)
01032 && bp->udpio->uih_dst_port == port_client)
01033 ||
01034 ((np->flags & NF_BOUND)
01035 && r >= sizeof(udp_io_hdr_t) + offsetof(dhcp_t, options)))
01036 && bp->dhcp->op == DHCP_BOOTREPLY
01037 && bp->dhcp->htype == DHCP_HTYPE_ETH
01038 && bp->dhcp->hlen == DHCP_HLEN_ETH
01039 && bp->dhcp->xid == XID(np)
01040 && memcmp(bp->dhcp->chaddr, &np->eth, sizeof(np->eth)) == 0
01041 ) {
01042
01043 u8_t *pdata;
01044 size_t len;
01045 int type;
01046 ipaddr_t mask, gateway, relay, server;
01047 u16_t mtu;
01048 u32_t lease, renew, rebind, t;
01049
01050 relay= bp->udpio->uih_src_addr;
01051 if (gettag(bp->dhcp, DHCP_TAG_SERVERID, &pdata, nil)) {
01052 memcpy(&server, pdata, sizeof(server));
01053 } else {
01054 server= relay;
01055 }
01056
01057 if (gettag(bp->dhcp, DHCP_TAG_TYPE, &pdata, nil)) {
01058 type= pdata[0];
01059 } else {
01060 type= DHCP_ACK;
01061 }
01062
01063 if (debug >= 1) {
01064 printf("%s: Got a DHCP %s from %s",
01065 np->fdp->device, dhcptypename(type), inet_ntoa(server));
01066 printf(relay != server ? " through %s\n" : "\n",
01067 inet_ntoa(relay));
01068 if (debug >= 2) printdhcp(bp->dhcp);
01069 }
01070
01071 if (gettag(bp->dhcp, DHCP_TAG_NETMASK, &pdata, nil)) {
01072 memcpy(&mask, pdata, sizeof(mask));
01073 } else {
01074 mask= defaultmask(bp->dhcp->ciaddr);
01075 }
01076
01077 if (gettag(bp->dhcp, DHCP_TAG_IPMTU, &pdata, nil)) {
01078 memcpy(&mtu, pdata, sizeof(mtu));
01079 mtu= ntohs(mtu);
01080 } else {
01081 mtu= 0;
01082 }
01083
01084 if (gettag(bp->dhcp, DHCP_TAG_GATEWAY, &pdata, nil)) {
01085 memcpy(&gateway, pdata, sizeof(gateway));
01086 } else {
01087 gateway= 0;
01088 }
01089
01090 lease= NEVER;
01091 if (gettag(bp->dhcp, DHCP_TAG_LEASE, &pdata, nil)) {
01092 memcpy(&lease, pdata, sizeof(lease));
01093 lease= ntohl(lease);
01094 }
01095
01096 rebind= lease - lease / 8;
01097 if (gettag(bp->dhcp, DHCP_TAG_REBINDING, &pdata, nil)) {
01098 memcpy(&t, pdata, sizeof(t));
01099 t= ntohl(t);
01100 if (t < rebind) rebind= t;
01101 }
01102
01103 renew= lease / 2;
01104 if (gettag(bp->dhcp, DHCP_TAG_RENEWAL, &pdata, nil)) {
01105 memcpy(&t, pdata, sizeof(t));
01106 t= ntohl(t);
01107 if (t < renew) renew= t;
01108 }
01109
01110 if (type == DHCP_OFFER && np->rebind <= np->renew) {
01111
01112
01113
01114 np->ip= bp->dhcp->yiaddr;
01115 np->mask= mask;
01116 np->server= server;
01117 np->gateway= gateway;
01118 np->delta= DELTA_FIRST;
01119 np->renew= now;
01120 np->rebind= np->lease= now + DELTA_FAST;
01121
01122
01123
01124
01125 make_arp(bp, np);
01126 if (send(np, bp->eth, sizeof(arp46_t))) {
01127 if (debug >= 2) {
01128 printf("Sent ARP for %s\n", inet_ntoa(np->ip));
01129 }
01130 }
01131 np->flags &= ~NF_CONFLICT;
01132 }
01133
01134 if (type == DHCP_ACK && !(np->flags & NF_CONFLICT)) {
01135
01136 cachedhcp(np->n, bp->dhcp);
01137 np->ip= bp->dhcp->yiaddr;
01138 np->mask= mask;
01139 np->server= server;
01140 set_ipconf(ipdev(np->n), np->ip, np->mask, mtu);
01141 if (debug >= 1) {
01142 printf("%s: Address set to %s\n",
01143 ipdev(np->n), cidr_ntoa(np->ip, np->mask));
01144 }
01145 if (lease >= NEVER - now) {
01146
01147 np->renew= np->rebind= np->lease= NEVER;
01148 } else {
01149 np->lease= now + lease;
01150 np->renew= now + renew;
01151 np->rebind= now + rebind;
01152 }
01153 if (test >= 3) {
01154 np->renew= now + 60;
01155 np->rebind= test >= 4 ? np->renew : np->renew + 60;
01156 np->lease= test >= 5 ? np->rebind : np->rebind + 60;
01157 }
01158 if (!(np->flags & NF_IRDP)) {
01159 np->sol_ct= (np->flags & NF_BOUND) ? 1 : N_SOLICITS;
01160 np->solicit= 0;
01161 }
01162 np->flags &= ~NF_NEGOTIATING;
01163 np->flags |= NF_BOUND;
01164 closedev(np, FT_ETHERNET);
01165 closedev(np, FT_BOOTPC);
01166 }
01167
01168 if (type == DHCP_ACK && (np->flags & NF_CONFLICT)) {
01169
01170 u8_t ethclid[1+DHCP_HLEN_ETH];
01171 static char USED[]= "Address in use by 00:00:00:00:00:00";
01172
01173 type= DHCP_DECLINE;
01174 dhcp_init(bp->dhcp);
01175 bp->dhcp->op= DHCP_BOOTREQUEST;
01176 bp->dhcp->htype= DHCP_HTYPE_ETH;
01177 bp->dhcp->hlen= DHCP_HLEN_ETH;
01178 bp->dhcp->xid= XID(np);
01179 bp->dhcp->secs= 0;
01180 memcpy(bp->dhcp->chaddr, &np->eth, sizeof(np->eth));
01181 settag(bp->dhcp, DHCP_TAG_REQIP, &np->ip, sizeof(np->ip));
01182 settag(bp->dhcp, DHCP_TAG_TYPE, &type, 1);
01183 ether2clid(ethclid, &np->eth);
01184 settag(bp->dhcp, DHCP_TAG_CLIENTID,ethclid,sizeof(ethclid));
01185 strcpy(USED+18, ether_ntoa(&np->conflict));
01186 settag(bp->dhcp, DHCP_TAG_MESSAGE, USED, strlen(USED));
01187
01188 bp->udpio->uih_src_port= port_client;
01189 bp->udpio->uih_dst_port= port_server;
01190 bp->udpio->uih_ip_opt_len= 0;
01191 bp->udpio->uih_data_len= sizeof(dhcp_t);
01192 udp2ether(bp, np);
01193
01194 if (send(np, bp->eth, sizeof(eth_hdr_t) + sizeof(ip_hdr_t)
01195 + sizeof(udp_hdr_t) + sizeof(dhcp_t))) {
01196 if (debug >= 1) {
01197 printf("%s: Broadcast DHCP %s\n",
01198 np->fdp->device, dhcptypename(type));
01199 if (debug >= 2) printdhcp(bp->dhcp);
01200 }
01201 }
01202
01203 np->renew= np->rebind= np->lease= now + DELTA_FAST;
01204 np->delta= DELTA_FIRST;
01205 }
01206
01207 if (type == DHCP_NAK) {
01208
01209 np->renew= np->rebind= np->lease= now + DELTA_FAST;
01210 np->delta= DELTA_FIRST;
01211
01212 fprintf(stderr, "%s: Got a NAK from %s",
01213 program, inet_ntoa(server));
01214 if (relay != server) {
01215 fprintf(stderr, " through %s", inet_ntoa(relay));
01216 }
01217 if (gettag(bp->dhcp, DHCP_TAG_MESSAGE, &pdata, &len)) {
01218 fprintf(stderr, " saying: \"%.*s\"", (int)len, pdata);
01219 }
01220 fputc('\n', stderr);
01221 }
01222 } else
01223 if (!(np->flags & NF_BOUND)
01224 && np->rebind > now
01225 && r >= sizeof(arp46_t)
01226 && is_arp_me(bp, np)
01227 ) {
01228
01229 np->flags |= NF_CONFLICT;
01230
01231 fprintf(stderr, "%s: %s: %s offered by ",
01232 program,
01233 np->fdp->device,
01234 inet_ntoa(np->ip));
01235 fprintf(stderr, "%s is already in use by %s\n",
01236 inet_ntoa(np->server),
01237 ether_ntoa(&np->conflict));
01238 }
01239 put_buf(&bp);
01240 if (np->renew < event) event= np->renew;
01241 }
01242
01243
01244 for (i= 0; i < n_nets; i++) {
01245 np= network[i];
01246 if (!(np->flags & NF_BOUND)) continue;
01247
01248 if (np->solicit <= now) {
01249 if (!opendev(np, FT_ICMP, 1)) continue;
01250 np->solicit= NEVER;
01251
01252 get_buf(&bp);
01253 if (np->gateway != 0) {
01254
01255
01256
01257 icmp_advert(bp, np);
01258 if (send(np, bp->ip, sizeof(ip_hdr_t) + 16)) {
01259 if (debug >= 2) {
01260 printf("%s: Sent advert for %s to self\n",
01261 np->fdp->device, inet_ntoa(np->gateway));
01262 }
01263 }
01264 np->solicit= now + DELTA_ADV/2;
01265 }
01266
01267 if (np->sol_ct >= 0 && --np->sol_ct >= 0) {
01268
01269 icmp_solicit(bp);
01270 if (send(np, bp->ip, sizeof(*bp->ip) + 8)) {
01271 if (debug >= 2) {
01272 printf("%s: Broadcast router solicitation\n",
01273 np->fdp->device);
01274 }
01275 }
01276 np->solicit= now + DELTA_SOL;
01277 } else {
01278
01279 closedev(np, FT_ICMP);
01280 }
01281
01282 put_buf(&bp);
01283 }
01284 if (np->solicit < event) event= np->solicit;
01285 }
01286
01287
01288 for (i= 0; i < n_nets; i++) {
01289 np= network[i];
01290 if (!(np->flags & NF_BOUND)) continue;
01291 if (np->sol_ct < 0) continue;
01292
01293 if (!opendev(np, FT_ICMP, 0)) continue;
01294 get_buf(&np->fdp->bp);
01295 r= asyn_read(&asyn, np->fdp->fd, np->fdp->bp->ip, BUF_IP_SIZE);
01296 if (r != -1) break;
01297 if (errno != ASYN_INPROGRESS && errno != EPACKSIZE) {
01298 report(np->fdp->device);
01299 sleep(10);
01300 }
01301 }
01302
01303
01304 if (i < n_nets && r >= sizeof(ip_hdr_t) + 8) {
01305 ipaddr_t router;
01306
01307 give_buf(&bp, &np->fdp->bp);
01308 if ((router= icmp_is_advert(bp)) != 0) {
01309 if (debug >= 2) {
01310 printf("%s: Router advert received from %s\n",
01311 np->fdp->device, inet_ntoa(router));
01312 }
01313 np->solicit= NEVER;
01314 np->sol_ct= -1;
01315 np->flags |= NF_IRDP;
01316 closedev(np, FT_ICMP);
01317 }
01318 put_buf(&bp);
01319 }
01320
01321
01322 for (i= 0; i < n_nets; i++) {
01323 np= network[i];
01324 if ((np->flags & NF_RELAYING) && (np->flags & NF_BOUND)) {
01325 if (((np->ip ^ np->server) & np->mask) == 0) {
01326
01327 np->flags &= ~NF_RELAYING;
01328 }
01329 }
01330 if (!(np->flags & (NF_SERVING|NF_RELAYING))) continue;
01331 if (!(np->flags & NF_BOUND)) { serving= 0; break; }
01332 serving= 1;
01333 }
01334
01335
01336 for (i= 0; i < n_nets; i++) {
01337 np= network[i];
01338 if (!(np->flags & NF_BOUND)) continue;
01339 if (!(np->flags & (NF_SERVING|NF_RELAYING)) || !serving) continue;
01340
01341 if (!opendev(np, FT_BOOTPS, 0)) continue;
01342 get_buf(&np->fdp->bp);
01343 r= asyn_read(&asyn, np->fdp->fd, np->fdp->bp->udpio, BUF_UDP_SIZE);
01344
01345 if (r != -1) break;
01346 if (errno != ASYN_INPROGRESS && errno != EPACKSIZE) {
01347 report(np->fdp->device);
01348 sleep(10);
01349 }
01350 }
01351
01352
01353 if (i < n_nets
01354 && r >= sizeof(udp_io_hdr_t) + offsetof(dhcp_t, options)
01355 ) {
01356 give_buf(&bp, &np->fdp->bp);
01357
01358 if (debug >= 1) {
01359 printf("%s: Got DHCP packet from %s to ",
01360 np->fdp->device, inet_ntoa(bp->udpio->uih_src_addr));
01361 printf("%s\n", inet_ntoa(bp->udpio->uih_dst_addr));
01362 if (debug >= 2) printdhcp(bp->dhcp);
01363 }
01364
01365
01366 if ((r= servdhcp(np, bp, r)) > 0) {
01367
01368 if (send(np, bp->udpio, r)) {
01369 if (debug >= 1) {
01370 printf("%s: Sent DHCP packet to %s\n",
01371 np->fdp->device,
01372 inet_ntoa(bp->udpio->uih_dst_addr));
01373 if (debug >= 2) printdhcp(bp->dhcp);
01374 }
01375 }
01376 }
01377 put_buf(&bp);
01378 }
01379
01380 if (debug >= 1) {
01381 static char *lastbrk;
01382 extern char _end;
01383
01384 if (sbrk(0) != lastbrk) {
01385 lastbrk= sbrk(0);
01386 printf("Memory use = %lu\n",
01387 (unsigned long) (lastbrk - &_end));
01388 }
01389 fflush(stdout);
01390 }
01391
01392
01393 if (!serving && event == NEVER) break;
01394
01395
01396 eventtv.tv_sec= event;
01397 if (asyn_wait(&asyn, 0, event == NEVER ? nil : &eventtv) < 0) {
01398 if (errno != EINTR) {
01399 report("asyn_wait()");
01400 sleep(10);
01401 }
01402 }
01403 }
01404 if (debug >= 1) printf("Nothing more to do! Bailing out...\n");
01405 return 0;
01406 }