18e8ee32ac1648fc0228d2ba472a9507750f1471
[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/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_XBSD_ENV)
603     TAILQ_FOREACH(ifn, &ifnet, if_link) {
604       if (i >= ADDRSPERSITE) break;
605 #else 
606     for (ifn = ifnet; ifn != NULL && i < ADDRSPERSITE; ifn = ifn->if_next) {
607 #endif
608       rxmtu = (ifn->if_mtu - RX_IPUDP_SIZE);
609 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
610       TAILQ_FOREACH(ifad, &ifn->if_addrhead, ifa_link) {
611       if (i >= ADDRSPERSITE) break;
612 #else
613       for (ifad = ifn->if_addrlist; ifad != NULL && i < ADDRSPERSITE;
614            ifad = ifad->ifa_next){
615 #endif
616         if (IFADDR2SA(ifad)->sa_family == AF_INET) {
617           ifinaddr = ntohl(((struct sockaddr_in *) IFADDR2SA(ifad))->sin_addr.s_addr);
618           if (myNetAddrs[i] != ifinaddr) { 
619             different++;
620           }
621           mtus[i] = rxmtu;
622           rxmtu = rxi_AdjustIfMTU(rxmtu);
623           maxmtu = rxmtu * rxi_nRecvFrags + ((rxi_nRecvFrags-1) * UDP_HDR_SIZE);
624           maxmtu = rxi_AdjustMaxMTU(rxmtu, maxmtu);
625           addrs[i++] = ifinaddr;
626           if ( ( ifinaddr != 0x7f000001 ) &&
627               (maxmtu > rx_maxReceiveSize) ) {
628             rx_maxReceiveSize = MIN( RX_MAX_PACKET_SIZE, maxmtu);
629             rx_maxReceiveSize = MIN( rx_maxReceiveSize, rx_maxReceiveSizeUser);
630           }
631         }
632       }
633     }
634
635     rx_maxJumboRecvSize = RX_HEADER_SIZE
636                           + rxi_nDgramPackets * RX_JUMBOBUFFERSIZE
637                           + (rxi_nDgramPackets-1) * RX_JUMBOHEADERSIZE;
638     rx_maxJumboRecvSize = MAX(rx_maxJumboRecvSize, rx_maxReceiveSize);
639
640     if (different) {
641       int j;
642       for (j=0; j< i; j++) {
643         myNetMTUs[j] = mtus[j];
644         myNetAddrs[j] = addrs[j];
645       }
646     }
647    return different;
648 }
649 #ifdef AFS_DARWIN60_ENV
650 /* Returns ifnet which best matches address */
651 struct ifnet *
652 rxi_FindIfnet(addr, pifad) 
653      afs_uint32 addr;
654      struct ifaddr **pifad;
655 {
656   struct sockaddr_in s;
657
658   if (numMyNetAddrs == 0)
659     (void) rxi_GetIFInfo();
660
661   s.sin_family=AF_INET;
662   s.sin_addr.s_addr=addr;
663   *pifad=ifa_ifwithnet((struct sockaddr *)&s);
664  done:
665   return (*pifad ?  (*pifad)->ifa_ifp : NULL );
666 }
667 #else
668 /* Returns ifnet which best matches address */
669 struct ifnet *rxi_FindIfnet(afs_uint32 addr, struct in_ifaddr **pifad) 
670 {
671   afs_uint32 ppaddr;
672   int match_value = 0;
673   extern struct in_ifaddr *in_ifaddr;
674   struct in_ifaddr *ifa;
675   struct sockaddr_in *sin;
676   
677   if (numMyNetAddrs == 0)
678     (void) rxi_GetIFInfo();
679
680   ppaddr = ntohl(addr);
681
682   /* if we're given an address, skip everything until we find it */
683   if (!*pifad)
684 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
685     *pifad = TAILQ_FIRST(&in_ifaddrhead);
686 #else 
687     *pifad = in_ifaddr;
688 #endif
689   else {
690     if (((ppaddr & (*pifad)->ia_subnetmask) == (*pifad)->ia_subnet))
691       match_value = 2; /* don't find matching nets, just subnets */
692 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
693     *pifad = TAILQ_NEXT(*pifad, ia_link);
694 #else   
695     *pifad = (*pifad)->ia_next;
696 #endif
697   }
698     
699 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
700   for (ifa = *pifad; ifa; ifa = TAILQ_NEXT(ifa, ia_link) ) {
701 #else
702   for (ifa = *pifad; ifa; ifa = ifa->ia_next ) {
703 #endif
704     if ((ppaddr & ifa->ia_netmask) == ifa->ia_net) {
705       if ((ppaddr & ifa->ia_subnetmask) == ifa->ia_subnet) {
706         sin=IA_SIN(ifa);
707         if ( sin->sin_addr.s_addr == ppaddr) {   /* ie, ME!!!  */
708           match_value = 4;
709           *pifad = ifa;
710           goto done;
711         }
712         if (match_value < 3) {
713           *pifad = ifa;
714           match_value = 3;
715         }
716       }
717       else {
718         if (match_value < 2) {
719           *pifad = ifa;
720           match_value = 2;
721         }
722       }
723     } /* if net matches */
724   } /* for all in_ifaddrs */
725
726  done:
727   return (*pifad ?  (*pifad)->ia_ifp : NULL );
728 }
729 #endif
730 #endif /* else AFS_USERSPACE_IP_ADDR */
731 #endif /* !SUN5 && !SGI62 */
732
733
734 /* rxk_NewSocket, rxk_FreeSocket and osi_NetSend are from the now defunct
735  * afs_osinet.c. One could argue that rxi_NewSocket could go into the
736  * system specific subdirectories for all systems. But for the moment,
737  * most of it is simple to follow common code.
738  */
739 #if !defined(UKERNEL)
740 #if !defined(AFS_SUN5_ENV) && !defined(AFS_LINUX20_ENV)
741 /* rxk_NewSocket creates a new socket on the specified port. The port is
742  * in network byte order.
743  */
744 struct osi_socket *rxk_NewSocket(short aport)
745 {
746     register afs_int32 code;
747     struct socket *newSocket;
748     register struct mbuf *nam;
749     struct sockaddr_in myaddr;
750     int wow;
751 #ifdef AFS_HPUX110_ENV
752     /* prototype copied from kernel source file streams/str_proto.h */
753     extern MBLKP allocb_wait(int, int);
754     MBLKP bindnam;
755     int addrsize = sizeof(struct sockaddr_in);
756 #endif
757 #ifdef AFS_SGI65_ENV
758     bhv_desc_t bhv;
759 #endif
760
761     AFS_STATCNT(osi_NewSocket);
762 #if (defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)) && defined(KERNEL_FUNNEL)
763     thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
764 #endif
765 #if     defined(AFS_HPUX102_ENV)
766 #if     defined(AFS_HPUX110_ENV)
767     /* blocking socket */
768     code = socreate(AF_INET, &newSocket, SOCK_DGRAM, 0, 0);
769 #else      /* AFS_HPUX110_ENV */
770     code = socreate(AF_INET, &newSocket, SOCK_DGRAM, 0, SS_NOWAIT);
771 #endif     /* else AFS_HPUX110_ENV */
772 #else
773 #ifdef AFS_SGI65_ENV
774     code = socreate(AF_INET, &newSocket, SOCK_DGRAM,IPPROTO_UDP);
775 #elif defined(AFS_XBSD_ENV)
776     code = socreate(AF_INET, &newSocket, SOCK_DGRAM,IPPROTO_UDP, curproc);
777 #else
778     code = socreate(AF_INET, &newSocket, SOCK_DGRAM, 0);
779 #endif /* AFS_SGI65_ENV */
780 #endif /* AFS_HPUX102_ENV */
781     if (code) goto bad;
782
783     myaddr.sin_family = AF_INET;
784     myaddr.sin_port = aport;
785     myaddr.sin_addr.s_addr = 0;
786 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
787     myaddr.sin_len = sizeof(myaddr);
788 #endif
789
790 #ifdef AFS_HPUX110_ENV
791     bindnam = allocb_wait((addrsize+SO_MSGOFFSET+1), BPRI_MED);
792     if (!bindnam) {
793        setuerror(ENOBUFS);
794        goto bad;
795     }
796     memcpy((caddr_t)bindnam->b_rptr+SO_MSGOFFSET, (caddr_t)&myaddr, addrsize);
797     bindnam->b_wptr = bindnam->b_rptr + (addrsize+SO_MSGOFFSET+1);
798
799     code = sobind(newSocket, bindnam, addrsize);
800     if (code) {
801        soclose(newSocket);
802        m_freem(nam);
803        goto bad;
804     }
805
806     freeb(bindnam);
807 #else /* AFS_HPUX110_ENV */
808     code = soreserve(newSocket, 50000, 50000);
809     if (code) {
810         code = soreserve(newSocket, 32766, 32766);
811         if (code)
812             osi_Panic("osi_NewSocket: last attempt to reserve 32K failed!\n");
813     }
814 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
815 #if defined(AFS_XBSD_ENV)
816     code = sobind(newSocket, (struct sockaddr *)&myaddr, curproc);
817 #else
818     code = sobind(newSocket, (struct sockaddr *)&myaddr);
819 #endif
820     if (code) {
821         printf("sobind fails\n");
822         soclose(newSocket);
823         goto bad;
824     }
825 #else
826 #ifdef  AFS_OSF_ENV
827     nam = m_getclr(M_WAIT, MT_SONAME);
828 #else   /* AFS_OSF_ENV */
829     nam = m_get(M_WAIT, MT_SONAME);
830 #endif
831     if (nam == NULL) {
832 #if !defined(AFS_SUN5_ENV) && !defined(AFS_OSF_ENV) && !defined(AFS_SGI64_ENV) && !defined(AFS_XBSD_ENV)
833         setuerror(ENOBUFS);
834 #endif
835         goto bad;
836     }
837     nam->m_len = sizeof(myaddr);
838 #ifdef  AFS_OSF_ENV
839     myaddr.sin_len = nam->m_len;
840 #endif  /* AFS_OSF_ENV */
841     memcpy(mtod(nam, caddr_t), &myaddr, sizeof(myaddr));
842 #ifdef AFS_SGI65_ENV
843     BHV_PDATA(&bhv) = (void*)newSocket;
844     code = sobind(&bhv, nam);
845     m_freem(nam);
846 #elif defined(AFS_XBSD_ENV)
847     code = sobind(newSocket, nam, curproc);
848 #else
849     code = sobind(newSocket, nam);
850 #endif
851     if (code) {
852         soclose(newSocket);
853 #ifndef AFS_SGI65_ENV
854         m_freem(nam);
855 #endif
856         goto bad;
857     }
858 #endif /* else AFS_DARWIN_ENV */
859 #endif /* else AFS_HPUX110_ENV */
860
861 #if defined(AFS_DARWIN_ENV) && defined(KERNEL_FUNNEL)
862     thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
863 #endif
864     return (struct osi_socket *) newSocket;
865
866 bad:
867 #if defined(AFS_DARWIN_ENV) && defined(KERNEL_FUNNEL)
868     thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
869 #endif
870     return (struct osi_socket *) 0;
871 }
872
873
874 /* free socket allocated by rxk_NewSocket */
875 int rxk_FreeSocket(register struct socket *asocket)
876 {
877     AFS_STATCNT(osi_FreeSocket);
878 #if defined(AFS_DARWIN_ENV) && defined(KERNEL_FUNNEL)
879     thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
880 #endif
881     soclose(asocket);
882 #if defined(AFS_DARWIN_ENV) && defined(KERNEL_FUNNEL)
883     thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
884 #endif
885     return 0;
886 }
887 #endif /* !SUN5 && !LINUX20 */
888
889 #if defined(RXK_LISTENER_ENV) || defined(AFS_SUN5_ENV)
890 /*
891  * Run RX event daemon every second (5 times faster than rest of systems)
892  */
893 void afs_rxevent_daemon(void) 
894 {
895     struct clock temp;
896     SPLVAR;
897
898     while (1) {
899 #ifdef RX_ENABLE_LOCKS
900         AFS_GUNLOCK();
901 #endif /* RX_ENABLE_LOCKS */
902         NETPRI;
903         AFS_RXGLOCK();
904         rxevent_RaiseEvents(&temp);
905         AFS_RXGUNLOCK();
906         USERPRI;
907 #ifdef RX_ENABLE_LOCKS
908         AFS_GLOCK();
909 #endif /* RX_ENABLE_LOCKS */
910         afs_osi_Wait(500, NULL, 0);
911         if (afs_termState == AFSOP_STOP_RXEVENT )
912         {
913 #ifdef RXK_LISTENER_ENV
914                 afs_termState = AFSOP_STOP_RXK_LISTENER;
915 #else
916                 afs_termState = AFSOP_STOP_COMPLETE;
917 #endif
918                 afs_osi_Wakeup(&afs_termState);
919                 return;
920         }
921     }
922 }
923 #endif
924
925 #ifdef RXK_LISTENER_ENV 
926
927 /* rxk_ReadPacket returns 1 if valid packet, 0 on error. */
928 int rxk_ReadPacket(osi_socket so, struct rx_packet *p, int *host, int *port)
929 {
930     int code;
931     struct sockaddr_in from;
932     int nbytes;
933     afs_int32 rlen;
934     register afs_int32 tlen;
935     afs_int32 savelen;            /* was using rlen but had aliasing problems */
936     rx_computelen(p, tlen);
937     rx_SetDataSize(p, tlen);  /* this is the size of the user data area */
938
939     tlen += RX_HEADER_SIZE;   /* now this is the size of the entire packet */
940     rlen = rx_maxJumboRecvSize; /* this is what I am advertising.  Only check
941                                  * it once in order to avoid races.  */
942     tlen = rlen - tlen;
943     if (tlen > 0) {
944       tlen = rxi_AllocDataBuf(p, tlen, RX_PACKET_CLASS_RECV_CBUF);
945       if (tlen >0) {
946         tlen = rlen - tlen;
947       }
948       else tlen = rlen;
949     }
950     else tlen = rlen;
951
952    /* add some padding to the last iovec, it's just to make sure that the 
953     * read doesn't return more data than we expect, and is done to get around
954     * our problems caused by the lack of a length field in the rx header. */
955     savelen = p->wirevec[p->niovecs-1].iov_len;
956     p->wirevec[p->niovecs-1].iov_len = savelen + RX_EXTRABUFFERSIZE;
957
958     nbytes = tlen + sizeof(afs_int32);
959     code = osi_NetReceive(rx_socket, &from, p->wirevec, p->niovecs,
960                             &nbytes);
961
962    /* restore the vec to its correct state */
963     p->wirevec[p->niovecs-1].iov_len = savelen;
964
965     if (!code) {
966         p->length = nbytes - RX_HEADER_SIZE;;
967         if ((nbytes > tlen) || (p->length & 0x8000)) {  /* Bogus packet */
968             if (nbytes > 0)
969                 rxi_MorePackets(rx_initSendWindow);
970             else {
971                 MUTEX_ENTER(&rx_stats_mutex);
972                 rx_stats.bogusPacketOnRead++;
973                 rx_stats.bogusHost = from.sin_addr.s_addr;
974                 MUTEX_EXIT(&rx_stats_mutex);
975                 dpf(("B: bogus packet from [%x,%d] nb=%d", from.sin_addr.s_addr,
976                      from.sin_port,nbytes));
977             }
978             return  -1;
979         }
980         else {
981             /* Extract packet header. */
982             rxi_DecodePacketHeader(p);
983       
984             *host = from.sin_addr.s_addr;
985             *port = from.sin_port;
986             if (p->header.type > 0 && p->header.type < RX_N_PACKET_TYPES) {
987                 MUTEX_ENTER(&rx_stats_mutex);
988                 rx_stats.packetsRead[p->header.type-1]++;
989                 MUTEX_EXIT(&rx_stats_mutex);
990             }
991
992             /* Free any empty packet buffers at the end of this packet */
993             rxi_TrimDataBufs(p, 1);
994
995             return  0;
996         }
997     }
998     else
999         return code;
1000 }
1001
1002 /* rxk_Listener() 
1003  *
1004  * Listen for packets on socket. This thread is typically started after
1005  * rx_Init has called rxi_StartListener(), but nevertheless, ensures that
1006  * the start state is set before proceeding.
1007  *
1008  * Note that this thread is outside the AFS global lock for much of
1009  * it's existence.
1010  *
1011  * In many OS's, the socket receive code sleeps interruptibly. That's not what
1012  * we want here. So we need to either block all signals (including SIGKILL
1013  * and SIGSTOP) or reset the thread's signal state to unsignalled when the
1014  * OS's socket receive routine returns as a result of a signal.
1015  */
1016 int rxk_ListenerPid; /* Used to signal process to wakeup at shutdown */
1017
1018 #ifdef AFS_SUN5_ENV
1019 /*
1020  * Run the listener as a kernel thread.
1021  */
1022 void rxk_Listener(void)
1023 {
1024     extern id_t syscid;
1025     void rxk_ListenerProc(void);
1026     if (thread_create(NULL, DEFAULTSTKSZ, rxk_ListenerProc,
1027         0, 0, &p0, TS_RUN, minclsyspri) == NULL)
1028         osi_Panic("rxk_Listener: failed to start listener thread!\n");
1029 }
1030
1031 void rxk_ListenerProc(void)
1032 #else /* AFS_SUN5_ENV */
1033 void rxk_Listener(void)
1034 #endif /* AFS_SUN5_ENV */
1035 {
1036     struct rx_packet *rxp = NULL;
1037     int code;
1038     int host, port;
1039
1040 #ifdef AFS_LINUX20_ENV
1041     rxk_ListenerPid = current->pid;
1042 #endif
1043 #ifdef AFS_SUN5_ENV
1044     rxk_ListenerPid = 1;        /* No PID, just a flag that we're alive */
1045 #endif /* AFS_SUN5_ENV */
1046 #ifdef AFS_FBSD_ENV
1047     rxk_ListenerPid = curproc->p_pid;
1048 #endif /* AFS_FBSD_ENV */
1049 #if defined(AFS_DARWIN_ENV)
1050     rxk_ListenerPid = current_proc()->p_pid;
1051 #endif
1052 #if defined(RX_ENABLE_LOCKS) && !defined(AFS_SUN5_ENV)
1053     AFS_GUNLOCK();
1054 #endif /* RX_ENABLE_LOCKS && !AFS_SUN5_ENV */
1055
1056     while (afs_termState != AFSOP_STOP_RXK_LISTENER) {
1057         if (rxp) {
1058             rxi_RestoreDataBufs(rxp);
1059         }
1060         else {
1061             rxp = rxi_AllocPacket(RX_PACKET_CLASS_RECEIVE);
1062             if (!rxp)
1063                 osi_Panic("rxk_Listener: No more Rx buffers!\n");
1064         }
1065         if (!(code = rxk_ReadPacket(rx_socket, rxp, &host, &port))) {
1066             AFS_RXGLOCK();
1067             rxp = rxi_ReceivePacket(rxp, rx_socket, host, port, 0, 0);
1068             AFS_RXGUNLOCK();
1069         }
1070     }
1071
1072 #ifdef RX_ENABLE_LOCKS
1073     AFS_GLOCK();
1074 #endif /* RX_ENABLE_LOCKS */
1075     if (afs_termState == AFSOP_STOP_RXK_LISTENER) {
1076         afs_termState = AFSOP_STOP_COMPLETE;
1077         afs_osi_Wakeup(&afs_termState);
1078     }
1079     rxk_ListenerPid = 0;
1080 #if defined(AFS_LINUX22_ENV) || defined(AFS_SUN5_ENV)
1081     afs_osi_Wakeup(&rxk_ListenerPid);
1082 #endif
1083 #ifdef AFS_SUN5_ENV
1084     AFS_GUNLOCK();
1085 #endif /* AFS_SUN5_ENV */
1086 }
1087
1088 #if !defined(AFS_LINUX20_ENV) && !defined(AFS_SUN5_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_XBSD_ENV)
1089 /* The manner of stopping the rx listener thread may vary. Most unix's should
1090  * be able to call soclose.
1091  */
1092 void osi_StopListener(void)
1093 {
1094     soclose(rx_socket);
1095 }
1096 #endif
1097 #endif /* RXK_LISTENER_ENV */
1098
1099 #endif /* !NCR && !UKERNEL */