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