newuuid-20070612
[openafs.git] / src / afs / afs_server.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11  * Implements:
12  * afs_MarkServerUpOrDown
13  * afs_ServerDown
14  * afs_CountServers
15  * afs_CheckServers
16  * afs_FindServer
17  * afs_random
18  * afs_randomMod127
19  * afs_SortServers
20  * afsi_SetServerIPRank
21  * afs_GetServer
22  * afs_ActivateServer
23  * 
24  *
25  * Local:
26  * HaveCallBacksFrom
27  * CheckVLServer
28  * afs_SortOneServer
29  * afs_SetServerPrefs
30  * 
31  */
32 #include <afsconfig.h>
33 #include "afs/param.h"
34
35 RCSID
36     ("$Header$");
37
38 #include "afs/stds.h"
39 #include "afs/sysincludes.h"    /* Standard vendor system headers */
40
41 #if !defined(UKERNEL)
42 #if !defined(AFS_LINUX20_ENV)
43 #include <net/if.h>
44 #endif
45 #include <netinet/in.h>
46
47 #ifdef AFS_SGI62_ENV
48 #include "h/hashing.h"
49 #endif
50 #if !defined(AFS_HPUX110_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN60_ENV)
51 #include <netinet/in_var.h>
52 #endif /* AFS_HPUX110_ENV */
53 #ifdef AFS_DARWIN60_ENV
54 #include <net/if_var.h>
55 #endif
56 #endif /* !defined(UKERNEL) */
57
58 #include "afsincludes.h"        /* Afs-based standard headers */
59 #include "afs/afs_stats.h"      /* afs statistics */
60 #include "rx/rx_multi.h"
61
62 #if     defined(AFS_SUN56_ENV)
63 #include <inet/led.h>
64 #include <inet/common.h>
65 #if     defined(AFS_SUN58_ENV)
66 # include <netinet/ip6.h>
67 # define ipif_local_addr ipif_lcl_addr
68 #  ifndef V4_PART_OF_V6
69 #  define V4_PART_OF_V6(v6)       v6.s6_addr32[3]
70 #  endif
71 # endif
72 #include <inet/ip.h>
73 #endif
74
75 /* Exported variables */
76 afs_rwlock_t afs_xserver;       /* allocation lock for servers */
77 struct server *afs_setTimeHost = 0;     /* last host we used for time */
78 struct server *afs_servers[NSERVERS];   /* Hashed by server`s uuid & 1st ip */
79 afs_rwlock_t afs_xsrvAddr;      /* allocation lock for srvAddrs */
80 struct srvAddr *afs_srvAddrs[NSERVERS]; /* Hashed by server's ip */
81
82
83 /* debugging aids - number of alloc'd server and srvAddr structs. */
84 int afs_reuseServers = 0;
85 int afs_reuseSrvAddrs = 0;
86 int afs_totalServers = 0;
87 int afs_totalSrvAddrs = 0;
88
89
90
91 static struct afs_stats_SrvUpDownInfo *
92 GetUpDownStats(struct server *srv)
93 {
94     struct afs_stats_SrvUpDownInfo *upDownP;
95     u_short fsport = AFS_FSPORT;
96
97     if (srv->cell)
98         fsport = srv->cell->fsport;
99
100     if (srv->addr->sa_portal == fsport)
101         upDownP = afs_stats_cmperf.fs_UpDown;
102     else
103         upDownP = afs_stats_cmperf.vl_UpDown;
104
105     if (srv->cell && afs_IsPrimaryCell(srv->cell))
106         return &upDownP[AFS_STATS_UPDOWN_IDX_SAME_CELL];
107     else
108         return &upDownP[AFS_STATS_UPDOWN_IDX_DIFF_CELL];
109 }
110
111
112 /*------------------------------------------------------------------------
113  * afs_MarkServerUpOrDown
114  *
115  * Description:
116  *      Mark the given server up or down, and track its uptime stats.
117  *
118  * Arguments:
119  *      a_serverP : Ptr to server record to fiddle with.
120  *      a_isDown  : Is the server is to be marked down?
121  *
122  * Returns:
123  *      Nothing.
124  *
125  * Environment:
126  *      The CM server structures must be write-locked.
127  *
128  * Side Effects:
129  *      As advertised.
130  *------------------------------------------------------------------------*/
131
132 void
133 afs_MarkServerUpOrDown(struct srvAddr *sa, int a_isDown)
134 {
135     register struct server *a_serverP = sa->server;
136     register struct srvAddr *sap;
137     osi_timeval_t currTime, *currTimeP; /*Current time */
138     afs_int32 downTime;         /*Computed downtime, in seconds */
139     struct afs_stats_SrvUpDownInfo *upDownP;    /*Ptr to up/down info record */
140
141     /*
142      * If the server record is marked the same as the new status we've
143      * been fed, then there isn't much to be done.
144      */
145     if ((a_isDown && (sa->sa_flags & SRVADDR_ISDOWN))
146         || (!a_isDown && !(sa->sa_flags & SRVADDR_ISDOWN)))
147         return;
148
149     if (a_isDown) {
150         sa->sa_flags |= SRVADDR_ISDOWN;
151         for (sap = a_serverP->addr; sap; sap = sap->next_sa) {
152             if (!(sap->sa_flags & SRVADDR_ISDOWN)) {
153                 /* Not all ips are up so don't bother with the
154                  * server's up/down stats */
155                 return;
156             }
157         }
158         /* 
159          * All ips are down we treat the whole server down
160          */
161         a_serverP->flags |= SRVR_ISDOWN;
162         /*
163          * If this was our time server, search for another time server
164          */
165         if (a_serverP == afs_setTimeHost)
166             afs_setTimeHost = 0;
167     } else {
168         sa->sa_flags &= ~SRVADDR_ISDOWN;
169         /* If any ips are up, the server is also marked up */
170         a_serverP->flags &= ~SRVR_ISDOWN;
171         for (sap = a_serverP->addr; sap; sap = sap->next_sa) {
172             if (sap->sa_flags & SRVADDR_ISDOWN) {
173                 /* Not all ips are up so don't bother with the
174                  * server's up/down stats */
175                 return;
176             }
177         }
178     }
179 #ifndef AFS_NOSTATS
180     /*
181      * Compute the current time and which overall stats record is to be
182      * updated; we'll need them one way or another.
183      */
184     currTimeP = &currTime;
185     osi_GetuTime(currTimeP);
186
187     upDownP = GetUpDownStats(a_serverP);
188
189     if (a_isDown) {
190         /*
191          * Server going up -> down; remember the beginning of this
192          * downtime incident.
193          */
194         a_serverP->lastDowntimeStart = currTime.tv_sec;
195
196         (upDownP->numDownRecords)++;
197         (upDownP->numUpRecords)--;
198     } /*Server being marked down */
199     else {
200         /*
201          * Server going down -> up; remember everything about this
202          * newly-completed downtime incident.
203          */
204         downTime = currTime.tv_sec - a_serverP->lastDowntimeStart;
205         (a_serverP->numDowntimeIncidents)++;
206         a_serverP->sumOfDowntimes += downTime;
207
208         (upDownP->numUpRecords)++;
209         (upDownP->numDownRecords)--;
210         (upDownP->numDowntimeIncidents)++;
211         if (a_serverP->numDowntimeIncidents == 1)
212             (upDownP->numRecordsNeverDown)--;
213         upDownP->sumOfDowntimes += downTime;
214         if ((upDownP->shortestDowntime == 0)
215             || (downTime < upDownP->shortestDowntime))
216             upDownP->shortestDowntime = downTime;
217         if ((upDownP->longestDowntime == 0)
218             || (downTime > upDownP->longestDowntime))
219             upDownP->longestDowntime = downTime;
220
221
222         if (downTime <= AFS_STATS_MAX_DOWNTIME_DURATION_BUCKET0)
223             (upDownP->downDurations[0])++;
224         else if (downTime <= AFS_STATS_MAX_DOWNTIME_DURATION_BUCKET1)
225             (upDownP->downDurations[1])++;
226         else if (downTime <= AFS_STATS_MAX_DOWNTIME_DURATION_BUCKET2)
227             (upDownP->downDurations[2])++;
228         else if (downTime <= AFS_STATS_MAX_DOWNTIME_DURATION_BUCKET3)
229             (upDownP->downDurations[3])++;
230         else if (downTime <= AFS_STATS_MAX_DOWNTIME_DURATION_BUCKET4)
231             (upDownP->downDurations[4])++;
232         else if (downTime <= AFS_STATS_MAX_DOWNTIME_DURATION_BUCKET5)
233             (upDownP->downDurations[5])++;
234         else
235             (upDownP->downDurations[6])++;
236
237     }                           /*Server being marked up */
238 #endif
239 }                               /*MarkServerUpOrDown */
240
241
242 void
243 afs_ServerDown(struct srvAddr *sa)
244 {
245     register struct server *aserver = sa->server;
246
247     AFS_STATCNT(ServerDown);
248     if (aserver->flags & SRVR_ISDOWN || sa->sa_flags & SRVADDR_ISDOWN)
249         return;
250     afs_MarkServerUpOrDown(sa, SRVR_ISDOWN);
251     if (sa->sa_portal == aserver->cell->vlport)
252         print_internet_address
253             ("afs: Lost contact with volume location server ", sa, "", 1);
254     else
255         print_internet_address("afs: Lost contact with file server ", sa, "",
256                                1);
257
258 }                               /*ServerDown */
259
260
261 /* return true if we have any callback promises from this server */
262 int
263 afs_HaveCallBacksFrom(struct server *aserver)
264 {
265     register afs_int32 now;
266     register int i;
267     register struct vcache *tvc;
268
269     AFS_STATCNT(HaveCallBacksFrom);
270     now = osi_Time();           /* for checking for expired callbacks */
271     for (i = 0; i < VCSIZE; i++) {      /* for all guys in the hash table */
272         for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
273             /*
274              * Check to see if this entry has an unexpired callback promise
275              * from the required host
276              */
277             if (aserver == tvc->callback && tvc->cbExpires >= now
278                 && ((tvc->states & CRO) == 0))
279                 return 1;
280         }
281     }
282     return 0;
283
284 }                               /*HaveCallBacksFrom */
285
286
287 static void
288 CheckVLServer(register struct srvAddr *sa, struct vrequest *areq)
289 {
290     register struct server *aserver = sa->server;
291     register struct conn *tc;
292     register afs_int32 code;
293
294     AFS_STATCNT(CheckVLServer);
295     /* Ping dead servers to see if they're back */
296     if (!((aserver->flags & SRVR_ISDOWN) || (sa->sa_flags & SRVADDR_ISDOWN))
297         || (aserver->flags & SRVR_ISGONE))
298         return;
299     if (!aserver->cell)
300         return;                 /* can't do much */
301
302     tc = afs_ConnByHost(aserver, aserver->cell->vlport,
303                         aserver->cell->cellNum, areq, 1, SHARED_LOCK);
304     if (!tc)
305         return;
306     rx_SetConnDeadTime(tc->id, 3);
307
308     RX_AFS_GUNLOCK();
309     code = VL_ProbeServer(tc->id);
310     RX_AFS_GLOCK();
311     rx_SetConnDeadTime(tc->id, afs_rx_deadtime);
312     afs_PutConn(tc, SHARED_LOCK);
313     /*
314      * If probe worked, or probe call not yet defined (for compatibility
315      * with old vlsevers), then we treat this server as running again
316      */
317     if (code == 0 || (code <= -450 && code >= -470)) {
318         if (tc->srvr == sa) {
319             afs_MarkServerUpOrDown(sa, 0);
320             print_internet_address("afs: volume location server ", sa,
321                                    " is back up", 2);
322         }
323     }
324
325 }                               /*CheckVLServer */
326
327
328 #ifndef AFS_MINCHANGE           /* So that some can increase it in param.h */
329 #define AFS_MINCHANGE 2         /* min change we'll bother with */
330 #endif
331 #ifndef AFS_MAXCHANGEBACK
332 #define AFS_MAXCHANGEBACK 10    /* max seconds we'll set a clock back at once */
333 #endif
334
335
336 /*------------------------------------------------------------------------
337  * EXPORTED afs_CountServers
338  *
339  * Description:
340  *      Originally meant to count the number of servers and determining
341  *      up/down info, this routine will now simply sum up all of the
342  *      server record ages.  All other up/down information is kept on the
343  *      fly.
344  *
345  * Arguments:
346  *      None.
347  *
348  * Returns:
349  *      Nothing.
350  *
351  * Environment:
352  *      This routine locks afs_xserver for write for the duration.
353  *
354  * Side Effects:
355  *      Set CM perf stats field sumOfRecordAges for all server record
356  *      entries.
357  *------------------------------------------------------------------------*/
358
359 void
360 afs_CountServers(void)
361 {
362     int currIdx;                /*Curr idx into srv table */
363     struct server *currSrvP;    /*Ptr to curr server record */
364     afs_int32 currChainLen;     /*Length of curr hash chain */
365     osi_timeval_t currTime;     /*Current time */
366     osi_timeval_t *currTimeP;   /*Ptr to above */
367     afs_int32 srvRecordAge;     /*Age of server record, in secs */
368     struct afs_stats_SrvUpDownInfo *upDownP;    /*Ptr to current up/down
369                                                  * info being manipulated */
370
371     /*
372      * Write-lock the server table so we don't get any interference.
373      */
374     ObtainReadLock(&afs_xserver);
375
376     /*
377      * Iterate over each hash index in the server table, walking down each
378      * chain and tallying what we haven't computed from the records there on
379      * the fly.  First, though, initialize the tallies that will change.
380      */
381     afs_stats_cmperf.srvMaxChainLength = 0;
382
383     afs_stats_cmperf.fs_UpDown[0].sumOfRecordAges = 0;
384     afs_stats_cmperf.fs_UpDown[0].ageOfYoungestRecord = 0;
385     afs_stats_cmperf.fs_UpDown[0].ageOfOldestRecord = 0;
386     memset((char *)afs_stats_cmperf.fs_UpDown[0].downIncidents, 0,
387            AFS_STATS_NUM_DOWNTIME_INCIDENTS_BUCKETS * sizeof(afs_int32));
388
389     afs_stats_cmperf.fs_UpDown[1].sumOfRecordAges = 0;
390     afs_stats_cmperf.fs_UpDown[1].ageOfYoungestRecord = 0;
391     afs_stats_cmperf.fs_UpDown[1].ageOfOldestRecord = 0;
392     memset((char *)afs_stats_cmperf.fs_UpDown[1].downIncidents, 0,
393            AFS_STATS_NUM_DOWNTIME_INCIDENTS_BUCKETS * sizeof(afs_int32));
394
395     afs_stats_cmperf.vl_UpDown[0].sumOfRecordAges = 0;
396     afs_stats_cmperf.vl_UpDown[0].ageOfYoungestRecord = 0;
397     afs_stats_cmperf.vl_UpDown[0].ageOfOldestRecord = 0;
398     memset((char *)afs_stats_cmperf.vl_UpDown[0].downIncidents, 0,
399            AFS_STATS_NUM_DOWNTIME_INCIDENTS_BUCKETS * sizeof(afs_int32));
400
401     afs_stats_cmperf.vl_UpDown[1].sumOfRecordAges = 0;
402     afs_stats_cmperf.vl_UpDown[1].ageOfYoungestRecord = 0;
403     afs_stats_cmperf.vl_UpDown[1].ageOfOldestRecord = 0;
404     memset((char *)afs_stats_cmperf.vl_UpDown[1].downIncidents, 0,
405            AFS_STATS_NUM_DOWNTIME_INCIDENTS_BUCKETS * sizeof(afs_int32));
406
407     /*
408      * Compute the current time, used to figure out server record ages.
409      */
410     currTimeP = &currTime;
411     osi_GetuTime(currTimeP);
412
413     /*
414      * Sweep the server hash table, tallying all we need to know.
415      */
416     for (currIdx = 0; currIdx < NSERVERS; currIdx++) {
417         currChainLen = 0;
418         for (currSrvP = afs_servers[currIdx]; currSrvP;
419              currSrvP = currSrvP->next) {
420             /*
421              * Bump the current chain length.
422              */
423             currChainLen++;
424
425             /*
426              * Any further tallying for this record will only be done if it has
427              * been activated. 
428              */
429             if ((currSrvP->flags & AFS_SERVER_FLAG_ACTIVATED)
430                 && currSrvP->addr && currSrvP->cell) {
431
432                 /*
433                  * Compute the current server record's age, then remember it
434                  * in the appropriate places.
435                  */
436                 srvRecordAge = currTime.tv_sec - currSrvP->activationTime;
437                 upDownP = GetUpDownStats(currSrvP);
438                 upDownP->sumOfRecordAges += srvRecordAge;
439                 if ((upDownP->ageOfYoungestRecord == 0)
440                     || (srvRecordAge < upDownP->ageOfYoungestRecord))
441                     upDownP->ageOfYoungestRecord = srvRecordAge;
442                 if ((upDownP->ageOfOldestRecord == 0)
443                     || (srvRecordAge > upDownP->ageOfOldestRecord))
444                     upDownP->ageOfOldestRecord = srvRecordAge;
445
446                 if (currSrvP->numDowntimeIncidents <=
447                     AFS_STATS_MAX_DOWNTIME_INCIDENTS_BUCKET0)
448                     (upDownP->downIncidents[0])++;
449                 else if (currSrvP->numDowntimeIncidents <=
450                          AFS_STATS_MAX_DOWNTIME_INCIDENTS_BUCKET1)
451                     (upDownP->downIncidents[1])++;
452                 else if (currSrvP->numDowntimeIncidents <=
453                          AFS_STATS_MAX_DOWNTIME_INCIDENTS_BUCKET2)
454                     (upDownP->downIncidents[2])++;
455                 else if (currSrvP->numDowntimeIncidents <=
456                          AFS_STATS_MAX_DOWNTIME_INCIDENTS_BUCKET3)
457                     (upDownP->downIncidents[3])++;
458                 else if (currSrvP->numDowntimeIncidents <=
459                          AFS_STATS_MAX_DOWNTIME_INCIDENTS_BUCKET4)
460                     (upDownP->downIncidents[4])++;
461                 else
462                     (upDownP->downIncidents[5])++;
463
464
465             }                   /*Current server has been active */
466         }                       /*Walk this chain */
467
468         /*
469          * Before advancing to the next chain, remember facts about this one.
470          */
471         if (currChainLen > afs_stats_cmperf.srvMaxChainLength) {
472             /*
473              * We beat out the former champion (which was initially set to 0
474              * here).  Mark down the new winner, and also remember if it's an
475              * all-time winner.
476              */
477             afs_stats_cmperf.srvMaxChainLength = currChainLen;
478             if (currChainLen > afs_stats_cmperf.srvMaxChainLengthHWM)
479                 afs_stats_cmperf.srvMaxChainLengthHWM = currChainLen;
480         }                       /*Update chain length maximum */
481     }                           /*For each hash chain */
482
483     /*
484      * We're done.  Unlock the server table before returning to our caller.
485      */
486     ReleaseReadLock(&afs_xserver);
487
488 }                               /*afs_CountServers */
489
490
491 void
492 ForceAllNewConnections()
493 {
494     int srvAddrCount;
495     struct srvAddr **addrs;
496     struct srvAddr *sa;
497     afs_int32 i, j;
498
499     ObtainReadLock(&afs_xserver);       /* Necessary? */
500     ObtainReadLock(&afs_xsrvAddr);
501
502     srvAddrCount = 0;
503     for (i = 0; i < NSERVERS; i++) {
504         for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
505             srvAddrCount++;
506         }
507     }
508
509     addrs = afs_osi_Alloc(srvAddrCount * sizeof(*addrs));
510     j = 0;
511     for (i = 0; i < NSERVERS; i++) {
512         for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
513             if (j >= srvAddrCount)
514                 break;
515             addrs[j++] = sa;
516         }
517     }
518
519     ReleaseReadLock(&afs_xsrvAddr);
520     ReleaseReadLock(&afs_xserver);
521     for (i = 0; i < j; i++) {
522         sa = addrs[i];
523         ForceNewConnections(sa);
524     }
525 }
526
527 /* check down servers (if adown), or running servers (if !adown) */
528 void
529 afs_CheckServers(int adown, struct cell *acellp)
530 {
531     struct vrequest treq;
532     struct server *ts;
533     struct srvAddr *sa;
534     struct conn *tc;
535     afs_int32 i, j;
536     afs_int32 code;
537     afs_int32 start, end = 0, delta;
538     osi_timeval_t tv;
539     struct unixuser *tu;
540     char tbuffer[CVBS];
541     int srvAddrCount;
542     struct srvAddr **addrs;
543     struct conn **conns;
544     int nconns;
545     struct rx_connection **rxconns;      
546     afs_int32 *conntimer, *deltas, *results;
547
548     AFS_STATCNT(afs_CheckServers);
549
550     conns = (struct conn **)0;
551     rxconns = (struct rx_connection **) 0;
552     conntimer = 0;
553     nconns = 0;
554
555     if ((code = afs_InitReq(&treq, afs_osi_credp)))
556         return;
557     ObtainReadLock(&afs_xserver);       /* Necessary? */
558     ObtainReadLock(&afs_xsrvAddr);
559
560     srvAddrCount = 0;
561     for (i = 0; i < NSERVERS; i++) {
562         for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
563             srvAddrCount++;
564         }
565     }
566
567     addrs = afs_osi_Alloc(srvAddrCount * sizeof(*addrs));
568     j = 0;
569     for (i = 0; i < NSERVERS; i++) {
570         for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
571             if (j >= srvAddrCount)
572                 break;
573             addrs[j++] = sa;
574         }
575     }
576
577     ReleaseReadLock(&afs_xsrvAddr);
578     ReleaseReadLock(&afs_xserver);
579
580     conns = (struct conn **)afs_osi_Alloc(j * sizeof(struct conn *));
581     rxconns = (struct rx_connection **)afs_osi_Alloc(j * sizeof(struct rx_connection *));
582     conntimer = (afs_int32 *)afs_osi_Alloc(j * sizeof (afs_int32));
583     deltas = (afs_int32 *)afs_osi_Alloc(j * sizeof (afs_int32));
584     results = (afs_int32 *)afs_osi_Alloc(j * sizeof (afs_int32));
585
586     for (i = 0; i < j; i++) {
587         deltas[i] = 0;
588         sa = addrs[i];
589         ts = sa->server;
590         if (!ts)
591             continue;
592
593         /* See if a cell to check was specified.  If it is spec'd and not
594          * this server's cell, just skip the server.
595          */
596         if (acellp && acellp != ts->cell)
597             continue;
598
599         if ((!adown && (sa->sa_flags & SRVADDR_ISDOWN))
600             || (adown && !(sa->sa_flags & SRVADDR_ISDOWN)))
601             continue;
602
603         /* check vlserver with special code */
604         if (sa->sa_portal == AFS_VLPORT) {
605             CheckVLServer(sa, &treq);
606             continue;
607         }
608
609         if (!ts->cell)          /* not really an active server, anyway, it must */
610             continue;           /* have just been added by setsprefs */
611
612         /* get a connection, even if host is down; bumps conn ref count */
613         tu = afs_GetUser(treq.uid, ts->cell->cellNum, SHARED_LOCK);
614         tc = afs_ConnBySA(sa, ts->cell->fsport, ts->cell->cellNum, tu,
615                           1 /*force */ , 1 /*create */ , SHARED_LOCK);
616         afs_PutUser(tu, SHARED_LOCK);
617         if (!tc)
618             continue;
619
620         if ((sa->sa_flags & SRVADDR_ISDOWN) || afs_HaveCallBacksFrom(sa->server)
621             || (tc->srvr->server == afs_setTimeHost)) {
622             conns[nconns]=tc; 
623             rxconns[nconns]=tc->id;
624             if (sa->sa_flags & SRVADDR_ISDOWN) {
625                 rx_SetConnDeadTime(tc->id, 3);
626                 conntimer[nconns]=1;
627             } else {
628                 conntimer[nconns]=0;
629             }
630             nconns++;
631         }
632     } /* Outer loop over addrs */
633
634     start = osi_Time();         /* time the gettimeofday call */
635     AFS_GUNLOCK(); 
636     multi_Rx(rxconns,nconns)
637       {
638         tv.tv_sec = tv.tv_usec = 0;
639         multi_RXAFS_GetTime(&tv.tv_sec, &tv.tv_usec);
640         tc = conns[multi_i];
641         sa = tc->srvr;
642         if (conntimer[multi_i] == 1)
643           rx_SetConnDeadTime(tc->id, afs_rx_deadtime);
644         end = osi_Time();
645         results[multi_i]=multi_error;
646         if ((start == end) && !multi_error)
647           deltas[multi_i] = end - tv.tv_sec;
648         
649       } multi_End;
650     AFS_GLOCK(); 
651     
652     for(i=0;i<nconns;i++){
653       tc = conns[i];
654       sa = tc->srvr;
655       
656       if (( results[i] >= 0 ) && (sa->sa_flags & SRVADDR_ISDOWN) && (tc->srvr == sa)) {
657         /* server back up */
658         print_internet_address("afs: file server ", sa, " is back up", 2);
659         
660         ObtainWriteLock(&afs_xserver, 244);
661         ObtainWriteLock(&afs_xsrvAddr, 245);        
662         afs_MarkServerUpOrDown(sa, 0);
663         ReleaseWriteLock(&afs_xsrvAddr);
664         ReleaseWriteLock(&afs_xserver);
665         
666         if (afs_waitForeverCount) {
667           afs_osi_Wakeup(&afs_waitForever);
668         }
669       } else {
670         if (results[i] < 0) {
671           /* server crashed */
672           afs_ServerDown(sa);
673           ForceNewConnections(sa);  /* multi homed clients */
674         }
675       }
676     }
677
678     /*
679      * If we're supposed to set the time, and the call worked
680      * quickly (same second response) and this is the host we
681      * use for the time and the time is really different, then
682      * really set the time
683      */
684     if (afs_setTime != 0) {
685         for (i=0; i<nconns; i++) {
686             delta = deltas[i];
687             tc = conns[i];
688             sa = tc->srvr;
689             
690             if ((tc->srvr->server == afs_setTimeHost ||
691                  /* Sync only to a server in the local cell */
692                  (afs_setTimeHost == (struct server *)0 &&
693                   afs_IsPrimaryCell(sa->server->cell)))) {
694                 /* set the time */
695                 char msgbuf[90];  /* strlen("afs: setting clock...") + slop */
696                 delta = end - tv.tv_sec;   /* how many secs fast we are */
697                 
698                 afs_setTimeHost = tc->srvr->server;
699                 /* see if clock has changed enough to make it worthwhile */
700                 if (delta >= AFS_MINCHANGE || delta <= -AFS_MINCHANGE) {
701                     end = osi_Time();
702                     if (delta > AFS_MAXCHANGEBACK) {
703                         /* setting clock too far back, just do it a little */
704                         tv.tv_sec = end - AFS_MAXCHANGEBACK;
705                     } else {
706                         tv.tv_sec = end - delta;
707                     }
708                     afs_osi_SetTime(&tv);
709                     if (delta > 0) {
710                         strcpy(msgbuf, "afs: setting clock back ");
711                         if (delta > AFS_MAXCHANGEBACK) {
712                             afs_strcat(msgbuf, 
713                                        afs_cv2string(&tbuffer[CVBS], 
714                                                      AFS_MAXCHANGEBACK));
715                             afs_strcat(msgbuf, " seconds (of ");
716                             afs_strcat(msgbuf, 
717                                        afs_cv2string(&tbuffer[CVBS], 
718                                                      delta - 
719                                                      AFS_MAXCHANGEBACK));
720                             afs_strcat(msgbuf, ", via ");
721                             print_internet_address(msgbuf, sa, 
722                                                    "); clock is still fast.",
723                                                    0);
724                         } else {
725                             afs_strcat(msgbuf, 
726                                        afs_cv2string(&tbuffer[CVBS], delta));
727                             afs_strcat(msgbuf, " seconds (via ");
728                             print_internet_address(msgbuf, sa, ").", 0);
729                         }
730                     } else {
731                         strcpy(msgbuf, "afs: setting clock ahead ");
732                         afs_strcat(msgbuf, 
733                                    afs_cv2string(&tbuffer[CVBS], -delta));
734                         afs_strcat(msgbuf, " seconds (via ");
735                         print_internet_address(msgbuf, sa, ").", 0);
736                     }
737                     /* We're only going to set it once; why bother looping? */
738                     break; 
739                 }
740             }
741         }
742     }
743     for (i = 0; i < nconns; i++) {
744         afs_PutConn(conns[i], SHARED_LOCK);     /* done with it now */
745     }
746     
747     afs_osi_Free(addrs, srvAddrCount * sizeof(*addrs));
748     afs_osi_Free(conns, j * sizeof(struct conn *));
749     afs_osi_Free(rxconns, j * sizeof(struct rx_connection *));
750     afs_osi_Free(conntimer, j * sizeof(afs_int32));
751     afs_osi_Free(deltas, j * sizeof(afs_int32));
752     afs_osi_Free(results, j * sizeof(afs_int32));
753     
754 } /*afs_CheckServers*/
755
756
757 /* find a server structure given the host address */
758 struct server *
759 afs_FindServer(afs_int32 aserver, afs_uint16 aport, afsUUID * uuidp,
760                afs_int32 locktype)
761 {
762     struct server *ts;
763     struct srvAddr *sa;
764     int i;
765
766     AFS_STATCNT(afs_FindServer);
767     if (uuidp) {
768         i = afs_uuid_hash(uuidp) % NSERVERS;
769         for (ts = afs_servers[i]; ts; ts = ts->next) {
770             if ((ts->flags & SRVR_MULTIHOMED)
771                 &&
772                 (memcmp((char *)uuidp, (char *)&ts->sr_uuid, sizeof(*uuidp))
773                  == 0) && (!ts->addr || (ts->addr->sa_portal == aport)))
774                 return ts;
775         }
776     } else {
777         i = SHash(aserver);
778         for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
779             if ((sa->sa_ip == aserver) && (sa->sa_portal == aport)) {
780                 return sa->server;
781             }
782         }
783     }
784     return NULL;
785
786 }                               /*afs_FindServer */
787
788
789 /* some code for creating new server structs and setting preferences follows
790  * in the next few lines...
791  */
792
793 #define MAXDEFRANK 60000
794 #define DEFRANK    40000
795
796 /* Random number generator and constants from KnuthV2 2d ed, p170 */
797
798 /* Rules:
799    X = (aX + c) % m
800    m is a power of two 
801    a % 8 is 5
802    a is 0.73m  should be 0.01m .. 0.99m
803    c is more or less immaterial.  1 or a is suggested.
804   
805 NB:  LOW ORDER BITS are not very random.  To get small random numbers,
806      treat result as <1, with implied binary point, and multiply by 
807      desired modulus.
808 NB:  Has to be unsigned, since shifts on signed quantities may preserve
809      the sign bit.
810 */
811 /* added rxi_getaddr() to try to get as much initial randomness as 
812    possible, since at least one customer reboots ALL their clients 
813    simultaneously -- so osi_Time is bound to be the same on some of the
814    clients.  This is probably OK, but I don't want to see too much of it.
815 */
816
817 #define ranstage(x)     (x)= (afs_uint32) (3141592621U*((afs_uint32)x)+1)
818
819 unsigned int
820 afs_random(void)
821 {
822     static afs_int32 state = 0;
823     register int i;
824
825     AFS_STATCNT(afs_random);
826     if (!state) {
827         osi_timeval_t t;
828         osi_GetTime(&t);
829         /*
830          * 0xfffffff0 was changed to (~0 << 4) since it works no matter how many
831          * bits are in a tv_usec
832          */
833         state = (t.tv_usec & (~0 << 4)) + (rxi_getaddr() & 0xff);
834         state += (t.tv_sec & 0xff);
835         for (i = 0; i < 30; i++) {
836             ranstage(state);
837         }
838     }
839
840     ranstage(state);
841     return (state);
842
843 }                               /*afs_random */
844
845 /* returns int 0..14 using the high bits of a pseudo-random number instead of
846    the low bits, as the low bits are "less random" than the high ones...
847    slight roundoff error exists, an excercise for the reader.
848    need to multiply by something with lots of ones in it, so multiply by 
849    8 or 16 is right out.
850  */
851 int
852 afs_randomMod15(void)
853 {
854     afs_uint32 temp;
855
856     temp = afs_random() >> 4;
857     temp = (temp * 15) >> 28;
858
859     return temp;
860 }
861
862 int
863 afs_randomMod127(void)
864 {
865     afs_uint32 temp;
866
867     temp = afs_random() >> 7;
868     temp = (temp * 127) >> 25;
869
870     return temp;
871 }
872
873 /* afs_SortOneServer()
874  * Sort all of the srvAddrs, of a server struct, by rank from low to high.
875  */
876 void
877 afs_SortOneServer(struct server *asp)
878 {
879     struct srvAddr **rootsa, *lowsa, *tsa, *lowprev;
880     int lowrank, rank;
881
882     for (rootsa = &(asp->addr); *rootsa; rootsa = &(lowsa->next_sa)) {
883         lowprev = NULL;
884         lowsa = *rootsa;        /* lowest sa is the first one */
885         lowrank = lowsa->sa_iprank;
886
887         for (tsa = *rootsa; tsa->next_sa; tsa = tsa->next_sa) {
888             rank = tsa->next_sa->sa_iprank;
889             if (rank < lowrank) {
890                 lowprev = tsa;
891                 lowsa = tsa->next_sa;
892                 lowrank = lowsa->sa_iprank;
893             }
894         }
895         if (lowprev) {          /* found one lower, so rearrange them */
896             lowprev->next_sa = lowsa->next_sa;
897             lowsa->next_sa = *rootsa;
898             *rootsa = lowsa;
899         }
900     }
901 }
902
903 /* afs_SortServer()
904  * Sort the pointer to servers by the server's rank (its lowest rank).
905  * It is assumed that the server already has its IP addrs sorted (the
906  * first being its lowest rank: afs_GetServer() calls afs_SortOneServer()).
907  */
908 void
909 afs_SortServers(struct server *aservers[], int count)
910 {
911     struct server *ts;
912     int i, j, low;
913
914     AFS_STATCNT(afs_SortServers);
915
916     for (i = 0; i < count; i++) {
917         if (!aservers[i])
918             break;
919         for (low = i, j = i + 1; j <= count; j++) {
920             if ((!aservers[j]) || (!aservers[j]->addr))
921                 break;
922             if ((!aservers[low]) || (!aservers[low]->addr))
923                 break;
924             if (aservers[j]->addr->sa_iprank < aservers[low]->addr->sa_iprank) {
925                 low = j;
926             }
927         }
928         if (low != i) {
929             ts = aservers[i];
930             aservers[i] = aservers[low];
931             aservers[low] = ts;
932         }
933     }
934 }                               /*afs_SortServers */
935
936 /* afs_SetServerPrefs is rather system-dependent.  It pokes around in kernel
937    data structures to determine what the local IP addresses and subnet masks 
938    are in order to choose which server(s) are on the local subnet.
939
940    As I see it, there are several cases:
941    1. The server address is one of this host's local addresses.  In this case
942           this server is to be preferred over all others.
943    2. The server is on the same subnet as one of the this host's local
944       addresses.  (ie, an odd-sized subnet, not class A,B,orC)
945    3. The server is on the same net as this host (class A,B or C)
946    4. The server is on a different logical subnet or net than this host, but
947    this host is a 'metric 0 gateway' to it.  Ie, two address-spaces share
948    one physical medium.
949    5. This host has a direct (point-to-point, ie, PPP or SLIP) link to the 
950    server.
951    6. This host and the server are disjoint.
952
953    That is a rough order of preference.  If a point-to-point link has a high
954    metric, I'm assuming that it is a very slow link, and putting it at the 
955    bottom of the list (at least until RX works better over slow links).  If 
956    its metric is 1, I'm assuming that it's relatively fast (T1) and putting 
957    it ahead of #6.
958    It's not easy to check for case #4, so I'm ignoring it for the time being.
959
960    BSD "if" code keeps track of some rough network statistics (cf 'netstat -i')
961    That could be used to prefer certain servers fairly easily.  Maybe some 
962    other time...
963
964    NOTE: this code is very system-dependent, and very dependent on the TCP/IP
965    protocols (well, addresses that are stored in uint32s, at any rate).
966  */
967
968 #define IA_DST(ia)((struct sockaddr_in *)(&((struct in_ifaddr *)ia)->ia_dstaddr))
969 #define IA_BROAD(ia)((struct sockaddr_in *)(&((struct in_ifaddr *)ia)->ia_broadaddr))
970
971 /* SA2ULONG takes a sockaddr_in, not a sockaddr (same thing, just cast it!) */
972 #define SA2ULONG(sa) ((sa)->sin_addr.s_addr)
973 #define TOPR 5000
974 #define HI  20000
975 #define MED 30000
976 #define LO DEFRANK
977 #define PPWEIGHT 4096
978
979 #define USEIFADDR
980
981
982 #if     defined(AFS_SUN5_ENV) && ! defined(AFS_SUN56_ENV)
983 #include <inet/common.h>
984 /* IP interface structure, one per local address */
985 typedef struct ipif_s {
986      /**/ struct ipif_s *ipif_next;
987     struct ill_s *ipif_ill;     /* Back pointer to our ill */
988     long ipif_id;               /* Logical unit number */
989     u_int ipif_mtu;             /* Starts at ipif_ill->ill_max_frag */
990     afs_int32 ipif_local_addr;  /* Local IP address for this if. */
991     afs_int32 ipif_net_mask;    /* Net mask for this interface. */
992     afs_int32 ipif_broadcast_addr;      /* Broadcast addr for this interface. */
993     afs_int32 ipif_pp_dst_addr; /* Point-to-point dest address. */
994     u_int ipif_flags;           /* Interface flags. */
995     u_int ipif_metric;          /* BSD if metric, for compatibility. */
996     u_int ipif_ire_type;        /* LOCAL or LOOPBACK */
997     mblk_t *ipif_arp_down_mp;   /* Allocated at time arp comes up to
998                                  * prevent awkward out of mem condition
999                                  * later
1000                                  */
1001     mblk_t *ipif_saved_ire_mp;  /* Allocated for each extra IRE_SUBNET/
1002                                  * RESOLVER on this interface so that
1003                                  * they can survive ifconfig down.
1004                                  */
1005     /*
1006      * The packet counts in the ipif contain the sum of the
1007      * packet counts in dead IREs that were affiliated with
1008      * this ipif.
1009      */
1010     u_long ipif_fo_pkt_count;   /* Forwarded thru our dead IREs */
1011     u_long ipif_ib_pkt_count;   /* Inbound packets for our dead IREs */
1012     u_long ipif_ob_pkt_count;   /* Outbound packets to our dead IREs */
1013     unsigned int
1014       ipif_multicast_up:1,      /* We have joined the allhosts group */
1015     : 0;
1016 } ipif_t;
1017
1018 typedef struct ipfb_s {
1019      /**/ struct ipf_s *ipfb_ipf;       /* List of ... */
1020     kmutex_t ipfb_lock;         /* Protect all ipf in list */
1021 } ipfb_t;
1022
1023 typedef struct ilm_s {
1024      /**/ afs_int32 ilm_addr;
1025     int ilm_refcnt;
1026     u_int ilm_timer;            /* IGMP */
1027     struct ipif_s *ilm_ipif;    /* Back pointer to ipif */
1028     struct ilm_s *ilm_next;     /* Linked list for each ill */
1029 } ilm_t;
1030
1031 typedef struct ill_s {
1032      /**/ struct ill_s *ill_next;       /* Chained in at ill_g_head. */
1033     struct ill_s **ill_ptpn;    /* Pointer to previous next. */
1034     queue_t *ill_rq;            /* Read queue. */
1035     queue_t *ill_wq;            /* Write queue. */
1036
1037     int ill_error;              /* Error value sent up by device. */
1038
1039     ipif_t *ill_ipif;           /* Interface chain for this ILL. */
1040     u_int ill_ipif_up_count;    /* Number of IPIFs currently up. */
1041     u_int ill_max_frag;         /* Max IDU. */
1042     char *ill_name;             /* Our name. */
1043     u_int ill_name_length;      /* Name length, incl. terminator. */
1044     u_int ill_subnet_type;      /* IRE_RESOLVER or IRE_SUBNET. */
1045     u_int ill_ppa;              /* Physical Point of Attachment num. */
1046     u_long ill_sap;
1047     int ill_sap_length;         /* Including sign (for position) */
1048     u_int ill_phys_addr_length; /* Excluding the sap. */
1049     mblk_t *ill_frag_timer_mp;  /* Reassembly timer state. */
1050     ipfb_t *ill_frag_hash_tbl;  /* Fragment hash list head. */
1051
1052     queue_t *ill_bind_pending_q;        /* Queue waiting for DL_BIND_ACK. */
1053     ipif_t *ill_ipif_pending;   /* IPIF waiting for DL_BIND_ACK. */
1054
1055     /* ill_hdr_length and ill_hdr_mp will be non zero if
1056      * the underlying device supports the M_DATA fastpath
1057      */
1058     int ill_hdr_length;
1059
1060     ilm_t *ill_ilm;             /* Multicast mebership for lower ill */
1061
1062     /* All non-nil cells between 'ill_first_mp_to_free' and
1063      * 'ill_last_mp_to_free' are freed in ill_delete.
1064      */
1065 #define ill_first_mp_to_free    ill_hdr_mp
1066     mblk_t *ill_hdr_mp;         /* Contains fastpath template */
1067     mblk_t *ill_bcast_mp;       /* DLPI header for broadcasts. */
1068     mblk_t *ill_bind_pending;   /* T_BIND_REQ awaiting completion. */
1069     mblk_t *ill_resolver_mp;    /* Resolver template. */
1070     mblk_t *ill_attach_mp;
1071     mblk_t *ill_bind_mp;
1072     mblk_t *ill_unbind_mp;
1073     mblk_t *ill_detach_mp;
1074 #define ill_last_mp_to_free     ill_detach_mp
1075
1076     u_int ill_frag_timer_running:1, ill_needs_attach:1, ill_is_ptp:1,
1077         ill_priv_stream:1, ill_unbind_pending:1, ill_pad_to_bit_31:27;
1078       MI_HRT_DCL(ill_rtime)
1079       MI_HRT_DCL(ill_rtmp)
1080 } ill_t;
1081 #endif
1082
1083 #ifdef AFS_USERSPACE_IP_ADDR
1084 #ifndef afs_min
1085 #define afs_min(A,B) ((A)<(B)) ? (A) : (B)
1086 #endif
1087 /*
1088  * The IP addresses and ranks are determined by afsd (in user space) and
1089  * passed into the kernel at startup time through the AFSOP_ADVISEADDR
1090  * system call. These are stored in the data structure 
1091  * called 'afs_cb_interface'. 
1092  *
1093  * struct srvAddr *sa;         remote server
1094  * afs_int32 addr;                one of my local addr in net order
1095  * afs_uint32 subnetmask;         subnet mask of local addr in net order
1096  *
1097  */
1098 void
1099 afsi_SetServerIPRank(struct srvAddr *sa, afs_int32 addr,
1100                      afs_uint32 subnetmask)
1101 {
1102     afs_uint32 myAddr, myNet, mySubnet, netMask;
1103     afs_uint32 serverAddr;
1104
1105     myAddr = ntohl(addr);       /* one of my IP addr in host order */
1106     serverAddr = ntohl(sa->sa_ip);      /* server's IP addr in host order */
1107     subnetmask = ntohl(subnetmask);     /* subnet mask in host order */
1108
1109     if (IN_CLASSA(myAddr))
1110         netMask = IN_CLASSA_NET;
1111     else if (IN_CLASSB(myAddr))
1112         netMask = IN_CLASSB_NET;
1113     else if (IN_CLASSC(myAddr))
1114         netMask = IN_CLASSC_NET;
1115     else
1116         netMask = 0;
1117
1118     myNet = myAddr & netMask;
1119     mySubnet = myAddr & subnetmask;
1120
1121     if ((serverAddr & netMask) == myNet) {
1122         if ((serverAddr & subnetmask) == mySubnet) {
1123             if (serverAddr == myAddr) { /* same machine */
1124                 sa->sa_iprank = afs_min(sa->sa_iprank, TOPR);
1125             } else {            /* same subnet */
1126                 sa->sa_iprank = afs_min(sa->sa_iprank, HI);
1127             }
1128         } else {                /* same net */
1129             sa->sa_iprank = afs_min(sa->sa_iprank, MED);
1130         }
1131     }
1132 }
1133 #else /* AFS_USERSPACE_IP_ADDR */
1134 #if (! defined(AFS_SUN5_ENV)) && !defined(AFS_DARWIN60_ENV) && defined(USEIFADDR)
1135 void
1136 afsi_SetServerIPRank(struct srvAddr *sa, struct in_ifaddr *ifa)
1137 {
1138     struct sockaddr_in *sin;
1139     int t;
1140
1141     if ((ntohl(sa->sa_ip) & ifa->ia_netmask) == ifa->ia_net) {
1142         if ((ntohl(sa->sa_ip) & ifa->ia_subnetmask) == ifa->ia_subnet) {
1143             sin = IA_SIN(ifa);
1144             if (SA2ULONG(sin) == ntohl(sa->sa_ip)) {    /* ie, ME!!!  */
1145                 sa->sa_iprank = TOPR;
1146             } else {
1147                 t = HI + ifa->ia_ifp->if_metric;        /* case #2 */
1148                 if (sa->sa_iprank > t)
1149                     sa->sa_iprank = t;
1150             }
1151         } else {
1152             t = MED + ifa->ia_ifp->if_metric;   /* case #3 */
1153             if (sa->sa_iprank > t)
1154                 sa->sa_iprank = t;
1155         }
1156     }
1157 #ifdef  IFF_POINTTOPOINT
1158     /* check for case #4 -- point-to-point link */
1159     if ((ifa->ia_ifp->if_flags & IFF_POINTOPOINT)
1160         && (SA2ULONG(IA_DST(ifa)) == ntohl(sa->sa_ip))) {
1161         if (ifa->ia_ifp->if_metric >= (MAXDEFRANK - MED) / PPWEIGHT)
1162             t = MAXDEFRANK;
1163         else
1164             t = MED + (PPWEIGHT << ifa->ia_ifp->if_metric);
1165         if (sa->sa_iprank > t)
1166             sa->sa_iprank = t;
1167     }
1168 #endif /* IFF_POINTTOPOINT */
1169 }
1170 #endif /*(!defined(AFS_SUN5_ENV)) && defined(USEIFADDR) */
1171 #if defined(AFS_DARWIN60_ENV) && defined(USEIFADDR)
1172 #ifndef afs_min
1173 #define afs_min(A,B) ((A)<(B)) ? (A) : (B)
1174 #endif
1175 void
1176 afsi_SetServerIPRank(sa, ifa)
1177      struct srvAddr *sa;
1178 #ifdef AFS_DARWIN80_ENV
1179      ifaddr_t ifa;
1180 #else
1181      struct ifaddr *ifa;
1182 #endif
1183 {
1184     struct sockaddr sout;
1185     struct sockaddr_in *sin;
1186     int t;
1187
1188     afs_uint32 subnetmask, myAddr, myNet, myDstaddr, mySubnet, netMask;
1189     afs_uint32 serverAddr;
1190
1191     if (ifaddr_address_family(ifa) != AF_INET)
1192         return;
1193     t = ifaddr_address(ifa, &sout, sizeof(sout));
1194     if (t == 0) {
1195         sin = (struct sockaddr_in *)&sout;
1196         myAddr = ntohl(sin->sin_addr.s_addr);   /* one of my IP addr in host order */
1197     } else {
1198         myAddr = 0;
1199     }
1200     serverAddr = ntohl(sa->sa_ip);      /* server's IP addr in host order */
1201     t = ifaddr_netmask(ifa, &sout, sizeof(sout));
1202     if (t == 0) {
1203         sin = (struct sockaddr_in *)&sout;
1204         subnetmask = ntohl(sin->sin_addr.s_addr);       /* subnet mask in host order */
1205     } else {
1206         subnetmask = 0;
1207     }
1208     t = ifaddr_dstaddress(ifa, &sout, sizeof(sout));
1209     if (t == 0) {
1210         sin = (struct sockaddr_in *)&sout;
1211         myDstaddr = sin->sin_addr.s_addr;
1212     } else {
1213         myDstaddr = 0;
1214     }
1215
1216     if (IN_CLASSA(myAddr))
1217         netMask = IN_CLASSA_NET;
1218     else if (IN_CLASSB(myAddr))
1219         netMask = IN_CLASSB_NET;
1220     else if (IN_CLASSC(myAddr))
1221         netMask = IN_CLASSC_NET;
1222     else
1223         netMask = 0;
1224
1225     myNet = myAddr & netMask;
1226     mySubnet = myAddr & subnetmask;
1227
1228     if ((serverAddr & netMask) == myNet) {
1229         if ((serverAddr & subnetmask) == mySubnet) {
1230             if (serverAddr == myAddr) { /* same machine */
1231                 sa->sa_iprank = afs_min(sa->sa_iprank, TOPR);
1232             } else {            /* same subnet */
1233                 sa->sa_iprank = afs_min(sa->sa_iprank, HI + ifnet_metric(ifaddr_ifnet(ifa)));
1234             }
1235         } else {                /* same net */
1236             sa->sa_iprank = afs_min(sa->sa_iprank, MED + ifnet_metric(ifaddr_ifnet(ifa)));
1237         }
1238     }
1239 #ifdef  IFF_POINTTOPOINT
1240     /* check for case #4 -- point-to-point link */
1241     if ((ifnet_flags(ifaddr_ifnet(ifa)) & IFF_POINTOPOINT)
1242         && (myDstaddr == serverAddr)) {
1243         if (ifnet_metric(ifaddr_ifnet(ifa)) >= (MAXDEFRANK - MED) / PPWEIGHT)
1244             t = MAXDEFRANK;
1245         else
1246             t = MED + (PPWEIGHT << ifnet_metric(ifaddr_ifnet(ifa)));
1247         if (sa->sa_iprank > t)
1248             sa->sa_iprank = t;
1249         }
1250 #endif /* IFF_POINTTOPOINT */
1251 }
1252 #endif /*(!defined(AFS_SUN5_ENV)) && defined(USEIFADDR) */
1253 #endif /* else AFS_USERSPACE_IP_ADDR */
1254
1255 #ifdef AFS_SGI62_ENV
1256 static int
1257
1258   afsi_enum_set_rank(struct hashbucket *h, caddr_t mkey, caddr_t arg1,
1259                      caddr_t arg2) {
1260     afsi_SetServerIPRank((struct srvAddr *)arg1, (struct in_ifaddr *)h);
1261     return 0;                   /* Never match, so we enumerate everyone */
1262 }
1263 #endif                          /* AFS_SGI62_ENV */
1264 static int afs_SetServerPrefs(struct srvAddr *sa) {
1265 #if     defined(AFS_USERSPACE_IP_ADDR)
1266     int i;
1267
1268       sa->sa_iprank = LO;
1269     for (i = 0; i < afs_cb_interface.numberOfInterfaces; i++) {
1270         afsi_SetServerIPRank(sa, afs_cb_interface.addr_in[i],
1271                              afs_cb_interface.subnetmask[i]);
1272     }
1273 #else                           /* AFS_USERSPACE_IP_ADDR */
1274 #if     defined(AFS_SUN5_ENV)
1275 #ifdef AFS_SUN510_ENV
1276     ill_walk_context_t ctx;
1277 #else
1278     extern struct ill_s *ill_g_headp;
1279     long *addr = (long *)ill_g_headp;
1280 #endif
1281     ill_t *ill;
1282     ipif_t *ipif;
1283     int subnet, subnetmask, net, netmask;
1284
1285     if (sa)
1286           sa->sa_iprank = 0;
1287 #ifdef AFS_SUN510_ENV
1288     for (ill = ILL_START_WALK_ALL(&ctx) ; ill ; ill = ill_next(&ctx, ill)) {
1289 #else
1290     for (ill = (struct ill_s *)*addr /*ill_g_headp */ ; ill;
1291          ill = ill->ill_next) {
1292 #endif
1293 #ifdef AFS_SUN58_ENV
1294         /* Make sure this is an IPv4 ILL */
1295         if (ill->ill_isv6)
1296             continue;
1297 #endif
1298         for (ipif = ill->ill_ipif; ipif; ipif = ipif->ipif_next) {
1299             subnet = ipif->ipif_local_addr & ipif->ipif_net_mask;
1300             subnetmask = ipif->ipif_net_mask;
1301             /*
1302              * Generate the local net using the local address and 
1303              * whate we know about Class A, B and C networks.
1304              */
1305             if (IN_CLASSA(ipif->ipif_local_addr)) {
1306                 netmask = IN_CLASSA_NET;
1307             } else if (IN_CLASSB(ipif->ipif_local_addr)) {
1308                 netmask = IN_CLASSB_NET;
1309             } else if (IN_CLASSC(ipif->ipif_local_addr)) {
1310                 netmask = IN_CLASSC_NET;
1311             } else {
1312                 netmask = 0;
1313             }
1314             net = ipif->ipif_local_addr & netmask;
1315 #ifdef notdef
1316             if (!s) {
1317                 if (ipif->ipif_local_addr != 0x7f000001) {      /* ignore loopback */
1318                     *cnt += 1;
1319                     if (*cnt > 16)
1320                         return;
1321                     *addrp++ = ipif->ipif_local_addr;
1322                 }
1323             } else
1324 #endif /* notdef */
1325             {
1326                 /* XXXXXX Do the individual ip ranking below XXXXX */
1327                 if ((sa->sa_ip & netmask) == net) {
1328                     if ((sa->sa_ip & subnetmask) == subnet) {
1329                         if (ipif->ipif_local_addr == sa->sa_ip) {       /* ie, ME!  */
1330                             sa->sa_iprank = TOPR;
1331                         } else {
1332                             sa->sa_iprank = HI + ipif->ipif_metric;     /* case #2 */
1333                         }
1334                     } else {
1335                         sa->sa_iprank = MED + ipif->ipif_metric;        /* case #3 */
1336                     }
1337                 } else {
1338                     sa->sa_iprank = LO + ipif->ipif_metric;     /* case #4 */
1339                 }
1340                 /* check for case #5 -- point-to-point link */
1341                 if ((ipif->ipif_flags & IFF_POINTOPOINT)
1342                     && (ipif->ipif_pp_dst_addr == sa->sa_ip)) {
1343
1344                     if (ipif->ipif_metric >= (MAXDEFRANK - MED) / PPWEIGHT)
1345                         sa->sa_iprank = MAXDEFRANK;
1346                     else
1347                         sa->sa_iprank = MED + (PPWEIGHT << ipif->ipif_metric);
1348                 }
1349             }
1350         }
1351     }
1352 #else
1353 #ifndef USEIFADDR
1354     struct ifnet *ifn = NULL;
1355     struct in_ifaddr *ifad = (struct in_ifaddr *)0;
1356     struct sockaddr_in *sin;
1357
1358     if (!sa) {
1359 #ifdef notdef                   /* clean up, remove this */
1360         for (ifn = ifnet; ifn != NULL; ifn = ifn->if_next) {
1361             for (ifad = ifn->if_addrlist; ifad != NULL; ifad = ifad->ifa_next) {
1362                 if ((IFADDR2SA(ifad)->sa_family == AF_INET)
1363                     && !(ifn->if_flags & IFF_LOOPBACK)) {
1364                     *cnt += 1;
1365                     if (*cnt > 16)
1366                         return;
1367                     *addrp++ =
1368                         ((struct sockaddr_in *)IFADDR2SA(ifad))->sin_addr.
1369                         s_addr;
1370                 }
1371         }}
1372 #endif                          /* notdef */
1373         return;
1374     }
1375     sa->sa_iprank = 0;
1376 #ifdef  ADAPT_MTU
1377     ifn = rxi_FindIfnet(sa->sa_ip, &ifad);
1378 #endif
1379     if (ifn) {                  /* local, more or less */
1380 #ifdef IFF_LOOPBACK
1381         if (ifn->if_flags & IFF_LOOPBACK) {
1382             sa->sa_iprank = TOPR;
1383             goto end;
1384         }
1385 #endif /* IFF_LOOPBACK */
1386         sin = (struct sockaddr_in *)IA_SIN(ifad);
1387         if (SA2ULONG(sin) == sa->sa_ip) {
1388             sa->sa_iprank = TOPR;
1389             goto end;
1390         }
1391 #ifdef IFF_BROADCAST
1392         if (ifn->if_flags & IFF_BROADCAST) {
1393             if (sa->sa_ip == (sa->sa_ip & SA2ULONG(IA_BROAD(ifad)))) {
1394                 sa->sa_iprank = HI;
1395                 goto end;
1396             }
1397         }
1398 #endif /* IFF_BROADCAST */
1399 #ifdef IFF_POINTOPOINT
1400         if (ifn->if_flags & IFF_POINTOPOINT) {
1401             if (sa->sa_ip == SA2ULONG(IA_DST(ifad))) {
1402                 if (ifn->if_metric > 4) {
1403                     sa->sa_iprank = LO;
1404                     goto end;
1405                 } else
1406                     sa->sa_iprank = ifn->if_metric;
1407             }
1408         }
1409 #endif /* IFF_POINTOPOINT */
1410         sa->sa_iprank += MED + ifn->if_metric;  /* couldn't find anything better */
1411     }
1412 #else                           /* USEIFADDR */
1413
1414     if (sa)
1415         sa->sa_iprank = LO;
1416 #ifdef AFS_SGI62_ENV
1417     (void)hash_enum(&hashinfo_inaddr, afsi_enum_set_rank, HTF_INET, NULL,
1418                     (caddr_t) sa, NULL);
1419 #elif defined(AFS_DARWIN80_ENV)
1420     {
1421         errno_t t;
1422         unsigned int count;
1423         int cnt=0, m, j;
1424         ifaddr_t *ifads;
1425         ifnet_t *ifn;
1426
1427         if (!ifnet_list_get(AF_INET, &ifn, &count)) {
1428             for (m = 0; m < count; m++) {
1429                 if (!ifnet_get_address_list(ifn[m], &ifads)) {
1430                     for (j = 0; ifads[j] != NULL && cnt < ADDRSPERSITE; j++) {
1431                         afsi_SetServerIPRank(sa, ifads[j]);
1432                         cnt++;
1433                     }
1434                     ifnet_free_address_list(ifads);
1435                 }
1436             }
1437             ifnet_list_free(ifn);
1438         }
1439     }
1440 #elif defined(AFS_DARWIN60_ENV)
1441     {
1442         struct ifnet *ifn;
1443         struct ifaddr *ifa;
1444           TAILQ_FOREACH(ifn, &ifnet, if_link) {
1445             TAILQ_FOREACH(ifa, &ifn->if_addrhead, ifa_link) {
1446                 afsi_SetServerIPRank(sa, ifa);
1447     }}}
1448 #elif defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
1449     {
1450         struct in_ifaddr *ifa;
1451           TAILQ_FOREACH(ifa, &in_ifaddrhead, ia_link) {
1452             afsi_SetServerIPRank(sa, ifa);
1453     }}
1454 #elif defined(AFS_OBSD_ENV)
1455     {
1456         extern struct in_ifaddrhead in_ifaddr;
1457         struct in_ifaddr *ifa;
1458         for (ifa = in_ifaddr.tqh_first; ifa; ifa = ifa->ia_list.tqe_next)
1459             afsi_SetServerIPRank(sa, ifa);
1460     }
1461 #else
1462     {
1463         struct in_ifaddr *ifa;
1464         for (ifa = in_ifaddr; ifa; ifa = ifa->ia_next) {
1465             afsi_SetServerIPRank(sa, ifa);
1466     }}
1467 #endif
1468     end:
1469 #endif                          /* USEIFADDR */
1470 #endif                          /* AFS_SUN5_ENV */
1471 #endif                          /* else AFS_USERSPACE_IP_ADDR */
1472     if (sa)
1473           sa->sa_iprank += afs_randomMod15();
1474
1475     return 0;
1476 }                               /* afs_SetServerPrefs */
1477
1478 #undef TOPR
1479 #undef HI
1480 #undef MED
1481 #undef LO
1482 #undef PPWEIGHT
1483
1484 /* afs_FlushServer()
1485  * The addresses on this server struct has changed in some way and will
1486  * clean up all other structures that may reference it.
1487  * The afs_xserver and afs_xsrvAddr locks are assumed taken.
1488  */
1489 void afs_FlushServer(struct server *srvp) {
1490     afs_int32 i;
1491     struct server *ts, **pts;
1492
1493     /* Find any volumes residing on this server and flush their state */
1494       afs_ResetVolumes(srvp);
1495
1496     /* Flush all callbacks in the all vcaches for this specific server */
1497       afs_FlushServerCBs(srvp);
1498
1499     /* Remove all the callbacks structs */
1500     if (srvp->cbrs) {
1501         struct afs_cbr *cb, *cbnext;
1502
1503           MObtainWriteLock(&afs_xvcb, 300);
1504         for (cb = srvp->cbrs; cb; cb = cbnext) {
1505             cbnext = cb->next;
1506             afs_FreeCBR(cb);
1507         } srvp->cbrs = (struct afs_cbr *)0;
1508         ReleaseWriteLock(&afs_xvcb);
1509     }
1510
1511     /* If no more srvAddr structs hanging off of this server struct,
1512      * then clean it up.
1513      */
1514     if (!srvp->addr) {
1515         /* Remove the server structure from the cell list - if there */
1516         afs_RemoveCellEntry(srvp);
1517
1518         /* Remove from the afs_servers hash chain */
1519         for (i = 0; i < NSERVERS; i++) {
1520             for (pts = &(afs_servers[i]), ts = *pts; ts;
1521                  pts = &(ts->next), ts = *pts) {
1522                 if (ts == srvp)
1523                     break;
1524             }
1525             if (ts)
1526                 break;
1527         }
1528         if (ts) {
1529             *pts = ts->next;    /* Found it. Remove it */
1530             afs_osi_Free(ts, sizeof(struct server));    /* Free it */
1531             afs_totalServers--;
1532         }
1533     }
1534 }
1535
1536 /* afs_RemoveSrvAddr()
1537  * This removes a SrvAddr structure from its server structure.
1538  * The srvAddr struct is not free'd because it connections may still
1539  * be open to it. It is up to the calling process to make sure it
1540  * remains connected to a server struct.
1541  * The afs_xserver and afs_xsrvAddr locks are assumed taken.
1542  *    It is not removed from the afs_srvAddrs hash chain.
1543  */
1544 void afs_RemoveSrvAddr(struct srvAddr *sap) {
1545     struct srvAddr **psa, *sa;
1546     struct server *srv;
1547
1548     if (!sap)
1549           return;
1550       srv = sap->server;
1551
1552     /* Find the srvAddr in the server's list and remove it */
1553     for (psa = &(srv->addr), sa = *psa; sa; psa = &(sa->next_sa), sa = *psa) {
1554         if (sa == sap)
1555             break;
1556     } if (sa) {
1557         *psa = sa->next_sa;
1558         sa->next_sa = 0;
1559         sa->server = 0;
1560
1561         /* Flush the server struct since it's IP address has changed */
1562         afs_FlushServer(srv);
1563     }
1564 }
1565
1566 /* afs_GetServer()
1567  * Return an updated and properly initialized server structure
1568  * corresponding to the server ID, cell, and port specified.
1569  * If one does not exist, then one will be created.
1570  * aserver and aport must be in NET byte order.
1571  */
1572 struct server *afs_GetServer(afs_uint32 * aserverp, afs_int32 nservers,
1573                              afs_int32 acell, u_short aport,
1574                              afs_int32 locktype, afsUUID * uuidp,
1575                              afs_int32 addr_uniquifier) {
1576     struct server *oldts = 0, *ts, *newts, *orphts = 0;
1577     struct srvAddr *oldsa, *newsa, *nextsa, *orphsa;
1578     u_short fsport;
1579     afs_int32 iphash, k, srvcount = 0;
1580     unsigned int srvhash;
1581
1582     AFS_STATCNT(afs_GetServer);
1583
1584     ObtainSharedLock(&afs_xserver, 13);
1585
1586     /* Check if the server struct exists and is up to date */
1587     if (!uuidp) {
1588         if (nservers != 1)
1589             panic("afs_GetServer: incorect count of servers");
1590         ObtainReadLock(&afs_xsrvAddr);
1591         ts = afs_FindServer(aserverp[0], aport, NULL, locktype);
1592         ReleaseReadLock(&afs_xsrvAddr);
1593         if (ts && !(ts->flags & SRVR_MULTIHOMED)) {
1594             /* Found a server struct that is not multihomed and has the
1595              * IP address associated with it. A correct match.
1596              */
1597             ReleaseSharedLock(&afs_xserver);
1598             return (ts);
1599         }
1600     } else {
1601         if (nservers <= 0)
1602             panic("afs_GetServer: incorrect count of servers");
1603         ts = afs_FindServer(0, aport, uuidp, locktype);
1604         if (ts && (ts->sr_addr_uniquifier == addr_uniquifier) && ts->addr) {
1605             /* Found a server struct that is multihomed and same
1606              * uniqufier (same IP addrs). The above if statement is the
1607              * same as in InstallUVolumeEntry().
1608              */
1609             ReleaseSharedLock(&afs_xserver);
1610             return ts;
1611         }
1612         if (ts)
1613             oldts = ts;         /* Will reuse if same uuid */
1614     }
1615
1616     UpgradeSToWLock(&afs_xserver, 36);
1617     ObtainWriteLock(&afs_xsrvAddr, 116);
1618
1619     srvcount = afs_totalServers;
1620
1621     /* Reuse/allocate a new server structure */
1622     if (oldts) {
1623         newts = oldts;
1624     } else {
1625         newts = (struct server *)afs_osi_Alloc(sizeof(struct server));
1626         if (!newts)
1627             panic("malloc of server struct");
1628         afs_totalServers++;
1629         memset((char *)newts, 0, sizeof(struct server));
1630
1631         /* Add the server struct to the afs_servers[] hash chain */
1632         srvhash =
1633             (uuidp ? (afs_uuid_hash(uuidp) % NSERVERS) : SHash(aserverp[0]));
1634         newts->next = afs_servers[srvhash];
1635         afs_servers[srvhash] = newts;
1636     }
1637
1638     /* Initialize the server structure */
1639     if (uuidp) {                /* Multihomed */
1640         newts->sr_uuid = *uuidp;
1641         newts->sr_addr_uniquifier = addr_uniquifier;
1642         newts->flags |= SRVR_MULTIHOMED;
1643     }
1644     if (acell)
1645         newts->cell = afs_GetCell(acell, 0);
1646
1647     fsport = (newts->cell ? newts->cell->fsport : AFS_FSPORT);
1648
1649     /* For each IP address we are registering */
1650     for (k = 0; k < nservers; k++) {
1651         iphash = SHash(aserverp[k]);
1652
1653         /* Check if the srvAddr structure already exists. If so, remove
1654          * it from its server structure and add it to the new one.
1655          */
1656         for (oldsa = afs_srvAddrs[iphash]; oldsa; oldsa = oldsa->next_bkt) {
1657             if ((oldsa->sa_ip == aserverp[k]) && (oldsa->sa_portal == aport))
1658                 break;
1659         }
1660         if (oldsa && (oldsa->server != newts)) {
1661             afs_RemoveSrvAddr(oldsa);   /* Remove from its server struct */
1662             oldsa->next_sa = newts->addr;       /* Add to the  new server struct */
1663             newts->addr = oldsa;
1664         }
1665
1666         /* Reuse/allocate a new srvAddr structure */
1667         if (oldsa) {
1668             newsa = oldsa;
1669         } else {
1670             newsa = (struct srvAddr *)afs_osi_Alloc(sizeof(struct srvAddr));
1671             if (!newsa)
1672                 panic("malloc of srvAddr struct");
1673             afs_totalSrvAddrs++;
1674             memset((char *)newsa, 0, sizeof(struct srvAddr));
1675
1676             /* Add the new srvAddr to the afs_srvAddrs[] hash chain */
1677             newsa->next_bkt = afs_srvAddrs[iphash];
1678             afs_srvAddrs[iphash] = newsa;
1679
1680             /* Hang off of the server structure  */
1681             newsa->next_sa = newts->addr;
1682             newts->addr = newsa;
1683
1684             /* Initialize the srvAddr Structure */
1685             newsa->sa_ip = aserverp[k];
1686             newsa->sa_portal = aport;
1687         }
1688
1689         /* Update the srvAddr Structure */
1690         newsa->server = newts;
1691         if (newts->flags & SRVR_ISDOWN)
1692             newsa->sa_flags |= SRVADDR_ISDOWN;
1693         if (uuidp)
1694             newsa->sa_flags |= SRVADDR_MH;
1695         else
1696             newsa->sa_flags &= ~SRVADDR_MH;
1697
1698         /* Compute preference values and resort */
1699         if (!newsa->sa_iprank) {
1700             afs_SetServerPrefs(newsa);  /* new server rank */
1701         }
1702     }
1703     afs_SortOneServer(newts);   /* Sort by rank */
1704
1705     /* If we reused the server struct, remove any of its srvAddr
1706      * structs that will no longer be associated with this server.
1707      */
1708     if (oldts) {                /* reused the server struct */
1709         for (orphsa = newts->addr; orphsa; orphsa = nextsa) {
1710             nextsa = orphsa->next_sa;
1711             for (k = 0; k < nservers; k++) {
1712                 if (orphsa->sa_ip == aserverp[k])
1713                     break;      /* belongs */
1714             }
1715             if (k < nservers)
1716                 continue;       /* belongs */
1717
1718             /* Have a srvAddr struct. Now get a server struct (if not already) */
1719             if (!orphts) {
1720                 orphts =
1721                     (struct server *)afs_osi_Alloc(sizeof(struct server));
1722                 if (!orphts)
1723                     panic("malloc of lo server struct");
1724                 memset((char *)orphts, 0, sizeof(struct server));
1725                 afs_totalServers++;
1726
1727                 /* Add the orphaned server to the afs_servers[] hash chain.
1728                  * Its iphash does not matter since we never look up the server
1729                  * in the afs_servers table by its ip address (only by uuid - 
1730                  * which this has none).
1731                  */
1732                 iphash = SHash(aserverp[k]);
1733                 orphts->next = afs_servers[iphash];
1734                 afs_servers[iphash] = orphts;
1735
1736                 if (acell)
1737                     orphts->cell = afs_GetCell(acell, 0);
1738             }
1739
1740             /* Hang the srvAddr struct off of the server structure. The server
1741              * may have multiple srvAddrs, but it won't be marked multihomed.
1742              */
1743             afs_RemoveSrvAddr(orphsa);  /* remove */
1744             orphsa->next_sa = orphts->addr;     /* hang off server struct */
1745             orphts->addr = orphsa;
1746             orphsa->server = orphts;
1747             orphsa->sa_flags |= SRVADDR_NOUSE;  /* flag indicating not in use */
1748             orphsa->sa_flags &= ~SRVADDR_MH;    /* Not multihomed */
1749         }
1750     }
1751
1752     srvcount = afs_totalServers - srvcount;     /* # servers added and removed */
1753     if (srvcount) {
1754         struct afs_stats_SrvUpDownInfo *upDownP;
1755         /* With the introduction of this new record, we need to adjust the
1756          * proper individual & global server up/down info.
1757          */
1758         upDownP = GetUpDownStats(newts);
1759         upDownP->numTtlRecords += srvcount;
1760         afs_stats_cmperf.srvRecords += srvcount;
1761         if (afs_stats_cmperf.srvRecords > afs_stats_cmperf.srvRecordsHWM)
1762             afs_stats_cmperf.srvRecordsHWM = afs_stats_cmperf.srvRecords;
1763     }
1764
1765     ReleaseWriteLock(&afs_xsrvAddr);
1766     ReleaseWriteLock(&afs_xserver);
1767     return (newts);
1768 }                               /* afs_GetServer */
1769
1770 void afs_ActivateServer(struct srvAddr *sap) {
1771     osi_timeval_t currTime;     /*Filled with current time */
1772     osi_timeval_t *currTimeP;   /*Ptr to above */
1773     struct afs_stats_SrvUpDownInfo *upDownP;    /*Ptr to up/down info record */
1774     struct server *aserver = sap->server;
1775
1776     if (!(aserver->flags & AFS_SERVER_FLAG_ACTIVATED)) {
1777         /*
1778          * This server record has not yet been activated.  Go for it,
1779          * recording its ``birth''.
1780          */
1781         aserver->flags |= AFS_SERVER_FLAG_ACTIVATED;
1782         currTimeP = &currTime;
1783         osi_GetuTime(currTimeP);
1784         aserver->activationTime = currTime.tv_sec;
1785         upDownP = GetUpDownStats(aserver);
1786         if (aserver->flags & SRVR_ISDOWN) {
1787             upDownP->numDownRecords++;
1788         } else {
1789             upDownP->numUpRecords++;
1790             upDownP->numRecordsNeverDown++;
1791         }
1792     }
1793 }
1794
1795
1796 void shutdown_server()
1797 {
1798     int i;
1799
1800     for (i = 0; i < NSERVERS; i++) {
1801         struct server *ts, *next;
1802
1803         ts = afs_servers[i];
1804         while(ts) {
1805             next = ts->next;
1806             afs_osi_Free(ts, sizeof(struct server));
1807             ts = next;
1808         }
1809     }
1810
1811     for (i = 0; i < NSERVERS; i++) {
1812         struct srvAddr *sa, *next;
1813
1814         sa = afs_srvAddrs[i];
1815         while(sa) {
1816             next = sa->next_bkt;
1817             afs_osi_Free(sa, sizeof(struct srvAddr));
1818             sa = next;
1819         }
1820     }
1821 }