openbsd-20021119
[openafs.git] / src / rx / rx_kcommon.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  * rx_kcommon.c - Common kernel RX code for all system types.
12  */
13
14 #include <afsconfig.h>
15 #include "afs/param.h"
16
17 RCSID("$Header$");
18
19 #include "rx/rx_kcommon.h"
20
21 #ifdef AFS_HPUX110_ENV
22 #include "h/tihdr.h"
23 #include <xti.h>
24 #endif
25 #include "afsint.h"
26
27 #ifdef AFS_DARWIN60_ENV
28 struct ifnet *rxi_FindIfnet(afs_uint32 addr, struct ifaddr **pifad);
29 #else
30 struct ifnet *rxi_FindIfnet(afs_uint32 addr, struct in_ifaddr **pifad);
31 #endif
32
33 #ifndef RXK_LISTENER_ENV
34 int (*rxk_PacketArrivalProc)(register struct rx_packet *ahandle,
35         register struct sockaddr_in *afrom, char *arock,
36         afs_int32 asize); /* set to packet allocation procedure */
37 int (*rxk_GetPacketProc)(char **ahandle, int asize);
38 #endif
39
40 extern  struct interfaceAddr afs_cb_interface;
41
42 rxk_ports_t rxk_ports;
43 rxk_portRocks_t rxk_portRocks;
44
45 int rxk_initDone=0;
46
47 /* add a port to the monitored list, port # is in network order */
48 static int rxk_AddPort(u_short aport, char * arock)
49 {
50     int i;
51     unsigned short *tsp, ts;
52     int zslot;
53
54     zslot = -1;     /* look for an empty slot simultaneously */
55     for(i=0,tsp=rxk_ports;i<MAXRXPORTS;i++,tsp++) {
56         if (((ts = *tsp) == 0) && (zslot == -1))
57             zslot = i;
58         if (ts == aport) {
59             return 0;
60         }
61     }
62     /* otherwise allocate a new port slot */
63     if (zslot < 0) return E2BIG; /* all full */
64     rxk_ports[zslot] = aport;
65     rxk_portRocks[zslot] = arock;
66     return 0;
67 }
68
69 /* remove as port from the monitored list, port # is in network order */
70 int rxk_DelPort(u_short aport)
71 {
72     register int i;
73     register unsigned short *tsp;
74
75     for(i=0,tsp=rxk_ports;i<MAXRXPORTS;i++,tsp++) {
76         if (*tsp == aport) {
77             /* found it, adjust ref count and free the port reference if all gone */
78             *tsp = 0;
79             return 0;
80         }
81     }
82     /* otherwise port not found */
83     return ENOENT;
84 }
85
86 void rxk_shutdownPorts(void)
87 {
88     int i;
89     for (i=0; i<MAXRXPORTS;i++) {
90         if (rxk_ports[i]) {
91             rxk_ports[i] = 0;
92 #if ! defined(AFS_SUN5_ENV) && ! defined(UKERNEL) && ! defined(RXK_LISTENER_ENV)
93             soclose((struct socket *)rxk_portRocks[i]);
94 #endif
95             rxk_portRocks[i] = NULL;
96         }
97     }
98 }
99
100 osi_socket rxi_GetUDPSocket(u_short port)
101 {
102     struct osi_socket *sockp;
103     sockp = (struct osi_socket *) rxk_NewSocket(port);
104     if (sockp == (struct osi_socket *) 0) return OSI_NULLSOCKET;
105     rxk_AddPort(port, (char *) sockp);
106     return (osi_socket)sockp;
107 }
108
109
110 void osi_Panic(msg, a1, a2, a3)
111 char *msg;
112 {
113     if (!msg)
114         msg = "Unknown AFS panic";
115
116     printf(msg, a1, a2, a3);
117 #ifdef AFS_LINUX20_ENV
118     *((char*)0xffffffff) = 42;
119 #else
120     panic(msg);
121 #endif
122 }
123
124 /*
125  * osi_utoa() - write the NUL-terminated ASCII decimal form of the given
126  * unsigned long value into the given buffer.  Returns 0 on success,
127  * and a value less than 0 on failure.  The contents of the buffer is
128  * defined only on success.
129  */
130
131 int osi_utoa(char *buf, size_t len, unsigned long val)
132 {
133         long k; /* index of first byte of string value */
134
135         /* we definitely need room for at least one digit and NUL */
136
137         if (len < 2) {
138                 return -1;
139         }
140
141         /* compute the string form from the high end of the buffer */
142
143         buf[len - 1] = '\0';
144         for (k = len - 2; k >= 0; k--) {
145                 buf[k] = val % 10 + '0';
146                 val /= 10;
147
148                 if (val == 0)
149                         break;
150         }
151
152         /* did we finish converting val to string form? */
153
154         if (val != 0) {
155                 return -2;
156         }
157
158         /* this should never happen */
159
160         if (k < 0) {
161                 return -3;
162         }
163
164         /* this should never happen */
165
166         if (k >= len) {
167                 return -4;
168         }
169
170         /* if necessary, relocate string to beginning of buf[] */
171
172         if (k > 0) {
173
174                 /*
175                  * We need to achieve the effect of calling
176                  *
177                  * memmove(buf, &buf[k], len - k);
178                  *
179                  * However, since memmove() is not available in all
180                  * kernels, we explicitly do an appropriate copy.
181                  */
182
183                 char *dst = buf;
184                 char *src = buf+k;
185
186                 while((*dst++ = *src++) != '\0')
187                         continue;
188         }
189
190         return 0;
191 }
192
193 /*
194  * osi_AssertFailK() -- used by the osi_Assert() macro.
195  *
196  * It essentially does
197  *
198  * osi_Panic("assertion failed: %s, file: %s, line: %d", expr, file, line);
199  *
200  * Since the kernel version of osi_Panic() only passes its first
201  * argument to the native panic(), we construct a single string and hand
202  * that to osi_Panic().
203  */
204 void osi_AssertFailK(const char *expr, const char *file, int line)
205 {
206         static const char msg0[] = "assertion failed: ";
207         static const char msg1[] = ", file: ";
208         static const char msg2[] = ", line: ";
209         static const char msg3[] = "\n";
210
211         /*
212          * These buffers add up to 1K, which is a pleasantly nice round
213          * value, but probably not vital.
214          */
215         char buf[1008];
216         char linebuf[16];
217
218         /* check line number conversion */
219
220         if (osi_utoa(linebuf, sizeof linebuf, line) < 0) {
221                 osi_Panic("osi_AssertFailK: error in osi_utoa()\n");
222         }
223
224         /* okay, panic */
225
226 #define ADDBUF(BUF, STR)                                        \
227         if (strlen(BUF) + strlen((char *)(STR)) + 1 <= sizeof BUF) {    \
228                 strcat(BUF, (char *)(STR));                             \
229         }
230
231         buf[0] = '\0';
232         ADDBUF(buf, msg0);
233         ADDBUF(buf, expr);
234         ADDBUF(buf, msg1);
235         ADDBUF(buf, file);
236         ADDBUF(buf, msg2);
237         ADDBUF(buf, linebuf);
238         ADDBUF(buf, msg3);
239
240 #undef ADDBUF
241
242         osi_Panic(buf);
243 }
244
245 #ifndef UKERNEL
246 /* This is the server process request loop. Kernel server
247  * processes never become listener threads */
248 void rx_ServerProc(void)
249 {
250     int threadID;
251
252     rxi_MorePackets(rx_maxReceiveWindow+2); /* alloc more packets */
253     rxi_dataQuota += rx_initSendWindow; /* Reserve some pkts for hard times */
254     /* threadID is used for making decisions in GetCall.  Get it by bumping
255      * number of threads handling incoming calls */
256     threadID = rxi_availProcs++;
257
258 #ifdef RX_ENABLE_LOCKS
259     AFS_GUNLOCK();
260 #endif /* RX_ENABLE_LOCKS */
261     rxi_ServerProc(threadID, NULL, NULL);
262 #ifdef RX_ENABLE_LOCKS
263     AFS_GLOCK();
264 #endif /* RX_ENABLE_LOCKS */
265 }
266 #endif /* !UKERNEL */
267
268 #ifndef RXK_LISTENER_ENV
269 /* asize includes the Rx header */
270 static int MyPacketProc(char **ahandle, int asize)
271 {
272     register struct rx_packet *tp;
273
274     /* If this is larger than we expected, increase rx_maxReceiveDataSize */
275     /* If we can't scrounge enough cbufs, then we have to drop the packet,
276      * but we should set a flag so we magic up some more at our leisure.
277      */
278
279     if ((asize >= 0) && (asize <= RX_MAX_PACKET_SIZE)) {
280       tp = rxi_AllocPacket(RX_PACKET_CLASS_RECEIVE);
281       if (tp && (tp->length + RX_HEADER_SIZE) < asize ) {
282         if (0 < rxi_AllocDataBuf(tp, asize - (tp->length + RX_HEADER_SIZE),
283                                  RX_PACKET_CLASS_RECV_CBUF)) {
284           rxi_FreePacket(tp);
285           tp = NULL;
286           MUTEX_ENTER(&rx_stats_mutex);
287           rx_stats.noPacketBuffersOnRead++;
288           MUTEX_EXIT(&rx_stats_mutex);
289         }
290       }
291     } else {
292       /*
293        * XXX if packet is too long for our buffer,
294        * should do this at a higher layer and let other
295        * end know we're losing.
296        */
297       MUTEX_ENTER(&rx_stats_mutex);
298       rx_stats.bogusPacketOnRead++;
299       MUTEX_EXIT(&rx_stats_mutex);
300       /* I DON"T LIKE THIS PRINTF -- PRINTFS MAKE THINGS VERY VERY SLOOWWW */
301       printf("rx: packet dropped: bad ulen=%d\n", asize);
302       tp = NULL;
303     }
304
305     if (!tp) return -1;
306     /* otherwise we have a packet, set appropriate values */
307     *ahandle = (char *) tp;
308     return 0;
309 }
310
311 static int MyArrivalProc(register struct rx_packet *ahandle, 
312         register struct sockaddr_in *afrom, char *arock, 
313         afs_int32 asize)
314 {
315     /* handle basic rx packet */
316     ahandle->length = asize - RX_HEADER_SIZE;
317     rxi_DecodePacketHeader(ahandle);
318     ahandle = rxi_ReceivePacket(ahandle, (struct socket *) arock,
319                                 afrom->sin_addr.s_addr, afrom->sin_port,
320                                 NULL, NULL);
321
322     /* free the packet if it has been returned */
323     if (ahandle) rxi_FreePacket(ahandle);
324     return 0;
325 }
326 #endif /* !RXK_LISTENER_ENV */
327
328 void rxi_StartListener(void)
329 {
330     /* if kernel, give name of appropriate procedures */
331 #ifndef RXK_LISTENER_ENV
332     rxk_GetPacketProc = MyPacketProc;
333     rxk_PacketArrivalProc = MyArrivalProc;
334     rxk_init();
335 #endif
336 }
337
338 /* Called from rxi_FindPeer, when initializing a clear rx_peer structure,
339   to get interesting information. */
340 void rxi_InitPeerParams(register struct rx_peer *pp)
341 {
342 #ifdef  ADAPT_MTU
343     u_short rxmtu;
344     afs_int32 i, mtu;
345
346 #ifndef AFS_SUN5_ENV
347 #ifdef AFS_USERSPACE_IP_ADDR    
348     i = rxi_Findcbi(pp->host);
349     if (i == -1) {
350        pp->timeout.sec = 3;
351        /* pp->timeout.usec = 0; */
352        pp->ifMTU = RX_REMOTE_PACKET_SIZE;
353     } else {
354        pp->timeout.sec = 2;
355        /* pp->timeout.usec = 0; */
356        pp->ifMTU = MIN(RX_MAX_PACKET_SIZE, rx_MyMaxSendSize);
357     }
358     if (i != -1) {
359         mtu = ntohl(afs_cb_interface.mtu[i]);
360         /* Diminish the packet size to one based on the MTU given by
361          * the interface. */
362         if (mtu > (RX_IPUDP_SIZE + RX_HEADER_SIZE)) {
363             rxmtu = mtu - RX_IPUDP_SIZE;
364             if (rxmtu < pp->ifMTU) pp->ifMTU = rxmtu;
365         }
366     }
367     else {   /* couldn't find the interface, so assume the worst */
368       pp->ifMTU = RX_REMOTE_PACKET_SIZE;
369     }
370 #else /* AFS_USERSPACE_IP_ADDR */
371 #ifdef AFS_DARWIN60_ENV
372     struct ifaddr *ifad = (struct ifaddr *) 0;
373 #else
374     struct in_ifaddr *ifad = (struct in_ifaddr *) 0;
375 #endif
376     struct ifnet *ifn;
377
378     /* At some time we need to iterate through rxi_FindIfnet() to find the
379      * global maximum.
380      */
381     ifn = rxi_FindIfnet(pp->host, &ifad);
382     if (ifn == NULL) {  /* not local */
383         pp->timeout.sec = 3;
384         /* pp->timeout.usec = 0; */
385         pp->ifMTU = RX_REMOTE_PACKET_SIZE;
386     } else {
387         pp->timeout.sec = 2;
388         /* pp->timeout.usec = 0; */
389         pp->ifMTU = MIN(RX_MAX_PACKET_SIZE, rx_MyMaxSendSize);
390     }
391     if (ifn) {
392 #ifdef IFF_POINTOPOINT
393         if (ifn->if_flags & IFF_POINTOPOINT) {
394             /* wish we knew the bit rate and the chunk size, sigh. */
395             pp->timeout.sec = 4;
396             pp->ifMTU = RX_PP_PACKET_SIZE;
397         }
398 #endif /* IFF_POINTOPOINT */
399         /* Diminish the packet size to one based on the MTU given by
400          * the interface. */
401         if (ifn->if_mtu > (RX_IPUDP_SIZE + RX_HEADER_SIZE)) {
402             rxmtu = ifn->if_mtu - RX_IPUDP_SIZE;
403             if (rxmtu < pp->ifMTU) pp->ifMTU = rxmtu;
404         }
405     }
406     else {   /* couldn't find the interface, so assume the worst */
407       pp->ifMTU = RX_REMOTE_PACKET_SIZE;
408     }
409 #endif/* else AFS_USERSPACE_IP_ADDR */
410 #else /* AFS_SUN5_ENV */
411     mtu = rxi_FindIfMTU(pp->host);
412
413     if (mtu <= 0) {
414         pp->timeout.sec = 3;
415         /* pp->timeout.usec = 0; */
416         pp->ifMTU = RX_REMOTE_PACKET_SIZE;
417     } else {
418         pp->timeout.sec = 2;
419         /* pp->timeout.usec = 0; */
420         pp->ifMTU = MIN(RX_MAX_PACKET_SIZE, rx_MyMaxSendSize);
421     }
422
423     if (mtu > 0) {
424         /* Diminish the packet size to one based on the MTU given by
425          * the interface. */
426         if (mtu > (RX_IPUDP_SIZE + RX_HEADER_SIZE)) {
427             rxmtu = mtu - RX_IPUDP_SIZE;
428             if (rxmtu < pp->ifMTU) pp->ifMTU = rxmtu;
429         }
430     } else {   /* couldn't find the interface, so assume the worst */
431         pp->ifMTU = RX_REMOTE_PACKET_SIZE;
432     }
433 #endif /* AFS_SUN5_ENV */
434 #else /* ADAPT_MTU */
435     pp->rateFlag = 2;   /* start timing after two full packets */
436     pp->timeout.sec = 2;
437     pp->ifMTU = OLD_MAX_PACKET_SIZE;
438 #endif /* else ADAPT_MTU */
439     pp->ifMTU = rxi_AdjustIfMTU(pp->ifMTU);
440     pp->maxMTU = OLD_MAX_PACKET_SIZE;  /* for compatibility with old guys */
441     pp->natMTU = MIN(pp->ifMTU, OLD_MAX_PACKET_SIZE); 
442     pp->ifDgramPackets = MIN(rxi_nDgramPackets,
443                              rxi_AdjustDgramPackets(RX_MAX_FRAGS, pp->ifMTU));
444     pp->maxDgramPackets = 1;
445
446     /* Initialize slow start parameters */
447     pp->MTU = MIN(pp->natMTU, pp->maxMTU);
448     pp->cwind = 1;
449     pp->nDgramPackets = 1;
450     pp->congestSeq = 0;
451 }
452
453
454 /* The following code is common to several system types, but not all. The
455  * separate ones are found in the system specific subdirectories.
456  */
457
458
459 #if ! defined(AFS_AIX_ENV) && ! defined(AFS_SUN5_ENV) && ! defined(UKERNEL) && ! defined(AFS_LINUX20_ENV) && !defined (AFS_DARWIN_ENV) && !defined (AFS_XBSD_ENV)
460 /* Routine called during the afsd "-shutdown" process to put things back to
461  * the initial state.
462  */
463 static struct protosw parent_proto;     /* udp proto switch */
464
465 void shutdown_rxkernel(void)
466 {
467     register struct protosw *tpro, *last;
468     last = inetdomain.dom_protoswNPROTOSW;
469     for (tpro = inetdomain.dom_protosw; tpro < last; tpro++)
470         if (tpro->pr_protocol == IPPROTO_UDP) {
471             /* restore original udp protocol switch */
472             memcpy((void *)tpro, (void *)&parent_proto, sizeof(parent_proto));
473             memset((void *)&parent_proto, 0, sizeof(parent_proto));
474             rxk_initDone = 0;
475             rxk_shutdownPorts();
476             return;
477         }    
478     printf("shutdown_rxkernel: no udp proto");
479 }
480 #endif /* !AIX && !SUN && !NCR  && !UKERNEL */
481
482 #if !defined(AFS_SUN5_ENV) && !defined(AFS_SGI62_ENV)
483 /* Determine what the network interfaces are for this machine. */
484
485 #define ADDRSPERSITE 16
486 static afs_uint32 myNetAddrs[ADDRSPERSITE];
487 static int myNetMTUs[ADDRSPERSITE];
488 static int numMyNetAddrs = 0;
489
490 #ifdef AFS_USERSPACE_IP_ADDR    
491 int rxi_GetcbiInfo(void)
492 {
493    int     i, j, different = 0;
494    int     rxmtu, maxmtu;
495    afs_uint32 ifinaddr;
496    afs_uint32 addrs[ADDRSPERSITE];
497    int     mtus[ADDRSPERSITE];
498
499    memset((void *)addrs, 0, sizeof(addrs));
500    memset((void *)mtus, 0, sizeof(mtus));
501
502    for (i=0; i<afs_cb_interface.numberOfInterfaces; i++) {
503       rxmtu    = (ntohl(afs_cb_interface.mtu[i]) - RX_IPUDP_SIZE);
504       ifinaddr = ntohl(afs_cb_interface.addr_in[i]);
505       if (myNetAddrs[i] != ifinaddr) different++;
506
507       mtus[i]    = rxmtu;
508       rxmtu      = rxi_AdjustIfMTU(rxmtu);
509       maxmtu     = rxmtu * rxi_nRecvFrags + ((rxi_nRecvFrags-1) * UDP_HDR_SIZE);
510       maxmtu     = rxi_AdjustMaxMTU(rxmtu, maxmtu);
511       addrs[i++] = ifinaddr;
512       if ( ( ifinaddr != 0x7f000001 ) && (maxmtu > rx_maxReceiveSize) ) {
513          rx_maxReceiveSize = MIN( RX_MAX_PACKET_SIZE, maxmtu);
514          rx_maxReceiveSize = MIN( rx_maxReceiveSize, rx_maxReceiveSizeUser);
515       }
516    }
517
518    rx_maxJumboRecvSize = RX_HEADER_SIZE +
519                          ( rxi_nDgramPackets    * RX_JUMBOBUFFERSIZE) +
520                          ((rxi_nDgramPackets-1) * RX_JUMBOHEADERSIZE);
521    rx_maxJumboRecvSize = MAX(rx_maxJumboRecvSize, rx_maxReceiveSize);
522
523    if (different) {
524       for (j=0; j<i; j++) {
525          myNetMTUs[j]  = mtus[j];
526          myNetAddrs[j] = addrs[j];
527       }
528    }
529    return different;
530 }
531
532
533 /* Returns the afs_cb_interface inxex which best matches address.
534  * If none is found, we return -1.
535  */
536 afs_int32 rxi_Findcbi(afs_uint32 addr)
537 {
538    int j;
539    afs_uint32 myAddr, thisAddr, netMask, subnetMask;
540    afs_int32 rvalue = -1;
541    int match_value = 0;
542
543   if (numMyNetAddrs == 0)
544     (void) rxi_GetcbiInfo();
545
546    myAddr = ntohl(addr);
547
548    if      ( IN_CLASSA(myAddr) ) netMask = IN_CLASSA_NET;
549    else if ( IN_CLASSB(myAddr) ) netMask = IN_CLASSB_NET;
550    else if ( IN_CLASSC(myAddr) ) netMask = IN_CLASSC_NET;
551    else                          netMask = 0;
552
553    for (j=0; j<afs_cb_interface.numberOfInterfaces; j++) {
554       thisAddr   = ntohl(afs_cb_interface.addr_in[j]);
555       subnetMask = ntohl(afs_cb_interface.subnetmask[j]);
556       if ((myAddr & netMask) == (thisAddr & netMask)) {
557          if ((myAddr & subnetMask) == (thisAddr & subnetMask)) {
558             if (myAddr == thisAddr) {
559                match_value = 4;
560                rvalue = j;
561                break;
562             }
563             if (match_value < 3) {
564                match_value = 3;
565                rvalue = j;
566             }
567          } else {
568             if (match_value < 2) {
569                match_value = 2;
570                rvalue = j;
571             }
572          }
573       }
574    }
575
576    return(rvalue);
577 }
578
579 #else /* AFS_USERSPACE_IP_ADDR */
580
581 #if !defined(AFS_AIX41_ENV) && !defined(AFS_DUX40_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_XBSD_ENV)
582 #define IFADDR2SA(f) (&((f)->ifa_addr))
583 #else /* AFS_AIX41_ENV */
584 #define IFADDR2SA(f) ((f)->ifa_addr)
585 #endif
586
587 int rxi_GetIFInfo(void)
588 {
589     int i = 0;
590     int different = 0;
591
592     register struct ifnet *ifn;
593     register int rxmtu, maxmtu;
594     afs_uint32 addrs[ADDRSPERSITE];
595     int mtus[ADDRSPERSITE];
596     struct ifaddr *ifad;  /* ifnet points to a if_addrlist of ifaddrs */
597     afs_uint32 ifinaddr;
598
599     memset(addrs, 0, sizeof(addrs));
600     memset(mtus, 0, sizeof(mtus));
601
602 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
603     TAILQ_FOREACH(ifn, &ifnet, if_link) {
604         if (i >= ADDRSPERSITE) break;
605 #elif defined(AFS_OBSD_ENV)
606     for (ifn = ifnet.tqh_first; i < ADDRSPERSITE && ifn != NULL; ifn = ifn->if_list.tqe_next) {
607 #else
608     for (ifn = ifnet; ifn != NULL && i < ADDRSPERSITE; ifn = ifn->if_next) {
609 #endif
610         rxmtu = (ifn->if_mtu - RX_IPUDP_SIZE);
611 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
612         TAILQ_FOREACH(ifad, &ifn->if_addrhead, ifa_link) {
613             if (i >= ADDRSPERSITE) break;
614 #elif defined(AFS_OBSD_ENV)
615         for (ifad = ifn->if_addrlist.tqh_first; ifad != NULL && i < ADDRSPERSITE;
616              ifad = ifad->ifa_list.tqe_next) {
617 #else
618         for (ifad = ifn->if_addrlist; ifad != NULL && i < ADDRSPERSITE;
619              ifad = ifad->ifa_next) {
620 #endif
621             if (IFADDR2SA(ifad)->sa_family == AF_INET) {
622                 ifinaddr = ntohl(((struct sockaddr_in *) IFADDR2SA(ifad))->sin_addr.s_addr);
623                 if (myNetAddrs[i] != ifinaddr) { 
624                     different++;
625                 }
626                 mtus[i] = rxmtu;
627                 rxmtu = rxi_AdjustIfMTU(rxmtu);
628                 maxmtu = rxmtu * rxi_nRecvFrags + ((rxi_nRecvFrags-1) * UDP_HDR_SIZE);
629                 maxmtu = rxi_AdjustMaxMTU(rxmtu, maxmtu);
630                 addrs[i++] = ifinaddr;
631                 if ( ( ifinaddr != 0x7f000001 ) &&
632                     (maxmtu > rx_maxReceiveSize) ) {
633                     rx_maxReceiveSize = MIN( RX_MAX_PACKET_SIZE, maxmtu);
634                     rx_maxReceiveSize = MIN( rx_maxReceiveSize, rx_maxReceiveSizeUser);
635                 }
636             }
637         }
638     }
639
640     rx_maxJumboRecvSize = RX_HEADER_SIZE
641                           + rxi_nDgramPackets * RX_JUMBOBUFFERSIZE
642                           + (rxi_nDgramPackets-1) * RX_JUMBOHEADERSIZE;
643     rx_maxJumboRecvSize = MAX(rx_maxJumboRecvSize, rx_maxReceiveSize);
644
645     if (different) {
646         int j;
647         for (j=0; j< i; j++) {
648             myNetMTUs[j] = mtus[j];
649             myNetAddrs[j] = addrs[j];
650         }
651     }
652     return different;
653 }
654 #ifdef AFS_DARWIN60_ENV
655 /* Returns ifnet which best matches address */
656 struct ifnet *
657 rxi_FindIfnet(addr, pifad) 
658      afs_uint32 addr;
659      struct ifaddr **pifad;
660 {
661   struct sockaddr_in s;
662
663   if (numMyNetAddrs == 0)
664     (void) rxi_GetIFInfo();
665
666   s.sin_family=AF_INET;
667   s.sin_addr.s_addr=addr;
668   *pifad=ifa_ifwithnet((struct sockaddr *)&s);
669  done:
670   return (*pifad ?  (*pifad)->ifa_ifp : NULL );
671 }
672 #else
673 /* Returns ifnet which best matches address */
674 struct ifnet *rxi_FindIfnet(afs_uint32 addr, struct in_ifaddr **pifad) 
675 {
676     afs_uint32 ppaddr;
677     int match_value = 0;
678 #ifndef AFS_OBSD_ENV
679     extern struct in_ifaddr *in_ifaddr;
680 #endif
681     struct in_ifaddr *ifa;
682     struct sockaddr_in *sin;
683   
684     if (numMyNetAddrs == 0)
685         (void) rxi_GetIFInfo();
686
687 #ifdef AFS_OBSD_ENV
688     ppaddr = addr;
689 #else
690     ppaddr = ntohl(addr);
691 #endif
692
693     /* if we're given an address, skip everything until we find it */
694     if (!*pifad)
695 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
696         *pifad = TAILQ_FIRST(&in_ifaddrhead);
697 #elif defined(AFS_OBSD_ENV)
698         *pifad = in_ifaddr.tqh_first;
699 #else
700         *pifad = in_ifaddr;
701 #endif
702     else {
703         if (((ppaddr & (*pifad)->ia_subnetmask) == (*pifad)->ia_subnet))
704             match_value = 2;    /* don't find matching nets, just subnets */
705 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
706         *pifad = TAILQ_NEXT(*pifad, ia_link);
707 #elif defined(AFS_OBSD_ENV)
708         *pifad = (*pifad)->ia_list.tqe_next;
709 #else   
710         *pifad = (*pifad)->ia_next;
711 #endif
712     }
713     
714 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
715     for (ifa = *pifad; ifa; ifa = TAILQ_NEXT(ifa, ia_link) ) {
716 #elif defined(AFS_OBSD_ENV)
717     for (ifa = *pifad; ifa; ifa = ifa->ia_list.tqe_next) {
718 #else   
719     for (ifa = *pifad; ifa; ifa = ifa->ia_next ) {
720 #endif
721         if ((ppaddr & ifa->ia_netmask) == ifa->ia_net) {
722             if ((ppaddr & ifa->ia_subnetmask) == ifa->ia_subnet) {
723                 sin=IA_SIN(ifa);
724                 if ( sin->sin_addr.s_addr == ppaddr) { /* ie, ME!!!  */
725                     match_value = 4;
726                     *pifad = ifa;
727                     goto done;
728                 }
729                 if (match_value < 3) {
730                     *pifad = ifa;
731                     match_value = 3;
732                 }
733             }
734             else {
735                 if (match_value < 2) {
736                     *pifad = ifa;
737                     match_value = 2;
738                 }
739             }
740         } /* if net matches */
741     } /* for all in_ifaddrs */
742
743  done:
744     return (*pifad ?  (*pifad)->ia_ifp : NULL );
745 }
746 #endif
747 #endif /* else AFS_USERSPACE_IP_ADDR */
748 #endif /* !SUN5 && !SGI62 */
749
750
751 /* rxk_NewSocket, rxk_FreeSocket and osi_NetSend are from the now defunct
752  * afs_osinet.c. One could argue that rxi_NewSocket could go into the
753  * system specific subdirectories for all systems. But for the moment,
754  * most of it is simple to follow common code.
755  */
756 #if !defined(UKERNEL)
757 #if !defined(AFS_SUN5_ENV) && !defined(AFS_LINUX20_ENV)
758 /* rxk_NewSocket creates a new socket on the specified port. The port is
759  * in network byte order.
760  */
761 struct osi_socket *rxk_NewSocket(short aport)
762 {
763     register afs_int32 code;
764     struct socket *newSocket;
765     struct mbuf *nam;
766     struct sockaddr_in myaddr;
767 #ifdef AFS_HPUX110_ENV
768     /* prototype copied from kernel source file streams/str_proto.h */
769     extern MBLKP allocb_wait(int, int);
770     MBLKP bindnam;
771     int addrsize = sizeof(struct sockaddr_in);
772 #endif
773 #ifdef AFS_SGI65_ENV
774     bhv_desc_t bhv;
775 #endif
776
777     AFS_STATCNT(osi_NewSocket);
778 #if (defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)) && defined(KERNEL_FUNNEL)
779     thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
780 #endif
781 #if     defined(AFS_HPUX102_ENV)
782 #if     defined(AFS_HPUX110_ENV)
783     /* blocking socket */
784     code = socreate(AF_INET, &newSocket, SOCK_DGRAM, 0, 0);
785 #else      /* AFS_HPUX110_ENV */
786     code = socreate(AF_INET, &newSocket, SOCK_DGRAM, 0, SS_NOWAIT);
787 #endif     /* else AFS_HPUX110_ENV */
788 #elif defined(AFS_SGI65_ENV) || defined(AFS_OBSD_ENV)
789     code = socreate(AF_INET, &newSocket, SOCK_DGRAM, IPPROTO_UDP);
790 #elif defined(AFS_FBSD_ENV)
791     code = socreate(AF_INET, &newSocket, SOCK_DGRAM, IPPROTO_UDP, curproc);
792 #else
793     code = socreate(AF_INET, &newSocket, SOCK_DGRAM, 0);
794 #endif /* AFS_HPUX102_ENV */
795     if (code) goto bad;
796
797     myaddr.sin_family = AF_INET;
798     myaddr.sin_port = aport;
799     myaddr.sin_addr.s_addr = 0;
800 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
801     myaddr.sin_len = sizeof(myaddr);
802 #endif
803
804 #ifdef AFS_HPUX110_ENV
805     bindnam = allocb_wait((addrsize+SO_MSGOFFSET+1), BPRI_MED);
806     if (!bindnam) {
807        setuerror(ENOBUFS);
808        goto bad;
809     }
810     memcpy((caddr_t)bindnam->b_rptr+SO_MSGOFFSET, (caddr_t)&myaddr, addrsize);
811     bindnam->b_wptr = bindnam->b_rptr + (addrsize+SO_MSGOFFSET+1);
812
813     code = sobind(newSocket, bindnam, addrsize);
814     if (code) {
815        soclose(newSocket);
816        m_freem(nam);
817        goto bad;
818     }
819
820     freeb(bindnam);
821 #else /* AFS_HPUX110_ENV */
822     code = soreserve(newSocket, 50000, 50000);
823     if (code) {
824         code = soreserve(newSocket, 32766, 32766);
825         if (code)
826             osi_Panic("osi_NewSocket: last attempt to reserve 32K failed!\n");
827     }
828 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
829 #if defined(AFS_FBSD_ENV)
830     code = sobind(newSocket, (struct sockaddr *) &myaddr, curproc);
831 #else
832     code = sobind(newSocket, (struct sockaddr *) &myaddr);
833 #endif
834     if (code) {
835         printf("sobind fails (%d)\n", (int) code);
836         soclose(newSocket);
837         goto bad;
838     }
839 #else /* defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV) */
840 #ifdef  AFS_OSF_ENV
841     nam = m_getclr(M_WAIT, MT_SONAME);
842 #else   /* AFS_OSF_ENV */
843     nam = m_get(M_WAIT, MT_SONAME);
844 #endif
845     if (nam == NULL) {
846 #if defined(KERNEL_HAVE_UERROR)
847         setuerror(ENOBUFS);
848 #endif
849         goto bad;
850     }
851     nam->m_len = sizeof(myaddr);
852     memcpy(mtod(nam, caddr_t), &myaddr, sizeof(myaddr));
853 #ifdef AFS_SGI65_ENV
854     BHV_PDATA(&bhv) = (void*)newSocket;
855     code = sobind(&bhv, nam);
856     m_freem(nam);
857 #else
858     code = sobind(newSocket, nam);
859 #endif
860     if (code) {
861         printf("sobind fails (%d)\n", (int) code);
862         soclose(newSocket);
863 #ifndef AFS_SGI65_ENV
864         m_freem(nam);
865 #endif
866         goto bad;
867     }
868 #endif /* else AFS_DARWIN_ENV */
869 #endif /* else AFS_HPUX110_ENV */
870
871 #if defined(AFS_DARWIN_ENV) && defined(KERNEL_FUNNEL)
872     thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
873 #endif
874     return (struct osi_socket *) newSocket;
875
876 bad:
877 #if defined(AFS_DARWIN_ENV) && defined(KERNEL_FUNNEL)
878     thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
879 #endif
880     return (struct osi_socket *) 0;
881 }
882
883
884 /* free socket allocated by rxk_NewSocket */
885 int rxk_FreeSocket(register struct socket *asocket)
886 {
887     AFS_STATCNT(osi_FreeSocket);
888 #if defined(AFS_DARWIN_ENV) && defined(KERNEL_FUNNEL)
889     thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
890 #endif
891     soclose(asocket);
892 #if defined(AFS_DARWIN_ENV) && defined(KERNEL_FUNNEL)
893     thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
894 #endif
895     return 0;
896 }
897 #endif /* !SUN5 && !LINUX20 */
898
899 #if defined(RXK_LISTENER_ENV) || defined(AFS_SUN5_ENV)
900 /*
901  * Run RX event daemon every second (5 times faster than rest of systems)
902  */
903 void afs_rxevent_daemon(void) 
904 {
905     struct clock temp;
906     SPLVAR;
907
908     while (1) {
909 #ifdef RX_ENABLE_LOCKS
910         AFS_GUNLOCK();
911 #endif /* RX_ENABLE_LOCKS */
912         NETPRI;
913         AFS_RXGLOCK();
914         rxevent_RaiseEvents(&temp);
915         AFS_RXGUNLOCK();
916         USERPRI;
917 #ifdef RX_ENABLE_LOCKS
918         AFS_GLOCK();
919 #endif /* RX_ENABLE_LOCKS */
920 #ifdef RX_KERNEL_TRACE
921         afs_Trace1(afs_iclSetp, CM_TRACE_TIMESTAMP,
922                    ICL_TYPE_STRING, "before afs_osi_Wait()");
923 #endif
924         afs_osi_Wait(500, NULL, 0);
925 #ifdef RX_KERNEL_TRACE
926         afs_Trace1(afs_iclSetp, CM_TRACE_TIMESTAMP,
927                    ICL_TYPE_STRING, "after afs_osi_Wait()");
928 #endif
929         if (afs_termState == AFSOP_STOP_RXEVENT )
930         {
931 #ifdef RXK_LISTENER_ENV
932                 afs_termState = AFSOP_STOP_RXK_LISTENER;
933 #else
934                 afs_termState = AFSOP_STOP_COMPLETE;
935 #endif
936                 osi_rxWakeup(&afs_termState);
937                 return;
938         }
939     }
940 }
941 #endif
942
943 #ifdef RXK_LISTENER_ENV 
944
945 /* rxk_ReadPacket returns 1 if valid packet, 0 on error. */
946 int rxk_ReadPacket(osi_socket so, struct rx_packet *p, int *host, int *port)
947 {
948     int code;
949     struct sockaddr_in from;
950     int nbytes;
951     afs_int32 rlen;
952     register afs_int32 tlen;
953     afs_int32 savelen;            /* was using rlen but had aliasing problems */
954     rx_computelen(p, tlen);
955     rx_SetDataSize(p, tlen);  /* this is the size of the user data area */
956
957     tlen += RX_HEADER_SIZE;   /* now this is the size of the entire packet */
958     rlen = rx_maxJumboRecvSize; /* this is what I am advertising.  Only check
959                                  * it once in order to avoid races.  */
960     tlen = rlen - tlen;
961     if (tlen > 0) {
962       tlen = rxi_AllocDataBuf(p, tlen, RX_PACKET_CLASS_RECV_CBUF);
963       if (tlen >0) {
964         tlen = rlen - tlen;
965       }
966       else tlen = rlen;
967     }
968     else tlen = rlen;
969
970    /* add some padding to the last iovec, it's just to make sure that the 
971     * read doesn't return more data than we expect, and is done to get around
972     * our problems caused by the lack of a length field in the rx header. */
973     savelen = p->wirevec[p->niovecs-1].iov_len;
974     p->wirevec[p->niovecs-1].iov_len = savelen + RX_EXTRABUFFERSIZE;
975
976     nbytes = tlen + sizeof(afs_int32);
977 #ifdef RX_KERNEL_TRACE
978     AFS_GLOCK();
979     afs_Trace1(afs_iclSetp, CM_TRACE_TIMESTAMP,
980                 ICL_TYPE_STRING, "before osi_NetRecive()");
981     AFS_GUNLOCK();
982 #endif
983     code = osi_NetReceive(rx_socket, &from, p->wirevec, p->niovecs,
984                             &nbytes);
985
986 #ifdef RX_KERNEL_TRACE
987     AFS_GLOCK();
988     afs_Trace1(afs_iclSetp, CM_TRACE_TIMESTAMP,
989                 ICL_TYPE_STRING, "after osi_NetRecive()");
990     AFS_GUNLOCK();
991 #endif
992    /* restore the vec to its correct state */
993     p->wirevec[p->niovecs-1].iov_len = savelen;
994
995     if (!code) {
996         p->length = nbytes - RX_HEADER_SIZE;;
997         if ((nbytes > tlen) || (p->length & 0x8000)) {  /* Bogus packet */
998             if (nbytes > 0)
999                 rxi_MorePackets(rx_initSendWindow);
1000             else {
1001                 MUTEX_ENTER(&rx_stats_mutex);
1002                 rx_stats.bogusPacketOnRead++;
1003                 rx_stats.bogusHost = from.sin_addr.s_addr;
1004                 MUTEX_EXIT(&rx_stats_mutex);
1005                 dpf(("B: bogus packet from [%x,%d] nb=%d", from.sin_addr.s_addr,
1006                      from.sin_port,nbytes));
1007             }
1008             return  -1;
1009         }
1010         else {
1011             /* Extract packet header. */
1012             rxi_DecodePacketHeader(p);
1013       
1014             *host = from.sin_addr.s_addr;
1015             *port = from.sin_port;
1016             if (p->header.type > 0 && p->header.type < RX_N_PACKET_TYPES) {
1017                 MUTEX_ENTER(&rx_stats_mutex);
1018                 rx_stats.packetsRead[p->header.type-1]++;
1019                 MUTEX_EXIT(&rx_stats_mutex);
1020             }
1021
1022             /* Free any empty packet buffers at the end of this packet */
1023             rxi_TrimDataBufs(p, 1);
1024
1025             return  0;
1026         }
1027     }
1028     else
1029         return code;
1030 }
1031
1032 /* rxk_Listener() 
1033  *
1034  * Listen for packets on socket. This thread is typically started after
1035  * rx_Init has called rxi_StartListener(), but nevertheless, ensures that
1036  * the start state is set before proceeding.
1037  *
1038  * Note that this thread is outside the AFS global lock for much of
1039  * it's existence.
1040  *
1041  * In many OS's, the socket receive code sleeps interruptibly. That's not what
1042  * we want here. So we need to either block all signals (including SIGKILL
1043  * and SIGSTOP) or reset the thread's signal state to unsignalled when the
1044  * OS's socket receive routine returns as a result of a signal.
1045  */
1046 int rxk_ListenerPid; /* Used to signal process to wakeup at shutdown */
1047
1048 #ifdef AFS_SUN5_ENV
1049 /*
1050  * Run the listener as a kernel thread.
1051  */
1052 void rxk_Listener(void)
1053 {
1054     extern id_t syscid;
1055     void rxk_ListenerProc(void);
1056     if (thread_create(NULL, DEFAULTSTKSZ, rxk_ListenerProc,
1057         0, 0, &p0, TS_RUN, minclsyspri) == NULL)
1058         osi_Panic("rxk_Listener: failed to start listener thread!\n");
1059 }
1060
1061 void rxk_ListenerProc(void)
1062 #else /* AFS_SUN5_ENV */
1063 void rxk_Listener(void)
1064 #endif /* AFS_SUN5_ENV */
1065 {
1066     struct rx_packet *rxp = NULL;
1067     int code;
1068     int host, port;
1069
1070 #ifdef AFS_LINUX20_ENV
1071     rxk_ListenerPid = current->pid;
1072 #endif
1073 #ifdef AFS_SUN5_ENV
1074     rxk_ListenerPid = 1;        /* No PID, just a flag that we're alive */
1075 #endif /* AFS_SUN5_ENV */
1076 #ifdef AFS_XBSD_ENV
1077     rxk_ListenerPid = curproc->p_pid;
1078 #endif /* AFS_FBSD_ENV */
1079 #if defined(AFS_DARWIN_ENV)
1080     rxk_ListenerPid = current_proc()->p_pid;
1081 #endif
1082 #if defined(RX_ENABLE_LOCKS) && !defined(AFS_SUN5_ENV)
1083     AFS_GUNLOCK();
1084 #endif /* RX_ENABLE_LOCKS && !AFS_SUN5_ENV */
1085
1086     while (afs_termState != AFSOP_STOP_RXK_LISTENER) {
1087         if (rxp) {
1088             rxi_RestoreDataBufs(rxp);
1089         }
1090         else {
1091             rxp = rxi_AllocPacket(RX_PACKET_CLASS_RECEIVE);
1092             if (!rxp)
1093                 osi_Panic("rxk_Listener: No more Rx buffers!\n");
1094         }
1095         if (!(code = rxk_ReadPacket(rx_socket, rxp, &host, &port))) {
1096             AFS_RXGLOCK();
1097             rxp = rxi_ReceivePacket(rxp, rx_socket, host, port, 0, 0);
1098             AFS_RXGUNLOCK();
1099         }
1100     }
1101
1102 #ifdef RX_ENABLE_LOCKS
1103     AFS_GLOCK();
1104 #endif /* RX_ENABLE_LOCKS */
1105     if (afs_termState == AFSOP_STOP_RXK_LISTENER) {
1106         afs_termState = AFSOP_STOP_COMPLETE;
1107         osi_rxWakeup(&afs_termState);
1108     }
1109     rxk_ListenerPid = 0;
1110 #if defined(AFS_LINUX22_ENV) || defined(AFS_SUN5_ENV)
1111     osi_rxWakeup(&rxk_ListenerPid);
1112 #endif
1113 #ifdef AFS_SUN5_ENV
1114     AFS_GUNLOCK();
1115 #endif /* AFS_SUN5_ENV */
1116 }
1117
1118 #if !defined(AFS_LINUX20_ENV) && !defined(AFS_SUN5_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_XBSD_ENV)
1119 /* The manner of stopping the rx listener thread may vary. Most unix's should
1120  * be able to call soclose.
1121  */
1122 void osi_StopListener(void)
1123 {
1124     soclose(rx_socket);
1125 }
1126 #endif
1127 #endif /* RXK_LISTENER_ENV */
1128
1129 #endif /* !NCR && !UKERNEL */