Sweep-fix comparing pointers with 0 (and assigning 0 to pointers).
[dragonfly.git] / usr.sbin / timed / timed / slave.c
1 /*-
2  * Copyright (c) 1985, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * @(#)slave.c  8.1 (Berkeley) 6/6/93
34  * $FreeBSD: src/usr.sbin/timed/timed/slave.c,v 1.7 1999/08/28 01:20:18 peter Exp $
35  */
36
37 #include "globals.h"
38 #include <setjmp.h>
39 #include "pathnames.h"
40
41 extern jmp_buf jmpenv;
42 extern int Mflag;
43 extern int justquit;
44
45 extern u_short sequence;
46
47 static char master_name[MAXHOSTNAMELEN];
48 static struct netinfo *old_slavenet;
49 static int old_status;
50
51 static void schgdate(struct tsp *, char *);
52 static void setmaster(struct tsp *);
53 static void answerdelay(void);
54
55 int
56 slave(void)
57 {
58         int tries;
59         long electiontime, refusetime, looktime, looptime, adjusttime;
60         u_short seq;
61         long fastelection;
62 #define FASTTOUT 3
63         struct in_addr cadr;
64         struct timeval otime;
65         struct sockaddr_in taddr;
66         char tname[MAXHOSTNAMELEN];
67         struct tsp *msg, to;
68         struct timeval ntime, wait;
69         time_t tsp_time_sec;
70         struct tsp *answer;
71         char olddate[32];
72         char newdate[32];
73         struct netinfo *ntp;
74         struct hosttbl *htp;
75
76
77         old_slavenet = NULL;
78         seq = 0;
79         refusetime = 0;
80         adjusttime = 0;
81
82         gettimeofday(&ntime, 0);
83         electiontime = ntime.tv_sec + delay2;
84         fastelection = ntime.tv_sec + FASTTOUT;
85         if (justquit)
86                 looktime = electiontime;
87         else
88                 looktime = fastelection;
89         looptime = fastelection;
90
91         if (slavenet)
92                 xmit(TSP_SLAVEUP, 0, &slavenet->dest_addr);
93         if (status & MASTER) {
94                 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
95                         if (ntp->status == MASTER)
96                                 masterup(ntp);
97                 }
98         }
99
100 loop:
101         get_goodgroup(0);
102         gettimeofday(&ntime, NULL);
103         if (ntime.tv_sec > electiontime) {
104                 if (trace)
105                         fprintf(fd, "election timer expired\n");
106                 longjmp(jmpenv, 1);
107         }
108
109         if (ntime.tv_sec >= looktime) {
110                 if (trace)
111                         fprintf(fd, "Looking for nets to master\n");
112
113                 if (Mflag && nignorednets > 0) {
114                         for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
115                                 if (ntp->status == IGNORE
116                                     || ntp->status == NOMASTER) {
117                                         lookformaster(ntp);
118                                         if (ntp->status == MASTER) {
119                                                 masterup(ntp);
120                                         } else if (ntp->status == MASTER) {
121                                                 ntp->status = NOMASTER;
122                                         }
123                                 }
124                                 if (ntp->status == MASTER
125                                     && --ntp->quit_count < 0)
126                                         ntp->quit_count = 0;
127                         }
128                         makeslave(slavenet);    /* prune extras */
129                         setstatus();
130                 }
131                 gettimeofday(&ntime, 0);
132                 looktime = ntime.tv_sec + delay2;
133         }
134         if (ntime.tv_sec >= looptime) {
135                 if (trace)
136                         fprintf(fd, "Looking for loops\n");
137                 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
138                     if (ntp->status == MASTER) {
139                         to.tsp_type = TSP_LOOP;
140                         to.tsp_vers = TSPVERSION;
141                         to.tsp_seq = sequence++;
142                         to.tsp_hopcnt = MAX_HOPCNT;
143                         strlcpy(to.tsp_name, hostname, sizeof(to.tsp_name));
144                         bytenetorder(&to);
145                         if (sendto(sock, (char *)&to, sizeof(struct tsp), 0,
146                                    (struct sockaddr*)&ntp->dest_addr,
147                                    sizeof(ntp->dest_addr)) < 0) {
148                                 trace_sendto_err(ntp->dest_addr.sin_addr);
149                         }
150                     }
151                 }
152                 gettimeofday(&ntime, 0);
153                 looptime = ntime.tv_sec + delay2;
154         }
155
156         wait.tv_sec = min(electiontime,min(looktime,looptime)) - ntime.tv_sec;
157         if (wait.tv_sec < 0)
158                 wait.tv_sec = 0;
159         wait.tv_sec += FASTTOUT;
160         wait.tv_usec = 0;
161         msg = readmsg(TSP_ANY, ANYADDR, &wait, 0);
162
163         if (msg != NULL) {
164                 /*
165                  * filter stuff not for us
166                  */
167                 switch (msg->tsp_type) {
168                 case TSP_SETDATE:
169                 case TSP_TRACEOFF:
170                 case TSP_TRACEON:
171                         /*
172                          * XXX check to see they are from ourself
173                          */
174                         break;
175
176                 case TSP_TEST:
177                 case TSP_MSITE:
178                         break;
179
180                 case TSP_MASTERUP:
181                         if (!fromnet) {
182                                 if (trace) {
183                                         fprintf(fd, "slave ignored: ");
184                                         print(msg, &from);
185                                 }
186                                 goto loop;
187                         }
188                         break;
189
190                 default:
191                         if (!fromnet
192                             || fromnet->status == IGNORE
193                             || fromnet->status == NOMASTER) {
194                                 if (trace) {
195                                         fprintf(fd, "slave ignored: ");
196                                         print(msg, &from);
197                                 }
198                                 goto loop;
199                         }
200                         break;
201                 }
202
203
204                 /*
205                  * now process the message
206                  */
207                 switch (msg->tsp_type) {
208
209                 case TSP_ADJTIME:
210                         if (fromnet != slavenet)
211                                 break;
212                         if (!good_host_name(msg->tsp_name)) {
213                                 syslog(LOG_NOTICE,
214                                    "attempted time adjustment by %s",
215                                        msg->tsp_name);
216                                 suppress(&from, msg->tsp_name, fromnet);
217                                 break;
218                         }
219                         /*
220                          * Speed up loop detection in case we have a loop.
221                          * Otherwise the clocks can race until the loop
222                          * is found.
223                          */
224                         gettimeofday(&otime, 0);
225                         if (adjusttime < otime.tv_sec)
226                                 looptime -= (looptime-otime.tv_sec)/2 + 1;
227
228                         setmaster(msg);
229                         if (seq != msg->tsp_seq) {
230                                 seq = msg->tsp_seq;
231                                 synch(tvtomsround(msg->tsp_time));
232                         }
233                         gettimeofday(&ntime, 0);
234                         electiontime = ntime.tv_sec + delay2;
235                         fastelection = ntime.tv_sec + FASTTOUT;
236                         adjusttime = ntime.tv_sec + SAMPLEINTVL*2;
237                         break;
238
239                 case TSP_SETTIME:
240                         if (fromnet != slavenet)
241                                 break;
242                         if (seq == msg->tsp_seq)
243                                 break;
244                         seq = msg->tsp_seq;
245
246                         /* adjust time for residence on the queue */
247                         gettimeofday(&otime, 0);
248                         adj_msg_time(msg,&otime);
249
250                         /*
251                          * the following line is necessary due to syslog
252                          * calling ctime() which clobbers the static buffer
253                          */
254                         strlcpy(olddate, date(), sizeof(olddate));
255                         tsp_time_sec = msg->tsp_time.tv_sec;
256                         strlcpy(newdate, ctime(&tsp_time_sec), sizeof(newdate));
257
258                         if (!good_host_name(msg->tsp_name)) {
259                                 syslog(LOG_NOTICE,
260                             "attempted time setting by untrusted %s to %s",
261                                        msg->tsp_name, newdate);
262                                 suppress(&from, msg->tsp_name, fromnet);
263                                 break;
264                         }
265
266                         setmaster(msg);
267                         timevalsub(&ntime, &msg->tsp_time, &otime);
268                         if (ntime.tv_sec < MAXADJ && ntime.tv_sec > -MAXADJ) {
269                                 /*
270                                  * do not change the clock if we can adjust it
271                                  */
272                                 synch(tvtomsround(ntime));
273                         } else {
274                                 logwtmp("|", "date", "");
275                                 settimeofday(&msg->tsp_time, 0);
276                                 logwtmp("{", "date", "");
277                                 syslog(LOG_NOTICE,
278                                        "date changed by %s from %s",
279                                         msg->tsp_name, olddate);
280                                 if (status & MASTER)
281                                         spreadtime();
282                         }
283                         gettimeofday(&ntime, 0);
284                         electiontime = ntime.tv_sec + delay2;
285                         fastelection = ntime.tv_sec + FASTTOUT;
286
287 /* This patches a bad protocol bug.  Imagine a system with several networks,
288  * where there are a pair of redundant gateways between a pair of networks,
289  * each running timed.  Assume that we start with a third machine mastering
290  * one of the networks, and one of the gateways mastering the other.
291  * Imagine that the third machine goes away and the non-master gateway
292  * decides to replace it.  If things are timed just 'right,' we will have
293  * each gateway mastering one network for a little while.  If a SETTIME
294  * message gets into the network at that time, perhaps from the newly
295  * masterful gateway as it was taking control, the SETTIME will loop
296  * forever.  Each time a gateway receives it on its slave side, it will
297  * call spreadtime to forward it on its mastered network.  We are now in
298  * a permanent loop, since the SETTIME msgs will keep any clock
299  * in the network from advancing.  Normally, the 'LOOP' stuff will detect
300  * and correct the situation.  However, with the clocks stopped, the
301  * 'looptime' timer cannot expire.  While they are in this state, the
302  * masters will try to saturate the network with SETTIME packets.
303  */
304                         looptime = ntime.tv_sec + (looptime-otime.tv_sec)/2-1;
305                         break;
306
307                 case TSP_MASTERUP:
308                         if (slavenet && fromnet != slavenet)
309                                 break;
310                         if (!good_host_name(msg->tsp_name)) {
311                                 suppress(&from, msg->tsp_name, fromnet);
312                                 if (electiontime > fastelection)
313                                         electiontime = fastelection;
314                                 break;
315                         }
316                         makeslave(fromnet);
317                         setmaster(msg);
318                         setstatus();
319                         answerdelay();
320                         xmit(TSP_SLAVEUP, 0, &from);
321                         gettimeofday(&ntime, 0);
322                         electiontime = ntime.tv_sec + delay2;
323                         fastelection = ntime.tv_sec + FASTTOUT;
324                         refusetime = 0;
325                         break;
326
327                 case TSP_MASTERREQ:
328                         if (fromnet->status != SLAVE)
329                                 break;
330                         gettimeofday(&ntime, 0);
331                         electiontime = ntime.tv_sec + delay2;
332                         break;
333
334                 case TSP_SETDATE:
335                         tsp_time_sec = msg->tsp_time.tv_sec;
336                         strlcpy(newdate, ctime(&tsp_time_sec), sizeof(newdate));
337                         schgdate(msg, newdate);
338                         break;
339
340                 case TSP_SETDATEREQ:
341                         if (fromnet->status != MASTER)
342                                 break;
343                         tsp_time_sec = msg->tsp_time.tv_sec;
344                         strlcpy(newdate, ctime(&tsp_time_sec), sizeof(newdate));
345                         htp = findhost(msg->tsp_name);
346                         if (NULL == htp) {
347                                 syslog(LOG_WARNING,
348                                        "DATEREQ from uncontrolled machine");
349                                 break;
350                         }
351                         if (!htp->good) {
352                                 syslog(LOG_WARNING,
353                                 "attempted date change by untrusted %s to %s",
354                                        htp->name, newdate);
355                                 spreadtime();
356                                 break;
357                         }
358                         schgdate(msg, newdate);
359                         break;
360
361                 case TSP_TRACEON:
362                         traceon();
363                         break;
364
365                 case TSP_TRACEOFF:
366                         traceoff("Tracing ended at %s\n");
367                         break;
368
369                 case TSP_SLAVEUP:
370                         newslave(msg);
371                         break;
372
373                 case TSP_ELECTION:
374                         if (fromnet->status == SLAVE) {
375                                 gettimeofday(&ntime, 0);
376                                 electiontime = ntime.tv_sec + delay2;
377                                 fastelection = ntime.tv_sec + FASTTOUT;
378                                 seq = 0;
379                                 if (!good_host_name(msg->tsp_name)) {
380                                         syslog(LOG_NOTICE,
381                                                "suppress election of %s",
382                                                msg->tsp_name);
383                                         to.tsp_type = TSP_QUIT;
384                                         electiontime = fastelection;
385                                 } else if (cadr.s_addr != from.sin_addr.s_addr
386                                            && ntime.tv_sec < refusetime) {
387 /* if the candidate has to repeat itself, the old code would refuse it
388  * the second time.  That would prevent elections.
389  */
390                                         to.tsp_type = TSP_REFUSE;
391                                 } else {
392                                         cadr.s_addr = from.sin_addr.s_addr;
393                                         to.tsp_type = TSP_ACCEPT;
394                                         refusetime = ntime.tv_sec + 30;
395                                 }
396                                 taddr = from;
397                                 strlcpy(tname, msg->tsp_name, sizeof(tname));
398                                 strlcpy(to.tsp_name, hostname, 
399                                         sizeof(to.tsp_name));
400                                 answerdelay();
401                                 if (!acksend(&to, &taddr, tname,
402                                              TSP_ACK, 0, 0))
403                                         syslog(LOG_WARNING,
404                                              "no answer from candidate %s\n",
405                                                tname);
406
407                         } else {        /* fromnet->status == MASTER */
408                                 htp = addmach(msg->tsp_name, &from,fromnet);
409                                 to.tsp_type = TSP_QUIT;
410                                 strlcpy(to.tsp_name, hostname, 
411                                         sizeof(to.tsp_name));
412                                 if (!acksend(&to, &htp->addr, htp->name,
413                                              TSP_ACK, 0, htp->noanswer)) {
414                                         syslog(LOG_ERR,
415                                           "no reply from %s to ELECTION-QUIT",
416                                                htp->name);
417                                         remmach(htp);
418                                 }
419                         }
420                         break;
421
422                 case TSP_CONFLICT:
423                         if (fromnet->status != MASTER)
424                                 break;
425                         /*
426                          * After a network partition, there can be
427                          * more than one master: the first slave to
428                          * come up will notify here the situation.
429                          */
430                         strlcpy(to.tsp_name, hostname, sizeof(to.tsp_name));
431
432                         /* The other master often gets into the same state,
433                          * with boring results.
434                          */
435                         ntp = fromnet;  /* (acksend() can leave fromnet=0 */
436                         for (tries = 0; tries < 3; tries++) {
437                                 to.tsp_type = TSP_RESOLVE;
438                                 answer = acksend(&to, &ntp->dest_addr,
439                                                  ANYADDR, TSP_MASTERACK,
440                                                  ntp, 0);
441                                 if (answer == NULL)
442                                         break;
443                                 htp = addmach(answer->tsp_name,&from,ntp);
444                                 to.tsp_type = TSP_QUIT;
445                                 answer = acksend(&to, &htp->addr, htp->name,
446                                                  TSP_ACK, 0, htp->noanswer);
447                                 if (!answer) {
448                                         syslog(LOG_WARNING,
449                                   "conflict error: no reply from %s to QUIT",
450                                                 htp->name);
451                                         remmach(htp);
452                                 }
453                         }
454                         masterup(ntp);
455                         break;
456
457                 case TSP_MSITE:
458                         if (!slavenet)
459                                 break;
460                         taddr = from;
461                         to.tsp_type = TSP_MSITEREQ;
462                         to.tsp_vers = TSPVERSION;
463                         to.tsp_seq = 0;
464                         strlcpy(to.tsp_name, hostname, sizeof(to.tsp_name));
465                         answer = acksend(&to, &slavenet->dest_addr,
466                                          ANYADDR, TSP_ACK,
467                                          slavenet, 0);
468                         if (answer != NULL
469                             && good_host_name(answer->tsp_name)) {
470                                 setmaster(answer);
471                                 to.tsp_type = TSP_ACK;
472                                 strlcpy(to.tsp_name, answer->tsp_name,
473                                         sizeof(to.tsp_name));
474                                 bytenetorder(&to);
475                                 if (sendto(sock, (char *)&to,
476                                            sizeof(struct tsp), 0,
477                                            (struct sockaddr*)&taddr,
478                                            sizeof(taddr)) < 0) {
479                                         trace_sendto_err(taddr.sin_addr);
480                                 }
481                         }
482                         break;
483
484                 case TSP_MSITEREQ:
485                         break;
486
487                 case TSP_ACCEPT:
488                 case TSP_REFUSE:
489                 case TSP_RESOLVE:
490                         break;
491
492                 case TSP_QUIT:
493                         doquit(msg);            /* become a slave */
494                         break;
495
496                 case TSP_TEST:
497                         electiontime = 0;
498                         break;
499
500                 case TSP_LOOP:
501                         /* looking for loops of masters */
502                         if (!(status & MASTER))
503                                 break;
504                         if (fromnet->status == SLAVE) {
505                             if (!strcmp(msg->tsp_name, hostname)) {
506                                 /*
507                                  * Someone forwarded our message back to
508                                  * us.  There must be a loop.  Tell the
509                                  * master of this network to quit.
510                                  *
511                                  * The other master often gets into
512                                  * the same state, with boring results.
513                                  */
514                                 ntp = fromnet;
515                                 for (tries = 0; tries < 3; tries++) {
516                                     to.tsp_type = TSP_RESOLVE;
517                                     answer = acksend(&to, &ntp->dest_addr,
518                                                      ANYADDR, TSP_MASTERACK,
519                                                      ntp,0);
520                                     if (answer == NULL)
521                                         break;
522                                     taddr = from;
523                                     strlcpy(tname, answer->tsp_name,
524                                             sizeof(tname));
525                                     to.tsp_type = TSP_QUIT;
526                                     strlcpy(to.tsp_name, hostname,
527                                             sizeof(to.tsp_name));
528                                     if (!acksend(&to, &taddr, tname,
529                                                  TSP_ACK, 0, 1)) {
530                                         syslog(LOG_ERR,
531                                         "no reply from %s to slave LOOP-QUIT",
532                                                  tname);
533                                     } else {
534                                         electiontime = 0;
535                                     }
536                                 }
537                                 gettimeofday(&ntime, 0);
538                                 looptime = ntime.tv_sec + FASTTOUT;
539                             } else {
540                                 if (msg->tsp_hopcnt-- < 1)
541                                     break;
542                                 bytenetorder(msg);
543                                 for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
544                                     if (ntp->status == MASTER
545                                         && 0 > sendto(sock, (char *)msg,
546                                                       sizeof(struct tsp), 0,
547                                               (struct sockaddr*)&ntp->dest_addr,
548                                                       sizeof(ntp->dest_addr)))
549                                     trace_sendto_err(ntp->dest_addr.sin_addr);
550                                 }
551                             }
552                         } else {        /* fromnet->status == MASTER */
553                             /*
554                              * We should not have received this from a net
555                              * we are master on.  There must be two masters,
556                              * unless the packet was really from us.
557                              */
558                             if (from.sin_addr.s_addr
559                                 == fromnet->my_addr.s_addr) {
560                                 if (trace)
561                                     fprintf(fd,"discarding forwarded LOOP\n");
562                                 break;
563                             }
564
565                             /*
566                              * The other master often gets into the same
567                              * state, with boring results.
568                              */
569                             ntp = fromnet;
570                             for (tries = 0; tries < 3; tries++) {
571                                 to.tsp_type = TSP_RESOLVE;
572                                 answer = acksend(&to, &ntp->dest_addr,
573                                                  ANYADDR, TSP_MASTERACK,
574                                                 ntp,0);
575                                 if (!answer)
576                                         break;
577                                 htp = addmach(answer->tsp_name,
578                                               &from,ntp);
579                                 to.tsp_type = TSP_QUIT;
580                                 strlcpy(to.tsp_name, hostname,
581                                         sizeof(to.tsp_name));
582                                 if (!acksend(&to,&htp->addr,htp->name,
583                                              TSP_ACK, 0, htp->noanswer)) {
584                                         syslog(LOG_ERR,
585                                     "no reply from %s to master LOOP-QUIT",
586                                                htp->name);
587                                         remmach(htp);
588                                 }
589                             }
590                             gettimeofday(&ntime, 0);
591                             looptime = ntime.tv_sec + FASTTOUT;
592                         }
593                         break;
594                 default:
595                         if (trace) {
596                                 fprintf(fd, "garbage message: ");
597                                 print(msg, &from);
598                         }
599                         break;
600                 }
601         }
602         goto loop;
603 }
604
605
606 /*
607  * tell the world who our master is
608  */
609 static void
610 setmaster(struct tsp *msg)
611 {
612
613         if (slavenet
614             && (slavenet != old_slavenet
615                 || strcmp(msg->tsp_name, master_name)
616                 || old_status != status)) {
617                 strlcpy(master_name, msg->tsp_name, sizeof(master_name));
618                 old_slavenet = slavenet;
619                 old_status = status;
620
621                 if (status & MASTER) {
622                         syslog(LOG_NOTICE, "submaster to %s", master_name);
623                         if (trace)
624                                 fprintf(fd, "submaster to %s\n", master_name);
625
626                 } else {
627                         syslog(LOG_NOTICE, "slave to %s", master_name);
628                         if (trace)
629                                 fprintf(fd, "slave to %s\n", master_name);
630                 }
631         }
632 }
633
634
635
636 /*
637  * handle date change request on a slave
638  */
639 static void
640 schgdate(struct tsp *msg, char *newdate)
641 {
642         struct tsp to;
643         u_short seq;
644         struct sockaddr_in taddr;
645         struct timeval otime;
646
647         if (!slavenet)
648                 return;                 /* no where to forward */
649
650         taddr = from;
651         seq = msg->tsp_seq;
652
653         syslog(LOG_INFO,
654                "forwarding date change by %s to %s",
655                msg->tsp_name, newdate);
656
657         /* adjust time for residence on the queue */
658         gettimeofday(&otime, 0);
659         adj_msg_time(msg, &otime);
660
661         to.tsp_type = TSP_SETDATEREQ;
662         to.tsp_time = msg->tsp_time;
663         strlcpy(to.tsp_name, hostname, sizeof(to.tsp_name));
664         if (!acksend(&to, &slavenet->dest_addr,
665                      ANYADDR, TSP_DATEACK,
666                      slavenet, 0))
667                 return;                 /* no answer */
668
669         xmit(TSP_DATEACK, seq, &taddr);
670 }
671
672
673 /*
674  * Used before answering a broadcast message to avoid network
675  * contention and likely collisions.
676  */
677 static void
678 answerdelay(void)
679 {
680
681         struct timeval timeout;
682
683         timeout.tv_sec = 0;
684         timeout.tv_usec = delay1;
685
686         select(0, NULL, NULL, NULL, &timeout);
687 }