more-rx-updates-20060504
[openafs.git] / src / rx / rx_user.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 /* rx_user.c contains routines specific to the user space UNIX implementation of rx */
11
12 #include <afsconfig.h>
13 #include <afs/param.h>
14
15 RCSID
16     ("$Header$");
17
18 # include <sys/types.h>
19 # include <errno.h>
20 # include <signal.h>
21 #ifdef AFS_NT40_ENV
22 # include <WINNT/syscfg.h>
23 #else
24 # include <sys/socket.h>
25 # include <sys/file.h>
26 # include <netdb.h>
27 # include <sys/stat.h>
28 # include <netinet/in.h>
29 # include <sys/time.h>
30 # include <net/if.h>
31 # include <sys/ioctl.h>
32 #endif
33 # include <fcntl.h>
34 #if !defined(AFS_AIX_ENV) && !defined(AFS_NT40_ENV) && !defined(AFS_DJGPP_ENV)
35 # include <sys/syscall.h>
36 #endif
37 #include <afs/afs_args.h>
38 #include <afs/afsutil.h>
39 #ifdef HAVE_STRING_H
40 #include <string.h>
41 #else
42 #ifdef HAVE_STRINGS_H
43 #include <strings.h>
44 #endif
45 #endif
46
47 #ifndef IPPORT_USERRESERVED
48 /* If in.h doesn't define this, define it anyway.  Unfortunately, defining
49    this doesn't put the code into the kernel to restrict kernel assigned
50    port numbers to numbers below IPPORT_USERRESERVED...  */
51 #define IPPORT_USERRESERVED 5000
52 # endif
53
54 #ifndef AFS_NT40_ENV
55 # include <sys/time.h>
56 #endif
57 # include "rx.h"
58 # include "rx_globals.h"
59
60 #ifdef AFS_PTHREAD_ENV
61 #include <assert.h>
62
63 /*
64  * The rx_if_init_mutex mutex protects the following global variables:
65  * Inited
66  */
67
68 pthread_mutex_t rx_if_init_mutex;
69 #define LOCK_IF_INIT assert(pthread_mutex_lock(&rx_if_init_mutex)==0)
70 #define UNLOCK_IF_INIT assert(pthread_mutex_unlock(&rx_if_init_mutex)==0)
71
72 /*
73  * The rx_if_mutex mutex protects the following global variables:
74  * myNetFlags
75  * myNetMTUs
76  * myNetMasks
77  */
78
79 pthread_mutex_t rx_if_mutex;
80 #define LOCK_IF assert(pthread_mutex_lock(&rx_if_mutex)==0)
81 #define UNLOCK_IF assert(pthread_mutex_unlock(&rx_if_mutex)==0)
82 #else
83 #define LOCK_IF_INIT
84 #define UNLOCK_IF_INIT
85 #define LOCK_IF
86 #define UNLOCK_IF
87 #endif /* AFS_PTHREAD_ENV */
88
89
90 /*
91  * Make a socket for receiving/sending IP packets.  Set it into non-blocking
92  * and large buffering modes.  If port isn't specified, the kernel will pick
93  * one.  Returns the socket (>= 0) on success.  Returns OSI_NULLSOCKET on
94  * failure. Port must be in network byte order. 
95  */
96 osi_socket
97 rxi_GetHostUDPSocket(struct sockaddr_storage *saddr, int salen)
98 {
99     int binds, code = 0;
100     osi_socket socketFd = OSI_NULLSOCKET;
101     char *name = "rxi_GetUDPSocket: ";
102 #ifdef AFS_LINUX22_ENV
103     int pmtu=IP_PMTUDISC_DONT;
104 #endif
105
106 #if 0
107 #if !defined(AFS_NT40_ENV) && !defined(AFS_DJGPP_ENV)
108     if (ntohs(port) >= IPPORT_RESERVED && ntohs(port) < IPPORT_USERRESERVED) {
109 /*      (osi_Msg "%s*WARNING* port number %d is not a reserved port number.  Use port numbers above %d\n", name, port, IPPORT_USERRESERVED);
110 */ ;
111     }
112     if (ntohs(port) > 0 && ntohs(port) < IPPORT_RESERVED && geteuid() != 0) {
113         (osi_Msg
114          "%sport number %d is a reserved port number which may only be used by root.  Use port numbers above %d\n",
115          name, ntohs(port), IPPORT_USERRESERVED);
116         goto error;
117     }
118 #endif
119 #endif
120     socketFd = socket(rx_ssfamily(saddr), SOCK_DGRAM, 0);
121
122     if (socketFd < 0) {
123         perror("socket");
124         goto error;
125     }
126
127 #define MAX_RX_BINDS 10
128     for (binds = 0; binds < MAX_RX_BINDS; binds++) {
129         if (binds)
130             rxi_Delay(10);
131         code = bind(socketFd, (struct sockaddr *) saddr, salen);
132         if (!code)
133             break;
134     }
135     if (code) {
136         perror("bind");
137         (osi_Msg "%sbind failed\n", name);
138         goto error;
139     }
140 #if !defined(AFS_NT40_ENV) && !defined(AFS_DJGPP_ENV)
141     /*
142      * Set close-on-exec on rx socket 
143      */
144     fcntl(socketFd, F_SETFD, 1);
145 #endif
146
147 #ifndef AFS_DJGPP_ENV
148     /* Use one of three different ways of getting a socket buffer expanded to
149      * a reasonable size.
150      */
151     {
152         int greedy = 0;
153         int len1, len2;
154
155         len1 = 32766;
156         len2 = rx_UdpBufSize;
157         greedy =
158             (setsockopt
159              (socketFd, SOL_SOCKET, SO_RCVBUF, (char *)&len2,
160               sizeof(len2)) >= 0);
161         if (!greedy) {
162             len2 = 32766;       /* fall back to old size... uh-oh! */
163         }
164
165         greedy =
166             (setsockopt
167              (socketFd, SOL_SOCKET, SO_SNDBUF, (char *)&len1,
168               sizeof(len1)) >= 0)
169             &&
170             (setsockopt
171              (socketFd, SOL_SOCKET, SO_RCVBUF, (char *)&len2,
172               sizeof(len2)) >= 0);
173         if (!greedy)
174             (osi_Msg "%s*WARNING* Unable to increase buffering on socket\n",
175              name);
176         MUTEX_ENTER(&rx_stats_mutex);
177         rx_stats.socketGreedy = greedy;
178         MUTEX_EXIT(&rx_stats_mutex);
179     }
180 #endif /* AFS_DJGPP_ENV */
181
182 #ifdef AFS_LINUX22_ENV
183     setsockopt(socketFd, SOL_IP, IP_MTU_DISCOVER, &pmtu, sizeof(pmtu));
184 #endif
185
186     if (rxi_Listen(socketFd) < 0) {
187         goto error;
188     }
189
190     return socketFd;
191
192   error:
193 #ifdef AFS_NT40_ENV
194     if (socketFd >= 0)
195         closesocket(socketFd);
196 #else
197     if (socketFd >= 0)
198         close(socketFd);
199 #endif
200
201     return OSI_NULLSOCKET;
202 }
203
204 osi_socket
205 rxi_GetUDPSocket(u_short port)
206 {
207     struct sockaddr_storage saddr;
208     struct sockaddr_in *sin = (struct sockaddr_in *) &saddr;
209
210     memset((void *) &saddr, 0, sizeof(saddr));
211
212     sin->sin_family = AF_INET;
213     sin->sin_addr.s_addr = htonl(INADDR_ANY);
214     sin->sin_port = port;
215
216     return rxi_GetHostUDPSocket(&saddr, sizeof(struct sockaddr_in));
217 }
218
219 void
220 osi_Panic(msg, a1, a2, a3) 
221      char *msg; 
222 {
223     (osi_Msg "Fatal Rx error: ");
224     (osi_Msg msg, a1, a2, a3);
225     fflush(stderr);
226     fflush(stdout);
227     afs_abort();
228 }
229
230 /*
231  * osi_AssertFailU() -- used by the osi_Assert() macro.
232  */
233
234 void
235 osi_AssertFailU(const char *expr, const char *file, int line)
236 {
237     osi_Panic("assertion failed: %s, file: %s, line: %d\n", expr,
238               file, line);
239 }
240
241 #if defined(AFS_AIX32_ENV) && !defined(KERNEL)
242 #ifndef osi_Alloc
243 static const char memZero;
244 void *
245 osi_Alloc(afs_int32 x)
246 {
247     /* 
248      * 0-length allocs may return NULL ptr from malloc, so we special-case
249      * things so that NULL returned iff an error occurred 
250      */
251     if (x == 0)
252         return (void *)&memZero;
253     return(malloc(x));
254 }
255
256 void
257 osi_Free(void *x, afs_int32 size)
258 {
259     if (x == &memZero)
260         return;
261     free(x);
262 }
263 #endif
264 #endif /* defined(AFS_AIX32_ENV) && !defined(KERNEL) */
265
266 #define ADDRSPERSITE    16
267
268
269 static afs_uint32 rxi_NetAddrs[ADDRSPERSITE];   /* host order */
270 static int myNetMTUs[ADDRSPERSITE];
271 static int myNetMasks[ADDRSPERSITE];
272 static int myNetFlags[ADDRSPERSITE];
273 static u_int rxi_numNetAddrs;
274 static int Inited = 0;
275
276 #if defined(AFS_NT40_ENV) || defined(AFS_DJGPP_ENV)
277 int
278 rxi_getaddr(void)
279 {
280     /* The IP address list can change so we must query for it */
281     rx_GetIFInfo();
282
283     /* we don't want to use the loopback adapter which is first */
284     /* this is a bad bad hack */
285     if (rxi_numNetAddrs > 1)
286         return htonl(rxi_NetAddrs[1]);  
287     else if (rxi_numNetAddrs > 0)
288         return htonl(rxi_NetAddrs[0]);
289     else
290         return 0;
291 }
292
293 /* 
294 ** return number of addresses 
295 ** and the addresses themselves in the buffer
296 ** maxSize - max number of interfaces to return.
297 */
298 int
299 rx_getAllAddr(afs_int32 * buffer, int maxSize)
300 {
301     int count = 0, offset = 0;
302
303     /* The IP address list can change so we must query for it */
304     rx_GetIFInfo();
305
306     /* we don't want to use the loopback adapter which is first */
307     /* this is a bad bad hack */
308     if ( rxi_numNetAddrs > 1 )
309         offset = 1;
310
311     for (count = 0; offset < rxi_numNetAddrs && maxSize > 0;
312          count++, offset++, maxSize--)
313         buffer[count] = htonl(rxi_NetAddrs[offset]);
314
315     return count;
316 }
317 #endif
318
319 #ifdef AFS_NT40_ENV
320 void
321 rx_GetIFInfo(void)
322 {
323     u_int maxsize;
324     u_int rxsize;
325     int npackets, ncbufs;
326     afs_uint32 i;
327
328     LOCK_IF_INIT;
329     Inited = 1;
330     UNLOCK_IF_INIT;
331
332     LOCK_IF;
333     rxi_numNetAddrs = ADDRSPERSITE;
334     (void)syscfg_GetIFInfo(&rxi_numNetAddrs, rxi_NetAddrs,
335                            myNetMasks, myNetMTUs, myNetFlags);
336
337     for (i = 0; i < rxi_numNetAddrs; i++) {
338         rxsize = rxi_AdjustIfMTU(myNetMTUs[i] - RX_IPUDP_SIZE);
339         maxsize =
340             rxi_nRecvFrags * rxsize + (rxi_nRecvFrags - 1) * UDP_HDR_SIZE;
341         maxsize = rxi_AdjustMaxMTU(rxsize, maxsize);
342         if (rx_maxReceiveSize < maxsize) {
343             rx_maxReceiveSize = MIN(RX_MAX_PACKET_SIZE, maxsize);
344             rx_maxReceiveSize =
345                 MIN(rx_maxReceiveSize, rx_maxReceiveSizeUser);
346         }
347
348     }
349     UNLOCK_IF;
350     ncbufs = (rx_maxJumboRecvSize - RX_FIRSTBUFFERSIZE);
351     if (ncbufs > 0) {
352         ncbufs = ncbufs / RX_CBUFFERSIZE;
353         npackets = rx_initSendWindow - 1;
354         rxi_MorePackets(npackets * (ncbufs + 1));
355     }
356 }
357 #endif
358
359 static afs_uint32
360 fudge_netmask(afs_uint32 addr)
361 {
362     afs_uint32 msk;
363
364     if (IN_CLASSA(addr))
365         msk = IN_CLASSA_NET;
366     else if (IN_CLASSB(addr))
367         msk = IN_CLASSB_NET;
368     else if (IN_CLASSC(addr))
369         msk = IN_CLASSC_NET;
370     else
371         msk = 0;
372
373     return msk;
374 }
375
376
377
378 #if !defined(AFS_AIX_ENV) && !defined(AFS_NT40_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_DJGPP_ENV)
379 int
380 rxi_syscall(a3, a4, a5)
381      afs_uint32 a3, a4;
382      void *a5;
383 {
384     afs_uint32 rcode;
385     void (*old) ();
386
387     old = (void (*)())signal(SIGSYS, SIG_IGN);
388
389 #if defined(AFS_SGI_ENV)
390     rcode = afs_syscall(a3, a4, a5);
391 #else
392     rcode = syscall(AFS_SYSCALL, 28 /* AFSCALL_CALL */ , a3, a4, a5);
393 #endif /* AFS_SGI_ENV */
394
395     signal(SIGSYS, old);
396
397     return rcode;
398 }
399 #endif /* AFS_AIX_ENV */
400
401 #ifndef AFS_NT40_ENV
402 void
403 rx_GetIFInfo(void)
404 {
405     int s;
406     int i, j, len, res;
407 #ifndef AFS_DJGPP_ENV
408     struct ifconf ifc;
409     struct ifreq ifs[ADDRSPERSITE];
410     struct ifreq *ifr;
411 #ifdef  AFS_AIX41_ENV
412     char buf[BUFSIZ], *cp, *cplim;
413 #endif
414     struct sockaddr_in *a;
415 #endif /* AFS_DJGPP_ENV */
416
417     LOCK_IF_INIT;
418     if (Inited) {
419         UNLOCK_IF_INIT;
420         return;
421     }
422     Inited = 1;
423     UNLOCK_IF_INIT;
424     LOCK_IF;
425     rxi_numNetAddrs = 0;
426     memset(rxi_NetAddrs, 0, sizeof(rxi_NetAddrs));
427     memset(myNetFlags, 0, sizeof(myNetFlags));
428     memset(myNetMTUs, 0, sizeof(myNetMTUs));
429     memset(myNetMasks, 0, sizeof(myNetMasks));
430     UNLOCK_IF;
431     s = socket(AF_INET, SOCK_DGRAM, 0);
432     if (s < 0)
433         return;
434
435 #ifndef AFS_DJGPP_ENV
436 #ifdef  AFS_AIX41_ENV
437     ifc.ifc_len = sizeof(buf);
438     ifc.ifc_buf = buf;
439     ifr = ifc.ifc_req;
440 #else
441     ifc.ifc_len = sizeof(ifs);
442     ifc.ifc_buf = (caddr_t) & ifs[0];
443     memset(&ifs[0], 0, sizeof(ifs));
444 #endif
445     res = ioctl(s, SIOCGIFCONF, &ifc);
446     if (res < 0) {
447         /* fputs(stderr, "ioctl error IFCONF\n"); */
448         close(s);
449         return;
450     }
451
452     LOCK_IF;
453 #ifdef  AFS_AIX41_ENV
454 #define size(p) MAX((p).sa_len, sizeof(p))
455     cplim = buf + ifc.ifc_len;  /*skip over if's with big ifr_addr's */
456     for (cp = buf; cp < cplim;
457          cp += sizeof(ifr->ifr_name) + MAX(a->sin_len, sizeof(*a))) {
458         if (rxi_numNetAddrs >= ADDRSPERSITE)
459             break;
460
461         ifr = (struct ifreq *)cp;
462 #else
463     len = ifc.ifc_len / sizeof(struct ifreq);
464     if (len > ADDRSPERSITE)
465         len = ADDRSPERSITE;
466
467     for (i = 0; i < len; ++i) {
468         ifr = &ifs[i];
469         res = ioctl(s, SIOCGIFADDR, ifr);
470 #endif
471         if (res < 0) {
472             /* fputs(stderr, "ioctl error IFADDR\n");
473              * perror(ifr->ifr_name);   */
474             continue;
475         }
476         a = (struct sockaddr_in *)&ifr->ifr_addr;
477         if (a->sin_family != AF_INET)
478             continue;
479         rxi_NetAddrs[rxi_numNetAddrs] = ntohl(a->sin_addr.s_addr);
480         if (rxi_NetAddrs[rxi_numNetAddrs] == 0x7f000001) {
481             /* we don't really care about "localhost" */
482             continue;
483         }
484         for (j = 0; j < rxi_numNetAddrs; j++) {
485             if (rxi_NetAddrs[j] == rxi_NetAddrs[rxi_numNetAddrs])
486                 break;
487         }
488         if (j < rxi_numNetAddrs)
489             continue;
490
491         /* fprintf(stderr, "if %s addr=%x\n", ifr->ifr_name,
492          * rxi_NetAddrs[rxi_numNetAddrs]); */
493
494 #ifdef SIOCGIFFLAGS
495         res = ioctl(s, SIOCGIFFLAGS, ifr);
496         if (res == 0) {
497             myNetFlags[rxi_numNetAddrs] = ifr->ifr_flags;
498 #ifdef IFF_LOOPBACK
499             /* Handle aliased loopbacks as well. */
500             if (ifr->ifr_flags & IFF_LOOPBACK)
501                 continue;
502 #endif
503             /* fprintf(stderr, "if %s flags=%x\n", 
504              * ifr->ifr_name, ifr->ifr_flags); */
505         } else {                /*
506                                  * fputs(stderr, "ioctl error IFFLAGS\n");
507                                  * perror(ifr->ifr_name); */
508         }
509 #endif /* SIOCGIFFLAGS */
510
511 #if !defined(AFS_AIX_ENV)  && !defined(AFS_LINUX20_ENV)
512         /* this won't run on an AIX system w/o a cache manager */
513         rxi_syscallp = rxi_syscall;
514 #endif
515
516         /* If I refer to kernel extensions that aren't loaded on AIX, the 
517          * program refuses to load and run, so I simply can't include the 
518          * following code.  Fortunately, AIX is the one operating system in
519          * which the subsequent ioctl works reliably. */
520         if (rxi_syscallp) {
521             if ((*rxi_syscallp) (20 /*AFSOP_GETMTU */ ,
522                                  htonl(rxi_NetAddrs[rxi_numNetAddrs]),
523                                  &(myNetMTUs[rxi_numNetAddrs]))) {
524                 /* fputs(stderr, "syscall error GETMTU\n");
525                  * perror(ifr->ifr_name); */
526                 myNetMTUs[rxi_numNetAddrs] = 0;
527             }
528             if ((*rxi_syscallp) (42 /*AFSOP_GETMASK */ ,
529                                  htonl(rxi_NetAddrs[rxi_numNetAddrs]),
530                                  &(myNetMasks[rxi_numNetAddrs]))) {
531                 /* fputs(stderr, "syscall error GETMASK\n");
532                  * perror(ifr->ifr_name); */
533                 myNetMasks[rxi_numNetAddrs] = 0;
534             } else
535                 myNetMasks[rxi_numNetAddrs] =
536                     ntohl(myNetMasks[rxi_numNetAddrs]);
537             /* fprintf(stderr, "if %s mask=0x%x\n", 
538              * ifr->ifr_name, myNetMasks[rxi_numNetAddrs]); */
539         }
540
541         if (myNetMTUs[rxi_numNetAddrs] == 0) {
542             myNetMTUs[rxi_numNetAddrs] = OLD_MAX_PACKET_SIZE + RX_IPUDP_SIZE;
543 #ifdef SIOCGIFMTU
544             res = ioctl(s, SIOCGIFMTU, ifr);
545             if ((res == 0) && (ifr->ifr_metric > 128)) {        /* sanity check */
546                 myNetMTUs[rxi_numNetAddrs] = ifr->ifr_metric;
547                 /* fprintf(stderr, "if %s mtu=%d\n", 
548                  * ifr->ifr_name, ifr->ifr_metric); */
549             } else {
550                 /* fputs(stderr, "ioctl error IFMTU\n");
551                  * perror(ifr->ifr_name); */
552             }
553 #endif
554         }
555
556         if (myNetMasks[rxi_numNetAddrs] == 0) {
557             myNetMasks[rxi_numNetAddrs] =
558                 fudge_netmask(rxi_NetAddrs[rxi_numNetAddrs]);
559 #ifdef SIOCGIFNETMASK
560             res = ioctl(s, SIOCGIFNETMASK, ifr);
561             if ((res == 0)) {
562                 a = (struct sockaddr_in *)&ifr->ifr_addr;
563                 myNetMasks[rxi_numNetAddrs] = ntohl(a->sin_addr.s_addr);
564                 /* fprintf(stderr, "if %s subnetmask=0x%x\n", 
565                  * ifr->ifr_name, myNetMasks[rxi_numNetAddrs]); */
566             } else {
567                 /* fputs(stderr, "ioctl error IFMASK\n");
568                  * perror(ifr->ifr_name); */
569             }
570 #endif
571         }
572
573         if (rxi_NetAddrs[rxi_numNetAddrs] != 0x7f000001) {      /* ignore lo0 */
574             int maxsize;
575             maxsize =
576                 rxi_nRecvFrags * (myNetMTUs[rxi_numNetAddrs] - RX_IP_SIZE);
577             maxsize -= UDP_HDR_SIZE;    /* only the first frag has a UDP hdr */
578             if (rx_maxReceiveSize < maxsize)
579                 rx_maxReceiveSize = MIN(RX_MAX_PACKET_SIZE, maxsize);
580             ++rxi_numNetAddrs;
581         }
582     }
583     UNLOCK_IF;
584     close(s);
585
586     /* have to allocate at least enough to allow a single packet to reach its
587      * maximum size, so ReadPacket will work.  Allocate enough for a couple
588      * of packets to do so, for good measure */
589     {
590         int npackets, ncbufs;
591
592         rx_maxJumboRecvSize =
593             RX_HEADER_SIZE + rxi_nDgramPackets * RX_JUMBOBUFFERSIZE +
594             (rxi_nDgramPackets - 1) * RX_JUMBOHEADERSIZE;
595         rx_maxJumboRecvSize = MAX(rx_maxJumboRecvSize, rx_maxReceiveSize);
596         ncbufs = (rx_maxJumboRecvSize - RX_FIRSTBUFFERSIZE);
597         if (ncbufs > 0) {
598             ncbufs = ncbufs / RX_CBUFFERSIZE;
599             npackets = rx_initSendWindow - 1;
600             rxi_MorePackets(npackets * (ncbufs + 1));
601         }
602     }
603 #else /* AFS_DJGPP_ENV */
604     close(s);
605     return;
606 #endif /* AFS_DJGPP_ENV */
607 }
608 #endif /* AFS_NT40_ENV */
609
610 /* Called from rxi_FindPeer, when initializing a clear rx_peer structure,
611  * to get interesting information.
612  * Curiously enough, the rx_peerHashTable_lock currently protects the
613  * Inited variable (and hence rx_GetIFInfo). When the fs suite uses
614  * pthreads, this issue will need to be revisited.
615  */
616
617 void
618 rxi_InitPeerParams(struct rx_peer *pp)
619 {
620     afs_uint32 ppaddr;
621     u_short rxmtu;
622     int ix;
623
624
625
626     LOCK_IF_INIT;
627     if (!Inited) {
628         UNLOCK_IF_INIT;
629         /*
630          * there's a race here since more than one thread could call
631          * rx_GetIFInfo.  The race stops in rx_GetIFInfo.
632          */
633         rx_GetIFInfo();
634     } else {
635         UNLOCK_IF_INIT;
636     }
637
638 #ifdef ADAPT_MTU
639     /* try to second-guess IP, and identify which link is most likely to
640      * be used for traffic to/from this host. */
641     switch (rx_ssfamily(&pp->saddr)) {
642     case AF_INET:
643         ppaddr = ntohl(((struct sockaddr_in * ) &pp->saddr)->sin_addr.s_addr);
644
645         pp->ifMTU = 0;
646         pp->timeout.sec = 2;
647         pp->rateFlag = 2;       /* start timing after two full packets */
648         /* I don't initialize these, because I presume they are bzero'd... 
649         * pp->burstSize pp->burst pp->burstWait.sec pp->burstWait.usec
650         * pp->timeout.usec */
651
652         LOCK_IF;
653         for (ix = 0; ix < rxi_numNetAddrs; ++ix) {
654             if ((rxi_NetAddrs[ix] & myNetMasks[ix]) ==
655                 (ppaddr & myNetMasks[ix])) {
656 #ifdef IFF_POINTOPOINT
657                 if (myNetFlags[ix] & IFF_POINTOPOINT)
658                     pp->timeout.sec = 4;
659 #endif /* IFF_POINTOPOINT */
660                 rxmtu = myNetMTUs[ix] - RX_IPUDP_SIZE;
661                 if (rxmtu < RX_MIN_PACKET_SIZE)
662                     rxmtu = RX_MIN_PACKET_SIZE;
663                 if (pp->ifMTU < rxmtu)
664                     pp->ifMTU = MIN(rx_MyMaxSendSize, rxmtu);
665             }
666         }
667         UNLOCK_IF;
668         if (!pp->ifMTU) {               /* not local */
669             pp->timeout.sec = 3;
670             pp->ifMTU = MIN(rx_MyMaxSendSize, RX_REMOTE_PACKET_SIZE);
671         }
672         break;
673 #ifdef AF_INET6
674     case AF_INET6:
675 #endif 
676     default:
677         pp->rateFlag = 2;       /* start timing after two full packets */
678         pp->timeout.sec = 2;
679         pp->ifMTU = MIN(rx_MyMaxSendSize, OLD_MAX_PACKET_SIZE);
680         break;
681     }
682 #else /* ADAPT_MTU */
683     pp->rateFlag = 2;           /* start timing after two full packets */
684     pp->timeout.sec = 2;
685     pp->ifMTU = MIN(rx_MyMaxSendSize, OLD_MAX_PACKET_SIZE);
686 #endif /* ADAPT_MTU */
687     pp->ifMTU = rxi_AdjustIfMTU(pp->ifMTU);
688     pp->maxMTU = OLD_MAX_PACKET_SIZE;   /* for compatibility with old guys */
689     pp->natMTU = MIN((int)pp->ifMTU, OLD_MAX_PACKET_SIZE);
690     pp->maxDgramPackets =
691         MIN(rxi_nDgramPackets,
692             rxi_AdjustDgramPackets(RX_MAX_FRAGS, pp->ifMTU));
693     pp->ifDgramPackets =
694         MIN(rxi_nDgramPackets,
695             rxi_AdjustDgramPackets(RX_MAX_FRAGS, pp->ifMTU));
696     pp->maxDgramPackets = 1;
697     /* Initialize slow start parameters */
698     pp->MTU = MIN(pp->natMTU, pp->maxMTU);
699     pp->cwind = 1;
700     pp->nDgramPackets = 1;
701     pp->congestSeq = 0;
702 }
703
704 /* Don't expose jumobgram internals. */
705 void
706 rx_SetNoJumbo(void)
707 {
708     rx_maxReceiveSize = OLD_MAX_PACKET_SIZE;
709     rxi_nSendFrags = rxi_nRecvFrags = 1;
710 }
711
712 /* Override max MTU.  If rx_SetNoJumbo is called, it must be 
713    called before calling rx_SetMaxMTU since SetNoJumbo clobbers rx_maxReceiveSize */
714 void
715 rx_SetMaxMTU(int mtu)
716 {
717     rx_MyMaxSendSize = rx_maxReceiveSizeUser = rx_maxReceiveSize = mtu;
718 }