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