aabd6338b20e599cc0ca9d030cebd982de76ff84
[openafs.git] / src / rx / rx_packet.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 #include <afsconfig.h>
11 #ifdef KERNEL
12 #include "afs/param.h"
13 #else
14 #include <afs/param.h>
15 #endif
16
17 RCSID
18     ("$Header$");
19
20 #ifdef KERNEL
21 # if defined(UKERNEL)
22 #  include "afs/sysincludes.h"
23 #  include "afsincludes.h"
24 #  include "rx/rx_kcommon.h"
25 #  include "rx/rx_clock.h"
26 #  include "rx/rx_queue.h"
27 #  include "rx/rx_packet.h"
28 # else /* defined(UKERNEL) */
29 #  ifdef RX_KERNEL_TRACE
30 #   include "../rx/rx_kcommon.h"
31 #  endif
32 #  include "h/types.h"
33 #  ifndef AFS_LINUX20_ENV
34 #   include "h/systm.h"
35 #  endif
36 #  if defined(AFS_SGI_ENV) || defined(AFS_HPUX110_ENV)
37 #   include "afs/sysincludes.h"
38 #  endif
39 #  if defined(AFS_OBSD_ENV)
40 #   include "h/proc.h"
41 #  endif
42 #  include "h/socket.h"
43 #  if !defined(AFS_SUN5_ENV) &&  !defined(AFS_LINUX20_ENV) && !defined(AFS_HPUX110_ENV)
44 #   if  !defined(AFS_OSF_ENV) && !defined(AFS_AIX41_ENV)
45 #    include "sys/mount.h"              /* it gets pulled in by something later anyway */
46 #   endif
47 #   include "h/mbuf.h"
48 #  endif
49 #  include "netinet/in.h"
50 #  include "afs/afs_osi.h"
51 #  include "rx_kmutex.h"
52 #  include "rx/rx_clock.h"
53 #  include "rx/rx_queue.h"
54 #  ifdef        AFS_SUN5_ENV
55 #   include <sys/sysmacros.h>
56 #  endif
57 #  include "rx/rx_packet.h"
58 # endif /* defined(UKERNEL) */
59 # include "rx/rx_internal.h"
60 # include "rx/rx_globals.h"
61 #else /* KERNEL */
62 # include "sys/types.h"
63 # include <sys/stat.h>
64 # include <errno.h>
65 # if defined(AFS_NT40_ENV) 
66 #  include <winsock2.h>
67 #  ifndef EWOULDBLOCK
68 #   define EWOULDBLOCK WSAEWOULDBLOCK
69 #  endif
70 #  include "rx_user.h"
71 #  include "rx_xmit_nt.h"
72 #  include <stdlib.h>
73 # else
74 #  include <sys/socket.h>
75 #  include <netinet/in.h>
76 # endif
77 # include "rx_clock.h"
78 # include "rx_internal.h"
79 # include "rx.h"
80 # include "rx_queue.h"
81 # ifdef AFS_SUN5_ENV
82 #  include <sys/sysmacros.h>
83 # endif
84 # include "rx_packet.h"
85 # include "rx_globals.h"
86 # include <lwp.h>
87 # include <assert.h>
88 # include <string.h>
89 # ifdef HAVE_UNISTD_H
90 #  include <unistd.h>
91 # endif
92 #endif /* KERNEL */
93
94 #ifdef RX_LOCKS_DB
95 /* rxdb_fileID is used to identify the lock location, along with line#. */
96 static int rxdb_fileID = RXDB_FILE_RX_PACKET;
97 #endif /* RX_LOCKS_DB */
98 static struct rx_packet *rx_mallocedP = 0;
99 #ifdef DEBUG
100 static afs_uint32       rx_packet_id = 0;
101 #endif
102
103 extern char cml_version_number[];
104
105 static int AllocPacketBufs(int class, int num_pkts, struct rx_queue *q);
106
107 static void rxi_SendDebugPacket(struct rx_packet *apacket, osi_socket asocket,
108                                 afs_int32 ahost, short aport,
109                                 afs_int32 istack);
110
111 static int rxi_FreeDataBufsToQueue(struct rx_packet *p, 
112                                    afs_uint32 first, 
113                                    struct rx_queue * q);
114 #ifdef RX_ENABLE_TSFPQ
115 static int
116 rxi_FreeDataBufsTSFPQ(struct rx_packet *p, afs_uint32 first, int flush_global);
117 #endif
118
119 /* some rules about packets:
120  * 1.  When a packet is allocated, the final iov_buf contains room for
121  * a security trailer, but iov_len masks that fact.  If the security
122  * package wants to add the trailer, it may do so, and then extend
123  * iov_len appropriately.  For this reason, packet's niovecs and
124  * iov_len fields should be accurate before calling PreparePacket.
125 */
126
127 /* Preconditions:
128  *        all packet buffers (iov_base) are integral multiples of 
129  *        the word size.
130  *        offset is an integral multiple of the word size.
131  */
132 afs_int32
133 rx_SlowGetInt32(struct rx_packet *packet, size_t offset)
134 {
135     unsigned int i;
136     size_t l;
137     for (l = 0, i = 1; i < packet->niovecs; i++) {
138         if (l + packet->wirevec[i].iov_len > offset) {
139             return
140                 *((afs_int32 *) ((char *)(packet->wirevec[i].iov_base) +
141                                  (offset - l)));
142         }
143         l += packet->wirevec[i].iov_len;
144     }
145
146     return 0;
147 }
148
149 /* Preconditions:
150  *        all packet buffers (iov_base) are integral multiples of the word size.
151  *        offset is an integral multiple of the word size.
152  */
153 afs_int32
154 rx_SlowPutInt32(struct rx_packet * packet, size_t offset, afs_int32 data)
155 {
156     unsigned int i;
157     size_t l;
158     for (l = 0, i = 1; i < packet->niovecs; i++) {
159         if (l + packet->wirevec[i].iov_len > offset) {
160             *((afs_int32 *) ((char *)(packet->wirevec[i].iov_base) +
161                              (offset - l))) = data;
162             return 0;
163         }
164         l += packet->wirevec[i].iov_len;
165     }
166
167     return 0;
168 }
169
170 /* Preconditions:
171  *        all packet buffers (iov_base) are integral multiples of the
172  *        word size.
173  *        offset is an integral multiple of the word size.
174  * Packet Invariants:
175  *         all buffers are contiguously arrayed in the iovec from 0..niovecs-1
176  */
177 afs_int32
178 rx_SlowReadPacket(struct rx_packet * packet, unsigned int offset, int resid,
179                   char *out)
180 {
181     unsigned int i, j, l, r;
182     for (l = 0, i = 1; i < packet->niovecs; i++) {
183         if (l + packet->wirevec[i].iov_len > offset) {
184             break;
185         }
186         l += packet->wirevec[i].iov_len;
187     }
188
189     /* i is the iovec which contains the first little bit of data in which we
190      * are interested.  l is the total length of everything prior to this iovec.
191      * j is the number of bytes we can safely copy out of this iovec.
192      * offset only applies to the first iovec.
193      */
194     r = resid;
195     while ((resid > 0) && (i < packet->niovecs)) {
196         j = MIN(resid, packet->wirevec[i].iov_len - (offset - l));
197         memcpy(out, (char *)(packet->wirevec[i].iov_base) + (offset - l), j);
198         resid -= j;
199         out += j;
200         l += packet->wirevec[i].iov_len;
201         offset = l;
202         i++;
203     }
204
205     return (resid ? (r - resid) : r);
206 }
207
208
209 /* Preconditions:
210  *        all packet buffers (iov_base) are integral multiples of the
211  *        word size.
212  *        offset is an integral multiple of the word size.
213  */
214 afs_int32
215 rx_SlowWritePacket(struct rx_packet * packet, int offset, int resid, char *in)
216 {
217     int i, j, l, r;
218     char *b;
219
220     for (l = 0, i = 1; i < packet->niovecs; i++) {
221         if (l + packet->wirevec[i].iov_len > offset) {
222             break;
223         }
224         l += packet->wirevec[i].iov_len;
225     }
226
227     /* i is the iovec which contains the first little bit of data in which we
228      * are interested.  l is the total length of everything prior to this iovec.
229      * j is the number of bytes we can safely copy out of this iovec.
230      * offset only applies to the first iovec.
231      */
232     r = resid;
233     while ((resid > 0) && (i < RX_MAXWVECS)) {
234         if (i >= packet->niovecs)
235             if (rxi_AllocDataBuf(packet, resid, RX_PACKET_CLASS_SEND_CBUF) > 0) /* ++niovecs as a side-effect */
236                 break;
237
238         b = (char *)(packet->wirevec[i].iov_base) + (offset - l);
239         j = MIN(resid, packet->wirevec[i].iov_len - (offset - l));
240         memcpy(b, in, j);
241         resid -= j;
242         in += j;
243         l += packet->wirevec[i].iov_len;
244         offset = l;
245         i++;
246     }
247
248     return (resid ? (r - resid) : r);
249 }
250
251 int
252 rxi_AllocPackets(int class, int num_pkts, struct rx_queue * q)
253 {
254     register struct rx_packet *p, *np;
255
256     num_pkts = AllocPacketBufs(class, num_pkts, q);
257
258     for (queue_Scan(q, p, np, rx_packet)) {
259         RX_PACKET_IOV_FULLINIT(p);
260     }
261
262     return num_pkts;
263 }
264
265 #ifdef RX_ENABLE_TSFPQ
266 static int
267 AllocPacketBufs(int class, int num_pkts, struct rx_queue * q)
268 {
269     register struct rx_ts_info_t * rx_ts_info;
270     int transfer;
271     SPLVAR;
272
273     RX_TS_INFO_GET(rx_ts_info);
274
275     transfer = num_pkts - rx_ts_info->_FPQ.len;
276     if (transfer > 0) {
277         NETPRI;
278         MUTEX_ENTER(&rx_freePktQ_lock);
279         transfer = MAX(transfer, rx_TSFPQGlobSize);
280         if (transfer > rx_nFreePackets) {
281             /* alloc enough for us, plus a few globs for other threads */
282             rxi_MorePacketsNoLock(transfer + 4 * rx_initSendWindow);
283         }
284
285         RX_TS_FPQ_GTOL2(rx_ts_info, transfer);
286
287         MUTEX_EXIT(&rx_freePktQ_lock);
288         USERPRI;
289     }
290
291     RX_TS_FPQ_QCHECKOUT(rx_ts_info, num_pkts, q);
292
293     return num_pkts;
294 }
295 #else /* RX_ENABLE_TSFPQ */
296 static int
297 AllocPacketBufs(int class, int num_pkts, struct rx_queue * q)
298 {
299     struct rx_packet *c;
300     int i;
301 #ifdef KERNEL
302     int overq = 0;
303 #endif
304     SPLVAR;
305
306     NETPRI;
307
308     MUTEX_ENTER(&rx_freePktQ_lock);
309
310 #ifdef KERNEL
311     for (; (num_pkts > 0) && (rxi_OverQuota2(class,num_pkts)); 
312          num_pkts--, overq++);
313
314     if (overq) {
315         rxi_NeedMorePackets = TRUE;
316         switch (class) {
317         case RX_PACKET_CLASS_RECEIVE:
318             rx_MutexIncrement(rx_stats.receivePktAllocFailures, rx_stats_mutex);
319             break;
320         case RX_PACKET_CLASS_SEND:
321             rx_MutexIncrement(rx_stats.sendPktAllocFailures, rx_stats_mutex);
322             break;
323         case RX_PACKET_CLASS_SPECIAL:
324             rx_MutexIncrement(rx_stats.specialPktAllocFailures, rx_stats_mutex);
325             break;
326         case RX_PACKET_CLASS_RECV_CBUF:
327             rx_MutexIncrement(rx_stats.receiveCbufPktAllocFailures, rx_stats_mutex);
328             break;
329         case RX_PACKET_CLASS_SEND_CBUF:
330             rx_MutexIncrement(rx_stats.sendCbufPktAllocFailures, rx_stats_mutex);
331             break;
332         }
333     }
334
335     if (rx_nFreePackets < num_pkts)
336         num_pkts = rx_nFreePackets;
337
338     if (!num_pkts) {
339         rxi_NeedMorePackets = TRUE;
340         goto done;
341     }
342 #else /* KERNEL */
343     if (rx_nFreePackets < num_pkts) {
344         rxi_MorePacketsNoLock(MAX((num_pkts-rx_nFreePackets), 4 * rx_initSendWindow));
345     }
346 #endif /* KERNEL */
347
348     for (i=0, c=queue_First(&rx_freePacketQueue, rx_packet);
349          i < num_pkts; 
350          i++, c=queue_Next(c, rx_packet)) {
351         RX_FPQ_MARK_USED(c);
352     }
353
354     queue_SplitBeforeAppend(&rx_freePacketQueue,q,c);
355
356     rx_nFreePackets -= num_pkts;
357
358 #ifdef KERNEL
359   done:
360 #endif
361     MUTEX_EXIT(&rx_freePktQ_lock);
362
363     USERPRI;
364     return num_pkts;
365 }
366 #endif /* RX_ENABLE_TSFPQ */
367
368 /*
369  * Free a packet currently used as a continuation buffer
370  */
371 #ifdef RX_ENABLE_TSFPQ
372 /* num_pkts=0 means queue length is unknown */
373 int
374 rxi_FreePackets(int num_pkts, struct rx_queue * q)
375 {
376     register struct rx_ts_info_t * rx_ts_info;
377     register struct rx_packet *c, *nc;
378     SPLVAR;
379
380     osi_Assert(num_pkts >= 0);
381     RX_TS_INFO_GET(rx_ts_info);
382
383     if (!num_pkts) {
384         for (queue_Scan(q, c, nc, rx_packet), num_pkts++) {
385             rxi_FreeDataBufsTSFPQ(c, 2, 0);
386         }
387     } else {
388         for (queue_Scan(q, c, nc, rx_packet)) {
389             rxi_FreeDataBufsTSFPQ(c, 2, 0);
390         }
391     }
392
393     if (num_pkts) {
394         RX_TS_FPQ_QCHECKIN(rx_ts_info, num_pkts, q);
395     }
396
397     if (rx_ts_info->_FPQ.len > rx_TSFPQLocalMax) {
398         NETPRI;
399         MUTEX_ENTER(&rx_freePktQ_lock);
400
401         RX_TS_FPQ_LTOG(rx_ts_info);
402
403         /* Wakeup anyone waiting for packets */
404         rxi_PacketsUnWait();
405
406         MUTEX_EXIT(&rx_freePktQ_lock);
407         USERPRI;
408     }
409
410     return num_pkts;
411 }
412 #else /* RX_ENABLE_TSFPQ */
413 /* num_pkts=0 means queue length is unknown */
414 int
415 rxi_FreePackets(int num_pkts, struct rx_queue *q)
416 {
417     struct rx_queue cbs;
418     register struct rx_packet *p, *np;
419     int qlen = 0;
420     SPLVAR;
421
422     osi_Assert(num_pkts >= 0);
423     queue_Init(&cbs);
424
425     if (!num_pkts) {
426         for (queue_Scan(q, p, np, rx_packet), num_pkts++) {
427             if (p->niovecs > 2) {
428                 qlen += rxi_FreeDataBufsToQueue(p, 2, &cbs);
429             }
430             RX_FPQ_MARK_FREE(p);
431         }
432         if (!num_pkts)
433             return 0;
434     } else {
435         for (queue_Scan(q, p, np, rx_packet)) {
436             if (p->niovecs > 2) {
437                 qlen += rxi_FreeDataBufsToQueue(p, 2, &cbs);
438             }
439             RX_FPQ_MARK_FREE(p);
440         }
441     }
442
443     if (qlen) {
444         queue_SpliceAppend(q, &cbs);
445         qlen += num_pkts;
446     } else
447         qlen = num_pkts;
448
449     NETPRI;
450     MUTEX_ENTER(&rx_freePktQ_lock);
451
452     queue_SpliceAppend(&rx_freePacketQueue, q);
453     rx_nFreePackets += qlen;
454
455     /* Wakeup anyone waiting for packets */
456     rxi_PacketsUnWait();
457
458     MUTEX_EXIT(&rx_freePktQ_lock);
459     USERPRI;
460
461     return num_pkts;
462 }
463 #endif /* RX_ENABLE_TSFPQ */
464
465 /* this one is kind of awful.
466  * In rxkad, the packet has been all shortened, and everything, ready for 
467  * sending.  All of a sudden, we discover we need some of that space back.
468  * This isn't terribly general, because it knows that the packets are only
469  * rounded up to the EBS (userdata + security header).
470  */
471 int
472 rxi_RoundUpPacket(struct rx_packet *p, unsigned int nb)
473 {
474     int i;
475     i = p->niovecs - 1;
476     if (p->wirevec[i].iov_base == (caddr_t) p->localdata) {
477         if (p->wirevec[i].iov_len <= RX_FIRSTBUFFERSIZE - nb) {
478             p->wirevec[i].iov_len += nb;
479             return 0;
480         }
481     } else {
482         if (p->wirevec[i].iov_len <= RX_CBUFFERSIZE - nb) {
483             p->wirevec[i].iov_len += nb;
484             return 0;
485         }
486     }
487
488     return 0;
489 }
490
491 /* get sufficient space to store nb bytes of data (or more), and hook
492  * it into the supplied packet.  Return nbytes<=0 if successful, otherwise
493  * returns the number of bytes >0 which it failed to come up with.
494  * Don't need to worry about locking on packet, since only
495  * one thread can manipulate one at a time. Locking on continution
496  * packets is handled by AllocPacketBufs */
497 /* MTUXXX don't need to go throught the for loop if we can trust niovecs */
498 int
499 rxi_AllocDataBuf(struct rx_packet *p, int nb, int class)
500 {
501     int i, nv;
502     struct rx_queue q;
503     register struct rx_packet *cb, *ncb;
504
505     /* compute the number of cbuf's we need */
506     nv = nb / RX_CBUFFERSIZE;
507     if ((nv * RX_CBUFFERSIZE) < nb)
508         nv++;
509     if ((nv + p->niovecs) > RX_MAXWVECS)
510         nv = RX_MAXWVECS - p->niovecs;
511     if (nv < 1)
512         return nb;
513
514     /* allocate buffers */
515     queue_Init(&q);
516     nv = AllocPacketBufs(class, nv, &q);
517
518     /* setup packet iovs */
519     for (i = p->niovecs, queue_Scan(&q, cb, ncb, rx_packet), i++) {
520         queue_Remove(cb);
521         p->wirevec[i].iov_base = (caddr_t) cb->localdata;
522         p->wirevec[i].iov_len = RX_CBUFFERSIZE;
523     }
524
525     nb -= (nv * RX_CBUFFERSIZE);
526     p->length += (nv * RX_CBUFFERSIZE);
527     p->niovecs += nv;
528
529     return nb;
530 }
531
532 /* Add more packet buffers */
533 #ifdef RX_ENABLE_TSFPQ
534 void
535 rxi_MorePackets(int apackets)
536 {
537     struct rx_packet *p, *e;
538     register struct rx_ts_info_t * rx_ts_info;
539     int getme;
540     SPLVAR;
541
542     getme = apackets * sizeof(struct rx_packet);
543     p = (struct rx_packet *)osi_Alloc(getme);
544     osi_Assert(p);
545
546     PIN(p, getme);              /* XXXXX */
547     memset((char *)p, 0, getme);
548     RX_TS_INFO_GET(rx_ts_info);
549
550     RX_TS_FPQ_LOCAL_ALLOC(rx_ts_info,apackets);
551     /* TSFPQ patch also needs to keep track of total packets */
552     MUTEX_ENTER(&rx_stats_mutex);
553     rx_nPackets += apackets;
554     RX_TS_FPQ_COMPUTE_LIMITS;
555     MUTEX_EXIT(&rx_stats_mutex);
556
557     for (e = p + apackets; p < e; p++) {
558         RX_PACKET_IOV_INIT(p);
559         p->niovecs = 2;
560
561         RX_TS_FPQ_CHECKIN(rx_ts_info,p);
562
563         NETPRI;
564         MUTEX_ENTER(&rx_freePktQ_lock);
565 #ifdef DEBUG
566         p->packetId = rx_packet_id++;
567         p->allNextp = rx_mallocedP;
568 #endif /* DEBUG */
569         rx_mallocedP = p;
570         MUTEX_EXIT(&rx_freePktQ_lock);
571         USERPRI;
572     }
573     rx_ts_info->_FPQ.delta += apackets;
574
575     if (rx_ts_info->_FPQ.len > rx_TSFPQLocalMax) {
576         NETPRI;
577         MUTEX_ENTER(&rx_freePktQ_lock);
578
579         RX_TS_FPQ_LTOG(rx_ts_info);
580         rxi_NeedMorePackets = FALSE;
581         rxi_PacketsUnWait();
582
583         MUTEX_EXIT(&rx_freePktQ_lock);
584         USERPRI;
585     }
586 }
587 #else /* RX_ENABLE_TSFPQ */
588 void
589 rxi_MorePackets(int apackets)
590 {
591     struct rx_packet *p, *e;
592     int getme;
593     SPLVAR;
594
595     getme = apackets * sizeof(struct rx_packet);
596     p = (struct rx_packet *)osi_Alloc(getme);
597     osi_Assert(p);
598
599     PIN(p, getme);              /* XXXXX */
600     memset((char *)p, 0, getme);
601     NETPRI;
602     MUTEX_ENTER(&rx_freePktQ_lock);
603
604     for (e = p + apackets; p < e; p++) {
605         RX_PACKET_IOV_INIT(p);
606         p->flags |= RX_PKTFLAG_FREE;
607         p->niovecs = 2;
608
609         queue_Append(&rx_freePacketQueue, p);
610 #ifdef DEBUG
611         p->packetId = rx_packet_id++;
612         p->allNextp = rx_mallocedP;
613 #endif /* DEBUG */
614         rx_mallocedP = p;
615     }
616
617     rx_nFreePackets += apackets;
618     rxi_NeedMorePackets = FALSE;
619     rxi_PacketsUnWait();
620
621     MUTEX_EXIT(&rx_freePktQ_lock);
622     USERPRI;
623 }
624 #endif /* RX_ENABLE_TSFPQ */
625
626 #ifdef RX_ENABLE_TSFPQ
627 void
628 rxi_MorePacketsTSFPQ(int apackets, int flush_global, int num_keep_local)
629 {
630     struct rx_packet *p, *e;
631     register struct rx_ts_info_t * rx_ts_info;
632     int getme;
633     SPLVAR;
634
635     getme = apackets * sizeof(struct rx_packet);
636     p = (struct rx_packet *)osi_Alloc(getme);
637
638     PIN(p, getme);              /* XXXXX */
639     memset((char *)p, 0, getme);
640     RX_TS_INFO_GET(rx_ts_info);
641
642     RX_TS_FPQ_LOCAL_ALLOC(rx_ts_info,apackets);
643     /* TSFPQ patch also needs to keep track of total packets */
644     MUTEX_ENTER(&rx_stats_mutex);
645     rx_nPackets += apackets;
646     RX_TS_FPQ_COMPUTE_LIMITS;
647     MUTEX_EXIT(&rx_stats_mutex);
648
649     for (e = p + apackets; p < e; p++) {
650         RX_PACKET_IOV_INIT(p);
651         p->niovecs = 2;
652         RX_TS_FPQ_CHECKIN(rx_ts_info,p);
653         
654         NETPRI;
655         MUTEX_ENTER(&rx_freePktQ_lock);
656 #ifdef DEBUG
657         p->packetId = rx_packet_id++;
658         p->allNextp = rx_mallocedP;
659 #endif /* DEBUG */
660         rx_mallocedP = p;
661         MUTEX_EXIT(&rx_freePktQ_lock);
662         USERPRI;
663     }
664     rx_ts_info->_FPQ.delta += apackets;
665
666     if (flush_global && 
667         (num_keep_local < apackets)) {
668         NETPRI;
669         MUTEX_ENTER(&rx_freePktQ_lock);
670
671         RX_TS_FPQ_LTOG2(rx_ts_info, (apackets - num_keep_local));
672         rxi_NeedMorePackets = FALSE;
673         rxi_PacketsUnWait();
674
675         MUTEX_EXIT(&rx_freePktQ_lock);
676         USERPRI;
677     }
678 }
679 #endif /* RX_ENABLE_TSFPQ */
680
681 #ifndef KERNEL
682 /* Add more packet buffers */
683 void
684 rxi_MorePacketsNoLock(int apackets)
685 {
686 #ifdef RX_ENABLE_TSFPQ
687     register struct rx_ts_info_t * rx_ts_info;
688 #endif /* RX_ENABLE_TSFPQ */
689     struct rx_packet *p, *e;
690     int getme;
691
692     /* allocate enough packets that 1/4 of the packets will be able
693      * to hold maximal amounts of data */
694     apackets += (apackets / 4)
695         * ((rx_maxJumboRecvSize - RX_FIRSTBUFFERSIZE) / RX_CBUFFERSIZE);
696     do {
697         getme = apackets * sizeof(struct rx_packet);
698         p = (struct rx_packet *)osi_Alloc(getme);
699         if (p == NULL) {
700             apackets -= apackets / 4;
701             osi_Assert(apackets > 0);
702         }
703     } while(p == NULL);
704     memset((char *)p, 0, getme);
705
706 #ifdef RX_ENABLE_TSFPQ
707     RX_TS_INFO_GET(rx_ts_info);
708     RX_TS_FPQ_GLOBAL_ALLOC(rx_ts_info,apackets);
709 #endif /* RX_ENABLE_TSFPQ */ 
710
711     for (e = p + apackets; p < e; p++) {
712         RX_PACKET_IOV_INIT(p);
713         p->flags |= RX_PKTFLAG_FREE;
714         p->niovecs = 2;
715
716         queue_Append(&rx_freePacketQueue, p);
717 #ifdef DEBUG
718         p->packetId = rx_packet_id++;
719         p->allNextp = rx_mallocedP;
720 #endif /* DEBUG */
721         rx_mallocedP = p;
722     }
723
724     rx_nFreePackets += apackets;
725 #ifdef RX_ENABLE_TSFPQ
726     /* TSFPQ patch also needs to keep track of total packets */
727     MUTEX_ENTER(&rx_stats_mutex);
728     rx_nPackets += apackets;
729     RX_TS_FPQ_COMPUTE_LIMITS;
730     MUTEX_EXIT(&rx_stats_mutex);
731 #endif /* RX_ENABLE_TSFPQ */
732     rxi_NeedMorePackets = FALSE;
733     rxi_PacketsUnWait();
734 }
735 #endif /* !KERNEL */
736
737 void
738 rxi_FreeAllPackets(void)
739 {
740     /* must be called at proper interrupt level, etcetera */
741     /* MTUXXX need to free all Packets */
742     osi_Free(rx_mallocedP,
743              (rx_maxReceiveWindow + 2) * sizeof(struct rx_packet));
744     UNPIN(rx_mallocedP, (rx_maxReceiveWindow + 2) * sizeof(struct rx_packet));
745 }
746
747 #ifdef RX_ENABLE_TSFPQ
748 void
749 rxi_AdjustLocalPacketsTSFPQ(int num_keep_local, int allow_overcommit)
750 {
751     register struct rx_ts_info_t * rx_ts_info;
752     register int xfer;
753     SPLVAR;
754
755     RX_TS_INFO_GET(rx_ts_info);
756
757     if (num_keep_local != rx_ts_info->_FPQ.len) {
758         NETPRI;
759         MUTEX_ENTER(&rx_freePktQ_lock);
760         if (num_keep_local < rx_ts_info->_FPQ.len) {
761             xfer = rx_ts_info->_FPQ.len - num_keep_local;
762             RX_TS_FPQ_LTOG2(rx_ts_info, xfer);
763             rxi_PacketsUnWait();
764         } else {
765             xfer = num_keep_local - rx_ts_info->_FPQ.len;
766             if ((num_keep_local > rx_TSFPQLocalMax) && !allow_overcommit)
767                 xfer = rx_TSFPQLocalMax - rx_ts_info->_FPQ.len;
768             if (rx_nFreePackets < xfer) {
769                 rxi_MorePacketsNoLock(MAX(xfer - rx_nFreePackets, 4 * rx_initSendWindow));
770             }
771             RX_TS_FPQ_GTOL2(rx_ts_info, xfer);
772         }
773         MUTEX_EXIT(&rx_freePktQ_lock);
774         USERPRI;
775     }
776 }
777
778 void
779 rxi_FlushLocalPacketsTSFPQ(void)
780 {
781     rxi_AdjustLocalPacketsTSFPQ(0, 0);
782 }
783 #endif /* RX_ENABLE_TSFPQ */
784
785 /* Allocate more packets iff we need more continuation buffers */
786 /* In kernel, can't page in memory with interrupts disabled, so we
787  * don't use the event mechanism. */
788 void
789 rx_CheckPackets(void)
790 {
791     if (rxi_NeedMorePackets) {
792         rxi_MorePackets(rx_initSendWindow);
793     }
794 }
795
796 /* In the packet freeing routine below, the assumption is that
797    we want all of the packets to be used equally frequently, so that we
798    don't get packet buffers paging out.  It would be just as valid to
799    assume that we DO want them to page out if not many are being used.
800    In any event, we assume the former, and append the packets to the end
801    of the free list.  */
802 /* This explanation is bogus.  The free list doesn't remain in any kind of
803    useful order for afs_int32: the packets in use get pretty much randomly scattered 
804    across all the pages.  In order to permit unused {packets,bufs} to page out, they
805    must be stored so that packets which are adjacent in memory are adjacent in the 
806    free list.  An array springs rapidly to mind.
807    */
808
809 /* Actually free the packet p. */
810 #ifdef RX_ENABLE_TSFPQ
811 void
812 rxi_FreePacketNoLock(struct rx_packet *p)
813 {
814     register struct rx_ts_info_t * rx_ts_info;
815     dpf(("Free %lx\n", (unsigned long)p));
816
817     RX_TS_INFO_GET(rx_ts_info);
818     RX_TS_FPQ_CHECKIN(rx_ts_info,p);
819     if (rx_ts_info->_FPQ.len > rx_TSFPQLocalMax) {
820         RX_TS_FPQ_LTOG(rx_ts_info);
821     }
822 }
823 #else /* RX_ENABLE_TSFPQ */
824 void
825 rxi_FreePacketNoLock(struct rx_packet *p)
826 {
827     dpf(("Free %lx\n", (unsigned long)p));
828
829     RX_FPQ_MARK_FREE(p);
830     rx_nFreePackets++;
831     queue_Append(&rx_freePacketQueue, p);
832 }
833 #endif /* RX_ENABLE_TSFPQ */
834
835 #ifdef RX_ENABLE_TSFPQ
836 void
837 rxi_FreePacketTSFPQ(struct rx_packet *p, int flush_global)
838 {
839     register struct rx_ts_info_t * rx_ts_info;
840     dpf(("Free %lx\n", (unsigned long)p));
841
842     RX_TS_INFO_GET(rx_ts_info);
843     RX_TS_FPQ_CHECKIN(rx_ts_info,p);
844
845     if (flush_global && (rx_ts_info->_FPQ.len > rx_TSFPQLocalMax)) {
846         NETPRI;
847         MUTEX_ENTER(&rx_freePktQ_lock);
848
849         RX_TS_FPQ_LTOG(rx_ts_info);
850
851         /* Wakeup anyone waiting for packets */
852         rxi_PacketsUnWait();
853
854         MUTEX_EXIT(&rx_freePktQ_lock);
855         USERPRI;
856     }
857 }
858 #endif /* RX_ENABLE_TSFPQ */
859
860 /* 
861  * free continuation buffers off a packet into a queue
862  *
863  * [IN] p      -- packet from which continuation buffers will be freed
864  * [IN] first  -- iovec offset of first continuation buffer to free
865  * [IN] q      -- queue into which continuation buffers will be chained
866  *
867  * returns:
868  *   number of continuation buffers freed
869  */
870 #ifndef RX_ENABLE_TSFPQ
871 static int
872 rxi_FreeDataBufsToQueue(struct rx_packet *p, afs_uint32 first, struct rx_queue * q)
873 {
874     struct iovec *iov;
875     struct rx_packet * cb;
876     int count = 0;
877
878     for (first = MAX(2, first); first < p->niovecs; first++, count++) {
879         iov = &p->wirevec[first];
880         if (!iov->iov_base)
881             osi_Panic("rxi_FreeDataBufsToQueue: unexpected NULL iov");
882         cb = RX_CBUF_TO_PACKET(iov->iov_base, p);
883         RX_FPQ_MARK_FREE(cb);
884         queue_Append(q, cb);
885     }
886     p->length = 0;
887     p->niovecs = 0;
888
889     return count;
890 }
891 #endif
892
893 /*
894  * free packet continuation buffers into the global free packet pool
895  *
896  * [IN] p      -- packet from which to free continuation buffers
897  * [IN] first  -- iovec offset of first continuation buffer to free
898  *
899  * returns:
900  *   zero always
901  */
902 int
903 rxi_FreeDataBufsNoLock(struct rx_packet *p, afs_uint32 first)
904 {
905     struct iovec *iov;
906
907     for (first = MAX(2, first); first < p->niovecs; first++) {
908         iov = &p->wirevec[first];
909         if (!iov->iov_base)
910             osi_Panic("rxi_FreeDataBufsNoLock: unexpected NULL iov");
911         rxi_FreePacketNoLock(RX_CBUF_TO_PACKET(iov->iov_base, p));
912     }
913     p->length = 0;
914     p->niovecs = 0;
915
916     return 0;
917 }
918
919 #ifdef RX_ENABLE_TSFPQ
920 /*
921  * free packet continuation buffers into the thread-local free pool
922  *
923  * [IN] p             -- packet from which continuation buffers will be freed
924  * [IN] first         -- iovec offset of first continuation buffer to free
925  *                       any value less than 2, the min number of iovecs,
926  *                       is treated as if it is 2.
927  * [IN] flush_global  -- if nonzero, we will flush overquota packets to the
928  *                       global free pool before returning
929  *
930  * returns:
931  *   zero always
932  */
933 static int
934 rxi_FreeDataBufsTSFPQ(struct rx_packet *p, afs_uint32 first, int flush_global)
935 {
936     struct iovec *iov;
937     register struct rx_ts_info_t * rx_ts_info;
938
939     RX_TS_INFO_GET(rx_ts_info);
940
941     for (first = MAX(2, first); first < p->niovecs; first++) {
942         iov = &p->wirevec[first];
943         if (!iov->iov_base)
944             osi_Panic("rxi_FreeDataBufsTSFPQ: unexpected NULL iov");
945         RX_TS_FPQ_CHECKIN(rx_ts_info,RX_CBUF_TO_PACKET(iov->iov_base, p));
946     }
947     p->length = 0;
948     p->niovecs = 0;
949
950     if (flush_global && (rx_ts_info->_FPQ.len > rx_TSFPQLocalMax)) {
951         NETPRI;
952         MUTEX_ENTER(&rx_freePktQ_lock);
953
954         RX_TS_FPQ_LTOG(rx_ts_info);
955
956         /* Wakeup anyone waiting for packets */
957         rxi_PacketsUnWait();
958
959         MUTEX_EXIT(&rx_freePktQ_lock);
960         USERPRI;
961     }
962     return 0;
963 }
964 #endif /* RX_ENABLE_TSFPQ */
965
966 int rxi_nBadIovecs = 0;
967
968 /* rxi_RestoreDataBufs 
969  *
970  * Restore the correct sizes to the iovecs. Called when reusing a packet
971  * for reading off the wire.
972  */
973 void
974 rxi_RestoreDataBufs(struct rx_packet *p)
975 {
976     int i;
977     struct iovec *iov = &p->wirevec[2];
978
979     RX_PACKET_IOV_INIT(p);
980
981     for (i = 2, iov = &p->wirevec[2]; i < p->niovecs; i++, iov++) {
982         if (!iov->iov_base) {
983             rxi_nBadIovecs++;
984             p->niovecs = i;
985             break;
986         }
987         iov->iov_len = RX_CBUFFERSIZE;
988     }
989 }
990
991 #ifdef RX_ENABLE_TSFPQ
992 int
993 rxi_TrimDataBufs(struct rx_packet *p, int first)
994 {
995     int length;
996     struct iovec *iov, *end;
997     register struct rx_ts_info_t * rx_ts_info;
998     SPLVAR;
999
1000     if (first != 1)
1001         osi_Panic("TrimDataBufs 1: first must be 1");
1002
1003     /* Skip over continuation buffers containing message data */
1004     iov = &p->wirevec[2];
1005     end = iov + (p->niovecs - 2);
1006     length = p->length - p->wirevec[1].iov_len;
1007     for (; iov < end && length > 0; iov++) {
1008         if (!iov->iov_base)
1009             osi_Panic("TrimDataBufs 3: vecs 1-niovecs must not be NULL");
1010         length -= iov->iov_len;
1011     }
1012
1013     /* iov now points to the first empty data buffer. */
1014     if (iov >= end)
1015         return 0;
1016
1017     RX_TS_INFO_GET(rx_ts_info);
1018     for (; iov < end; iov++) {
1019         if (!iov->iov_base)
1020             osi_Panic("TrimDataBufs 4: vecs 2-niovecs must not be NULL");
1021         RX_TS_FPQ_CHECKIN(rx_ts_info,RX_CBUF_TO_PACKET(iov->iov_base, p));
1022         p->niovecs--;
1023     }
1024     if (rx_ts_info->_FPQ.len > rx_TSFPQLocalMax) {
1025         NETPRI;
1026         MUTEX_ENTER(&rx_freePktQ_lock);
1027
1028         RX_TS_FPQ_LTOG(rx_ts_info);
1029         rxi_PacketsUnWait();
1030
1031         MUTEX_EXIT(&rx_freePktQ_lock);
1032         USERPRI;
1033     }
1034
1035     return 0;
1036 }
1037 #else /* RX_ENABLE_TSFPQ */
1038 int
1039 rxi_TrimDataBufs(struct rx_packet *p, int first)
1040 {
1041     int length;
1042     struct iovec *iov, *end;
1043     SPLVAR;
1044
1045     if (first != 1)
1046         osi_Panic("TrimDataBufs 1: first must be 1");
1047
1048     /* Skip over continuation buffers containing message data */
1049     iov = &p->wirevec[2];
1050     end = iov + (p->niovecs - 2);
1051     length = p->length - p->wirevec[1].iov_len;
1052     for (; iov < end && length > 0; iov++) {
1053         if (!iov->iov_base)
1054             osi_Panic("TrimDataBufs 3: vecs 1-niovecs must not be NULL");
1055         length -= iov->iov_len;
1056     }
1057
1058     /* iov now points to the first empty data buffer. */
1059     if (iov >= end)
1060         return 0;
1061
1062     NETPRI;
1063     MUTEX_ENTER(&rx_freePktQ_lock);
1064
1065     for (; iov < end; iov++) {
1066         if (!iov->iov_base)
1067             osi_Panic("TrimDataBufs 4: vecs 2-niovecs must not be NULL");
1068         rxi_FreePacketNoLock(RX_CBUF_TO_PACKET(iov->iov_base, p));
1069         p->niovecs--;
1070     }
1071     rxi_PacketsUnWait();
1072
1073     MUTEX_EXIT(&rx_freePktQ_lock);
1074     USERPRI;
1075
1076     return 0;
1077 }
1078 #endif /* RX_ENABLE_TSFPQ */
1079
1080 /* Free the packet p.  P is assumed not to be on any queue, i.e.
1081  * remove it yourself first if you call this routine. */
1082 #ifdef RX_ENABLE_TSFPQ
1083 void
1084 rxi_FreePacket(struct rx_packet *p)
1085 {
1086     rxi_FreeDataBufsTSFPQ(p, 2, 0);
1087     rxi_FreePacketTSFPQ(p, RX_TS_FPQ_FLUSH_GLOBAL);
1088 }
1089 #else /* RX_ENABLE_TSFPQ */
1090 void
1091 rxi_FreePacket(struct rx_packet *p)
1092 {
1093     SPLVAR;
1094
1095     NETPRI;
1096     MUTEX_ENTER(&rx_freePktQ_lock);
1097
1098     rxi_FreeDataBufsNoLock(p, 2);
1099     rxi_FreePacketNoLock(p);
1100     /* Wakeup anyone waiting for packets */
1101     rxi_PacketsUnWait();
1102
1103     MUTEX_EXIT(&rx_freePktQ_lock);
1104     USERPRI;
1105 }
1106 #endif /* RX_ENABLE_TSFPQ */
1107
1108 /* rxi_AllocPacket sets up p->length so it reflects the number of 
1109  * bytes in the packet at this point, **not including** the header.
1110  * The header is absolutely necessary, besides, this is the way the
1111  * length field is usually used */
1112 #ifdef RX_ENABLE_TSFPQ
1113 struct rx_packet *
1114 rxi_AllocPacketNoLock(int class)
1115 {
1116     register struct rx_packet *p;
1117     register struct rx_ts_info_t * rx_ts_info;
1118
1119     RX_TS_INFO_GET(rx_ts_info);
1120
1121 #ifdef KERNEL
1122     if (rxi_OverQuota(class)) {
1123         rxi_NeedMorePackets = TRUE;
1124         switch (class) {
1125         case RX_PACKET_CLASS_RECEIVE:
1126             rx_MutexIncrement(rx_stats.receivePktAllocFailures, rx_stats_mutex);
1127             break;
1128         case RX_PACKET_CLASS_SEND:
1129             rx_MutexIncrement(rx_stats.sendPktAllocFailures, rx_stats_mutex);
1130             break;
1131         case RX_PACKET_CLASS_SPECIAL:
1132             rx_MutexIncrement(rx_stats.specialPktAllocFailures, rx_stats_mutex);
1133             break;
1134         case RX_PACKET_CLASS_RECV_CBUF:
1135             rx_MutexIncrement(rx_stats.receiveCbufPktAllocFailures, rx_stats_mutex);
1136             break;
1137         case RX_PACKET_CLASS_SEND_CBUF:
1138             rx_MutexIncrement(rx_stats.sendCbufPktAllocFailures, rx_stats_mutex);
1139             break;
1140         }
1141         return (struct rx_packet *)0;
1142     }
1143 #endif /* KERNEL */
1144
1145     rx_MutexIncrement(rx_stats.packetRequests, rx_stats_mutex);
1146     if (queue_IsEmpty(&rx_ts_info->_FPQ)) {
1147
1148 #ifdef KERNEL
1149         if (queue_IsEmpty(&rx_freePacketQueue))
1150             osi_Panic("rxi_AllocPacket error");
1151 #else /* KERNEL */
1152         if (queue_IsEmpty(&rx_freePacketQueue))
1153             rxi_MorePacketsNoLock(4 * rx_initSendWindow);
1154 #endif /* KERNEL */
1155
1156
1157         RX_TS_FPQ_GTOL(rx_ts_info);
1158     }
1159
1160     RX_TS_FPQ_CHECKOUT(rx_ts_info,p);
1161
1162     dpf(("Alloc %lx, class %d\n", (unsigned long)p, class));
1163
1164
1165     /* have to do this here because rx_FlushWrite fiddles with the iovs in
1166      * order to truncate outbound packets.  In the near future, may need 
1167      * to allocate bufs from a static pool here, and/or in AllocSendPacket
1168      */
1169     RX_PACKET_IOV_FULLINIT(p);
1170     return p;
1171 }
1172 #else /* RX_ENABLE_TSFPQ */
1173 struct rx_packet *
1174 rxi_AllocPacketNoLock(int class)
1175 {
1176     register struct rx_packet *p;
1177
1178 #ifdef KERNEL
1179     if (rxi_OverQuota(class)) {
1180         rxi_NeedMorePackets = TRUE;
1181         switch (class) {
1182         case RX_PACKET_CLASS_RECEIVE:
1183             rx_MutexIncrement(rx_stats.receivePktAllocFailures, rx_stats_mutex);
1184             break;
1185         case RX_PACKET_CLASS_SEND:
1186             rx_MutexIncrement(rx_stats.sendPktAllocFailures, rx_stats_mutex);
1187             break;
1188         case RX_PACKET_CLASS_SPECIAL:
1189             rx_MutexIncrement(rx_stats.specialPktAllocFailures, rx_stats_mutex);
1190             break;
1191         case RX_PACKET_CLASS_RECV_CBUF:
1192             rx_MutexIncrement(rx_stats.receiveCbufPktAllocFailures, rx_stats_mutex);
1193             break;
1194         case RX_PACKET_CLASS_SEND_CBUF:
1195             rx_MutexIncrement(rx_stats.sendCbufPktAllocFailures, rx_stats_mutex);
1196             break;
1197         }
1198         return (struct rx_packet *)0;
1199     }
1200 #endif /* KERNEL */
1201
1202     rx_MutexIncrement(rx_stats.packetRequests, rx_stats_mutex);
1203
1204 #ifdef KERNEL
1205     if (queue_IsEmpty(&rx_freePacketQueue))
1206         osi_Panic("rxi_AllocPacket error");
1207 #else /* KERNEL */
1208     if (queue_IsEmpty(&rx_freePacketQueue))
1209         rxi_MorePacketsNoLock(4 * rx_initSendWindow);
1210 #endif /* KERNEL */
1211
1212     rx_nFreePackets--;
1213     p = queue_First(&rx_freePacketQueue, rx_packet);
1214     queue_Remove(p);
1215     RX_FPQ_MARK_USED(p);
1216
1217     dpf(("Alloc %lx, class %d\n", (unsigned long)p, class));
1218
1219
1220     /* have to do this here because rx_FlushWrite fiddles with the iovs in
1221      * order to truncate outbound packets.  In the near future, may need 
1222      * to allocate bufs from a static pool here, and/or in AllocSendPacket
1223      */
1224     RX_PACKET_IOV_FULLINIT(p);
1225     return p;
1226 }
1227 #endif /* RX_ENABLE_TSFPQ */
1228
1229 #ifdef RX_ENABLE_TSFPQ
1230 struct rx_packet *
1231 rxi_AllocPacketTSFPQ(int class, int pull_global)
1232 {
1233     register struct rx_packet *p;
1234     register struct rx_ts_info_t * rx_ts_info;
1235
1236     RX_TS_INFO_GET(rx_ts_info);
1237
1238     rx_MutexIncrement(rx_stats.packetRequests, rx_stats_mutex);
1239     if (pull_global && queue_IsEmpty(&rx_ts_info->_FPQ)) {
1240         MUTEX_ENTER(&rx_freePktQ_lock);
1241
1242         if (queue_IsEmpty(&rx_freePacketQueue))
1243             rxi_MorePacketsNoLock(4 * rx_initSendWindow);
1244
1245         RX_TS_FPQ_GTOL(rx_ts_info);
1246
1247         MUTEX_EXIT(&rx_freePktQ_lock);
1248     } else if (queue_IsEmpty(&rx_ts_info->_FPQ)) {
1249         return NULL;
1250     }
1251
1252     RX_TS_FPQ_CHECKOUT(rx_ts_info,p);
1253
1254     dpf(("Alloc %lx, class %d\n", (unsigned long)p, class));
1255
1256     /* have to do this here because rx_FlushWrite fiddles with the iovs in
1257      * order to truncate outbound packets.  In the near future, may need 
1258      * to allocate bufs from a static pool here, and/or in AllocSendPacket
1259      */
1260     RX_PACKET_IOV_FULLINIT(p);
1261     return p;
1262 }
1263 #endif /* RX_ENABLE_TSFPQ */
1264
1265 #ifdef RX_ENABLE_TSFPQ
1266 struct rx_packet *
1267 rxi_AllocPacket(int class)
1268 {
1269     register struct rx_packet *p;
1270
1271     p = rxi_AllocPacketTSFPQ(class, RX_TS_FPQ_PULL_GLOBAL);
1272     return p;
1273 }
1274 #else /* RX_ENABLE_TSFPQ */
1275 struct rx_packet *
1276 rxi_AllocPacket(int class)
1277 {
1278     register struct rx_packet *p;
1279
1280     MUTEX_ENTER(&rx_freePktQ_lock);
1281     p = rxi_AllocPacketNoLock(class);
1282     MUTEX_EXIT(&rx_freePktQ_lock);
1283     return p;
1284 }
1285 #endif /* RX_ENABLE_TSFPQ */
1286
1287 /* This guy comes up with as many buffers as it {takes,can get} given
1288  * the MTU for this call. It also sets the packet length before
1289  * returning.  caution: this is often called at NETPRI
1290  * Called with call locked.
1291  */
1292 struct rx_packet *
1293 rxi_AllocSendPacket(register struct rx_call *call, int want)
1294 {
1295     register struct rx_packet *p = (struct rx_packet *)0;
1296     register int mud;
1297     register unsigned delta;
1298
1299     SPLVAR;
1300     mud = call->MTU - RX_HEADER_SIZE;
1301     delta =
1302         rx_GetSecurityHeaderSize(rx_ConnectionOf(call)) +
1303         rx_GetSecurityMaxTrailerSize(rx_ConnectionOf(call));
1304
1305 #ifdef RX_ENABLE_TSFPQ
1306     if ((p = rxi_AllocPacketTSFPQ(RX_PACKET_CLASS_SEND, 0))) {
1307         want += delta;
1308         want = MIN(want, mud);
1309
1310         if ((unsigned)want > p->length)
1311             (void)rxi_AllocDataBuf(p, (want - p->length),
1312                                    RX_PACKET_CLASS_SEND_CBUF);
1313
1314         if ((unsigned)p->length > mud)
1315             p->length = mud;
1316
1317         if (delta >= p->length) {
1318             rxi_FreePacket(p);
1319             p = NULL;
1320         } else {
1321             p->length -= delta;
1322         }
1323         return p;
1324     }
1325 #endif /* RX_ENABLE_TSFPQ */
1326
1327     while (!(call->error)) {
1328         MUTEX_ENTER(&rx_freePktQ_lock);
1329         /* if an error occurred, or we get the packet we want, we're done */
1330         if ((p = rxi_AllocPacketNoLock(RX_PACKET_CLASS_SEND))) {
1331             MUTEX_EXIT(&rx_freePktQ_lock);
1332
1333             want += delta;
1334             want = MIN(want, mud);
1335
1336             if ((unsigned)want > p->length)
1337                 (void)rxi_AllocDataBuf(p, (want - p->length),
1338                                        RX_PACKET_CLASS_SEND_CBUF);
1339
1340             if ((unsigned)p->length > mud)
1341                 p->length = mud;
1342
1343             if (delta >= p->length) {
1344                 rxi_FreePacket(p);
1345                 p = NULL;
1346             } else {
1347                 p->length -= delta;
1348             }
1349             break;
1350         }
1351
1352         /* no error occurred, and we didn't get a packet, so we sleep.
1353          * At this point, we assume that packets will be returned
1354          * sooner or later, as packets are acknowledged, and so we
1355          * just wait.  */
1356         NETPRI;
1357         call->flags |= RX_CALL_WAIT_PACKETS;
1358         CALL_HOLD(call, RX_CALL_REFCOUNT_PACKET);
1359         MUTEX_EXIT(&call->lock);
1360         rx_waitingForPackets = 1;
1361
1362 #ifdef  RX_ENABLE_LOCKS
1363         CV_WAIT(&rx_waitingForPackets_cv, &rx_freePktQ_lock);
1364 #else
1365         osi_rxSleep(&rx_waitingForPackets);
1366 #endif
1367         MUTEX_EXIT(&rx_freePktQ_lock);
1368         MUTEX_ENTER(&call->lock);
1369         CALL_RELE(call, RX_CALL_REFCOUNT_PACKET);
1370         call->flags &= ~RX_CALL_WAIT_PACKETS;
1371         USERPRI;
1372     }
1373
1374     return p;
1375 }
1376
1377 #ifndef KERNEL
1378 #ifdef AFS_NT40_ENV      
1379 /* Windows does not use file descriptors. */
1380 #define CountFDs(amax) 0
1381 #else
1382 /* count the number of used FDs */
1383 static int
1384 CountFDs(register int amax)
1385 {
1386     struct stat tstat;
1387     register int i, code;
1388     register int count;
1389
1390     count = 0;
1391     for (i = 0; i < amax; i++) {
1392         code = fstat(i, &tstat);
1393         if (code == 0)
1394             count++;
1395     }
1396     return count;
1397 }
1398 #endif /* AFS_NT40_ENV */
1399 #else /* KERNEL */
1400
1401 #define CountFDs(amax) amax
1402
1403 #endif /* KERNEL */
1404
1405 #if !defined(KERNEL) || defined(UKERNEL)
1406
1407 /* This function reads a single packet from the interface into the
1408  * supplied packet buffer (*p).  Return 0 if the packet is bogus.  The
1409  * (host,port) of the sender are stored in the supplied variables, and
1410  * the data length of the packet is stored in the packet structure.
1411  * The header is decoded. */
1412 int
1413 rxi_ReadPacket(osi_socket socket, register struct rx_packet *p, afs_uint32 * host,
1414                u_short * port)
1415 {
1416     struct sockaddr_in from;
1417     int nbytes;
1418     afs_int32 rlen;
1419     register afs_int32 tlen, savelen;
1420     struct msghdr msg;
1421     rx_computelen(p, tlen);
1422     rx_SetDataSize(p, tlen);    /* this is the size of the user data area */
1423
1424     tlen += RX_HEADER_SIZE;     /* now this is the size of the entire packet */
1425     rlen = rx_maxJumboRecvSize; /* this is what I am advertising.  Only check
1426                                  * it once in order to avoid races.  */
1427     tlen = rlen - tlen;
1428     if (tlen > 0) {
1429         tlen = rxi_AllocDataBuf(p, tlen, RX_PACKET_CLASS_SEND_CBUF);
1430         if (tlen > 0) {
1431             tlen = rlen - tlen;
1432         } else
1433             tlen = rlen;
1434     } else
1435         tlen = rlen;
1436
1437     /* Extend the last iovec for padding, it's just to make sure that the 
1438      * read doesn't return more data than we expect, and is done to get around
1439      * our problems caused by the lack of a length field in the rx header.
1440      * Use the extra buffer that follows the localdata in each packet
1441      * structure. */
1442     savelen = p->wirevec[p->niovecs - 1].iov_len;
1443     p->wirevec[p->niovecs - 1].iov_len += RX_EXTRABUFFERSIZE;
1444
1445     memset((char *)&msg, 0, sizeof(msg));
1446     msg.msg_name = (char *)&from;
1447     msg.msg_namelen = sizeof(struct sockaddr_in);
1448     msg.msg_iov = p->wirevec;
1449     msg.msg_iovlen = p->niovecs;
1450     nbytes = rxi_Recvmsg(socket, &msg, 0);
1451
1452     /* restore the vec to its correct state */
1453     p->wirevec[p->niovecs - 1].iov_len = savelen;
1454
1455     p->length = (nbytes - RX_HEADER_SIZE);
1456     if ((nbytes > tlen) || (p->length & 0x8000)) {      /* Bogus packet */
1457         if (nbytes < 0 && errno == EWOULDBLOCK) {
1458             rx_MutexIncrement(rx_stats.noPacketOnRead, rx_stats_mutex);
1459         } else if (nbytes <= 0) {
1460             MUTEX_ENTER(&rx_stats_mutex);
1461             rx_stats.bogusPacketOnRead++;
1462             rx_stats.bogusHost = from.sin_addr.s_addr;
1463             MUTEX_EXIT(&rx_stats_mutex);
1464             dpf(("B: bogus packet from [%x,%d] nb=%d", ntohl(from.sin_addr.s_addr),
1465                  ntohs(from.sin_port), nbytes));
1466         }
1467         return 0;
1468     } 
1469 #ifdef RXDEBUG
1470     else if ((rx_intentionallyDroppedOnReadPer100 > 0)
1471                 && (random() % 100 < rx_intentionallyDroppedOnReadPer100)) {
1472         rxi_DecodePacketHeader(p);
1473
1474         *host = from.sin_addr.s_addr;
1475         *port = from.sin_port;
1476
1477         dpf(("Dropped %d %s: %x.%u.%u.%u.%u.%u.%u flags %d len %d",
1478               p->header.serial, rx_packetTypes[p->header.type - 1], ntohl(*host), ntohs(*port), p->header.serial, 
1479               p->header.epoch, p->header.cid, p->header.callNumber, p->header.seq, p->header.flags, 
1480               p->length));
1481         rxi_TrimDataBufs(p, 1);
1482         return 0;
1483     } 
1484 #endif
1485     else {
1486         /* Extract packet header. */
1487         rxi_DecodePacketHeader(p);
1488
1489         *host = from.sin_addr.s_addr;
1490         *port = from.sin_port;
1491         if (p->header.type > 0 && p->header.type < RX_N_PACKET_TYPES) {
1492             struct rx_peer *peer;
1493             rx_MutexIncrement(rx_stats.packetsRead[p->header.type - 1], rx_stats_mutex);
1494             /*
1495              * Try to look up this peer structure.  If it doesn't exist,
1496              * don't create a new one - 
1497              * we don't keep count of the bytes sent/received if a peer
1498              * structure doesn't already exist.
1499              *
1500              * The peer/connection cleanup code assumes that there is 1 peer
1501              * per connection.  If we actually created a peer structure here
1502              * and this packet was an rxdebug packet, the peer structure would
1503              * never be cleaned up.
1504              */
1505             peer = rxi_FindPeer(*host, *port, 0, 0);
1506             /* Since this may not be associated with a connection,
1507              * it may have no refCount, meaning we could race with
1508              * ReapConnections
1509              */
1510             if (peer && (peer->refCount > 0)) {
1511                 MUTEX_ENTER(&peer->peer_lock);
1512                 hadd32(peer->bytesReceived, p->length);
1513                 MUTEX_EXIT(&peer->peer_lock);
1514             }
1515         }
1516
1517         /* Free any empty packet buffers at the end of this packet */
1518         rxi_TrimDataBufs(p, 1);
1519
1520         return 1;
1521     }
1522 }
1523
1524 #endif /* !KERNEL || UKERNEL */
1525
1526 /* This function splits off the first packet in a jumbo packet.
1527  * As of AFS 3.5, jumbograms contain more than one fixed size
1528  * packet, and the RX_JUMBO_PACKET flag is set in all but the
1529  * last packet header. All packets (except the last) are padded to
1530  * fall on RX_CBUFFERSIZE boundaries.
1531  * HACK: We store the length of the first n-1 packets in the
1532  * last two pad bytes. */
1533
1534 struct rx_packet *
1535 rxi_SplitJumboPacket(register struct rx_packet *p, afs_int32 host, short port,
1536                      int first)
1537 {
1538     struct rx_packet *np;
1539     struct rx_jumboHeader *jp;
1540     int niov, i;
1541     struct iovec *iov;
1542     int length;
1543     afs_uint32 temp;
1544
1545     /* All but the last packet in each jumbogram are RX_JUMBOBUFFERSIZE
1546      * bytes in length. All but the first packet are preceded by
1547      * an abbreviated four byte header. The length of the last packet
1548      * is calculated from the size of the jumbogram. */
1549     length = RX_JUMBOBUFFERSIZE + RX_JUMBOHEADERSIZE;
1550
1551     if ((int)p->length < length) {
1552         dpf(("rxi_SplitJumboPacket: bogus length %d\n", p->length));
1553         return NULL;
1554     }
1555     niov = p->niovecs - 2;
1556     if (niov < 1) {
1557         dpf(("rxi_SplitJumboPacket: bogus niovecs %d\n", p->niovecs));
1558         return NULL;
1559     }
1560     iov = &p->wirevec[2];
1561     np = RX_CBUF_TO_PACKET(iov->iov_base, p);
1562
1563     /* Get a pointer to the abbreviated packet header */
1564     jp = (struct rx_jumboHeader *)
1565         ((char *)(p->wirevec[1].iov_base) + RX_JUMBOBUFFERSIZE);
1566
1567     /* Set up the iovecs for the next packet */
1568     np->wirevec[0].iov_base = (char *)(&np->wirehead[0]);
1569     np->wirevec[0].iov_len = sizeof(struct rx_header);
1570     np->wirevec[1].iov_base = (char *)(&np->localdata[0]);
1571     np->wirevec[1].iov_len = length - RX_JUMBOHEADERSIZE;
1572     np->niovecs = niov + 1;
1573     for (i = 2, iov++; i <= niov; i++, iov++) {
1574         np->wirevec[i] = *iov;
1575     }
1576     np->length = p->length - length;
1577     p->length = RX_JUMBOBUFFERSIZE;
1578     p->niovecs = 2;
1579
1580     /* Convert the jumbo packet header to host byte order */
1581     temp = ntohl(*(afs_uint32 *) jp);
1582     jp->flags = (u_char) (temp >> 24);
1583     jp->cksum = (u_short) (temp);
1584
1585     /* Fill in the packet header */
1586     np->header = p->header;
1587     np->header.serial = p->header.serial + 1;
1588     np->header.seq = p->header.seq + 1;
1589     np->header.flags = jp->flags;
1590     np->header.spare = jp->cksum;
1591
1592     return np;
1593 }
1594
1595 #ifndef KERNEL
1596 /* Send a udp datagram */
1597 int
1598 osi_NetSend(osi_socket socket, void *addr, struct iovec *dvec, int nvecs,
1599             int length, int istack)
1600 {
1601     struct msghdr msg;
1602         int ret;
1603
1604     memset(&msg, 0, sizeof(msg));
1605     msg.msg_iov = dvec;
1606     msg.msg_iovlen = nvecs;
1607     msg.msg_name = addr;
1608     msg.msg_namelen = sizeof(struct sockaddr_in);
1609
1610     ret = rxi_Sendmsg(socket, &msg, 0);
1611
1612     return ret;
1613 }
1614 #elif !defined(UKERNEL)
1615 /*
1616  * message receipt is done in rxk_input or rx_put.
1617  */
1618
1619 #if defined(AFS_SUN5_ENV) || defined(AFS_HPUX110_ENV)
1620 /*
1621  * Copy an mblock to the contiguous area pointed to by cp.
1622  * MTUXXX Supposed to skip <off> bytes and copy <len> bytes,
1623  * but it doesn't really.
1624  * Returns the number of bytes not transferred.
1625  * The message is NOT changed.
1626  */
1627 static int
1628 cpytoc(mblk_t * mp, register int off, register int len, register char *cp)
1629 {
1630     register int n;
1631
1632     for (; mp && len > 0; mp = mp->b_cont) {
1633         if (mp->b_datap->db_type != M_DATA) {
1634             return -1;
1635         }
1636         n = MIN(len, (mp->b_wptr - mp->b_rptr));
1637         memcpy(cp, (char *)mp->b_rptr, n);
1638         cp += n;
1639         len -= n;
1640         mp->b_rptr += n;
1641     }
1642     return (len);
1643 }
1644
1645 /* MTUXXX Supposed to skip <off> bytes and copy <len> bytes,
1646  * but it doesn't really.  
1647  * This sucks, anyway, do it like m_cpy.... below 
1648  */
1649 static int
1650 cpytoiovec(mblk_t * mp, int off, int len, register struct iovec *iovs,
1651            int niovs)
1652 {
1653     register int m, n, o, t, i;
1654
1655     for (i = -1, t = 0; i < niovs && mp && len > 0; mp = mp->b_cont) {
1656         if (mp->b_datap->db_type != M_DATA) {
1657             return -1;
1658         }
1659         n = MIN(len, (mp->b_wptr - mp->b_rptr));
1660         len -= n;
1661         while (n) {
1662             if (!t) {
1663                 o = 0;
1664                 i++;
1665                 t = iovs[i].iov_len;
1666             }
1667             m = MIN(n, t);
1668             memcpy(iovs[i].iov_base + o, (char *)mp->b_rptr, m);
1669             mp->b_rptr += m;
1670             o += m;
1671             t -= m;
1672             n -= m;
1673         }
1674     }
1675     return (len);
1676 }
1677
1678 #define m_cpytoc(a, b, c, d)  cpytoc(a, b, c, d)
1679 #define m_cpytoiovec(a, b, c, d, e) cpytoiovec(a, b, c, d, e)
1680 #else
1681 #if !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN80_ENV)
1682 static int
1683 m_cpytoiovec(struct mbuf *m, int off, int len, struct iovec iovs[], int niovs)
1684 {
1685     caddr_t p1, p2;
1686     unsigned int l1, l2, i, t;
1687
1688     if (m == NULL || off < 0 || len < 0 || iovs == NULL)
1689         osi_Panic("m_cpytoiovec");      /* MTUXXX probably don't need this check */
1690
1691     while (off && m)
1692         if (m->m_len <= off) {
1693             off -= m->m_len;
1694             m = m->m_next;
1695             continue;
1696         } else
1697             break;
1698
1699     if (m == NULL)
1700         return len;
1701
1702     p1 = mtod(m, caddr_t) + off;
1703     l1 = m->m_len - off;
1704     i = 0;
1705     p2 = iovs[0].iov_base;
1706     l2 = iovs[0].iov_len;
1707
1708     while (len) {
1709         t = MIN(l1, MIN(l2, (unsigned int)len));
1710         memcpy(p2, p1, t);
1711         p1 += t;
1712         p2 += t;
1713         l1 -= t;
1714         l2 -= t;
1715         len -= t;
1716         if (!l1) {
1717             m = m->m_next;
1718             if (!m)
1719                 break;
1720             p1 = mtod(m, caddr_t);
1721             l1 = m->m_len;
1722         }
1723         if (!l2) {
1724             if (++i >= niovs)
1725                 break;
1726             p2 = iovs[i].iov_base;
1727             l2 = iovs[i].iov_len;
1728         }
1729
1730     }
1731
1732     return len;
1733 }
1734 #endif /* LINUX */
1735 #endif /* AFS_SUN5_ENV */
1736
1737 #if !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN80_ENV)
1738 int
1739 rx_mb_to_packet(amb, free, hdr_len, data_len, phandle)
1740 #if defined(AFS_SUN5_ENV) || defined(AFS_HPUX110_ENV)
1741      mblk_t *amb;
1742 #else
1743      struct mbuf *amb;
1744 #endif
1745      void (*free) ();
1746      struct rx_packet *phandle;
1747      int hdr_len, data_len;
1748 {
1749     register int code;
1750
1751     code =
1752         m_cpytoiovec(amb, hdr_len, data_len, phandle->wirevec,
1753                      phandle->niovecs);
1754     (*free) (amb);
1755
1756     return code;
1757 }
1758 #endif /* LINUX */
1759 #endif /*KERNEL && !UKERNEL */
1760
1761
1762 /* send a response to a debug packet */
1763
1764 struct rx_packet *
1765 rxi_ReceiveDebugPacket(register struct rx_packet *ap, osi_socket asocket,
1766                        afs_int32 ahost, short aport, int istack)
1767 {
1768     struct rx_debugIn tin;
1769     afs_int32 tl;
1770     struct rx_serverQueueEntry *np, *nqe;
1771
1772     /*
1773      * Only respond to client-initiated Rx debug packets,
1774      * and clear the client flag in the response.
1775      */
1776     if (ap->header.flags & RX_CLIENT_INITIATED) {
1777         ap->header.flags = ap->header.flags & ~RX_CLIENT_INITIATED;
1778         rxi_EncodePacketHeader(ap);
1779     } else {
1780         return ap;
1781     }
1782
1783     rx_packetread(ap, 0, sizeof(struct rx_debugIn), (char *)&tin);
1784     /* all done with packet, now set length to the truth, so we can 
1785      * reuse this packet */
1786     rx_computelen(ap, ap->length);
1787
1788     tin.type = ntohl(tin.type);
1789     tin.index = ntohl(tin.index);
1790     switch (tin.type) {
1791     case RX_DEBUGI_GETSTATS:{
1792             struct rx_debugStats tstat;
1793
1794             /* get basic stats */
1795             memset((char *)&tstat, 0, sizeof(tstat));   /* make sure spares are zero */
1796             tstat.version = RX_DEBUGI_VERSION;
1797 #ifndef RX_ENABLE_LOCKS
1798             tstat.waitingForPackets = rx_waitingForPackets;
1799 #endif
1800             MUTEX_ENTER(&rx_serverPool_lock);
1801             tstat.nFreePackets = htonl(rx_nFreePackets);
1802             tstat.nPackets = htonl(rx_nPackets);
1803             tstat.callsExecuted = htonl(rxi_nCalls);
1804             tstat.packetReclaims = htonl(rx_packetReclaims);
1805             tstat.usedFDs = CountFDs(64);
1806             tstat.nWaiting = htonl(rx_nWaiting);
1807             tstat.nWaited = htonl(rx_nWaited);
1808             queue_Count(&rx_idleServerQueue, np, nqe, rx_serverQueueEntry,
1809                         tstat.idleThreads);
1810             MUTEX_EXIT(&rx_serverPool_lock);
1811             tstat.idleThreads = htonl(tstat.idleThreads);
1812             tl = sizeof(struct rx_debugStats) - ap->length;
1813             if (tl > 0)
1814                 tl = rxi_AllocDataBuf(ap, tl, RX_PACKET_CLASS_SEND_CBUF);
1815
1816             if (tl <= 0) {
1817                 rx_packetwrite(ap, 0, sizeof(struct rx_debugStats),
1818                                (char *)&tstat);
1819                 ap->length = sizeof(struct rx_debugStats);
1820                 rxi_SendDebugPacket(ap, asocket, ahost, aport, istack);
1821                 rx_computelen(ap, ap->length);
1822             }
1823             break;
1824         }
1825
1826     case RX_DEBUGI_GETALLCONN:
1827     case RX_DEBUGI_GETCONN:{
1828             int i, j;
1829             register struct rx_connection *tc;
1830             struct rx_call *tcall;
1831             struct rx_debugConn tconn;
1832             int all = (tin.type == RX_DEBUGI_GETALLCONN);
1833
1834
1835             tl = sizeof(struct rx_debugConn) - ap->length;
1836             if (tl > 0)
1837                 tl = rxi_AllocDataBuf(ap, tl, RX_PACKET_CLASS_SEND_CBUF);
1838             if (tl > 0)
1839                 return ap;
1840
1841             memset((char *)&tconn, 0, sizeof(tconn));   /* make sure spares are zero */
1842             /* get N'th (maybe) "interesting" connection info */
1843             for (i = 0; i < rx_hashTableSize; i++) {
1844 #if !defined(KERNEL)
1845                 /* the time complexity of the algorithm used here
1846                  * exponentially increses with the number of connections.
1847                  */
1848 #ifdef AFS_PTHREAD_ENV
1849                 pthread_yield();
1850 #else
1851                 (void)IOMGR_Poll();
1852 #endif
1853 #endif
1854                 RWLOCK_RDLOCK(&rx_connHashTable_lock);
1855                 /* We might be slightly out of step since we are not 
1856                  * locking each call, but this is only debugging output.
1857                  */
1858                 for (tc = rx_connHashTable[i]; tc; tc = tc->next) {
1859                     if ((all || rxi_IsConnInteresting(tc))
1860                         && tin.index-- <= 0) {
1861                         tconn.host = tc->peer->host;
1862                         tconn.port = tc->peer->port;
1863                         tconn.cid = htonl(tc->cid);
1864                         tconn.epoch = htonl(tc->epoch);
1865                         tconn.serial = htonl(tc->serial);
1866                         for (j = 0; j < RX_MAXCALLS; j++) {
1867                             tconn.callNumber[j] = htonl(tc->callNumber[j]);
1868                             if ((tcall = tc->call[j])) {
1869                                 tconn.callState[j] = tcall->state;
1870                                 tconn.callMode[j] = tcall->mode;
1871                                 tconn.callFlags[j] = tcall->flags;
1872                                 if (queue_IsNotEmpty(&tcall->rq))
1873                                     tconn.callOther[j] |= RX_OTHER_IN;
1874                                 if (queue_IsNotEmpty(&tcall->tq))
1875                                     tconn.callOther[j] |= RX_OTHER_OUT;
1876                             } else
1877                                 tconn.callState[j] = RX_STATE_NOTINIT;
1878                         }
1879
1880                         tconn.natMTU = htonl(tc->peer->natMTU);
1881                         tconn.error = htonl(tc->error);
1882                         tconn.flags = tc->flags;
1883                         tconn.type = tc->type;
1884                         tconn.securityIndex = tc->securityIndex;
1885                         if (tc->securityObject) {
1886                             RXS_GetStats(tc->securityObject, tc,
1887                                          &tconn.secStats);
1888 #define DOHTONL(a) (tconn.secStats.a = htonl(tconn.secStats.a))
1889 #define DOHTONS(a) (tconn.secStats.a = htons(tconn.secStats.a))
1890                             DOHTONL(flags);
1891                             DOHTONL(expires);
1892                             DOHTONL(packetsReceived);
1893                             DOHTONL(packetsSent);
1894                             DOHTONL(bytesReceived);
1895                             DOHTONL(bytesSent);
1896                             for (i = 0;
1897                                  i <
1898                                  sizeof(tconn.secStats.spares) /
1899                                  sizeof(short); i++)
1900                                 DOHTONS(spares[i]);
1901                             for (i = 0;
1902                                  i <
1903                                  sizeof(tconn.secStats.sparel) /
1904                                  sizeof(afs_int32); i++)
1905                                 DOHTONL(sparel[i]);
1906                         }
1907                         
1908                         RWLOCK_UNLOCK(&rx_connHashTable_lock);
1909                         rx_packetwrite(ap, 0, sizeof(struct rx_debugConn),
1910                                        (char *)&tconn);
1911                         tl = ap->length;
1912                         ap->length = sizeof(struct rx_debugConn);
1913                         rxi_SendDebugPacket(ap, asocket, ahost, aport,
1914                                             istack);
1915                         ap->length = tl;
1916                         return ap;
1917                     }
1918                 }
1919                 RWLOCK_UNLOCK(&rx_connHashTable_lock);
1920             }
1921             /* if we make it here, there are no interesting packets */
1922             tconn.cid = htonl(0xffffffff);      /* means end */
1923             rx_packetwrite(ap, 0, sizeof(struct rx_debugConn),
1924                            (char *)&tconn);
1925             tl = ap->length;
1926             ap->length = sizeof(struct rx_debugConn);
1927             rxi_SendDebugPacket(ap, asocket, ahost, aport, istack);
1928             ap->length = tl;
1929             break;
1930         }
1931
1932         /*
1933          * Pass back all the peer structures we have available
1934          */
1935
1936     case RX_DEBUGI_GETPEER:{
1937             int i;
1938             register struct rx_peer *tp;
1939             struct rx_debugPeer tpeer;
1940
1941
1942             tl = sizeof(struct rx_debugPeer) - ap->length;
1943             if (tl > 0)
1944                 tl = rxi_AllocDataBuf(ap, tl, RX_PACKET_CLASS_SEND_CBUF);
1945             if (tl > 0)
1946                 return ap;
1947
1948             memset((char *)&tpeer, 0, sizeof(tpeer));
1949             for (i = 0; i < rx_hashTableSize; i++) {
1950 #if !defined(KERNEL)
1951                 /* the time complexity of the algorithm used here
1952                  * exponentially increses with the number of peers.
1953                  *
1954                  * Yielding after processing each hash table entry
1955                  * and dropping rx_peerHashTable_lock.
1956                  * also increases the risk that we will miss a new
1957                  * entry - but we are willing to live with this
1958                  * limitation since this is meant for debugging only
1959                  */
1960 #ifdef AFS_PTHREAD_ENV
1961                 pthread_yield();
1962 #else
1963                 (void)IOMGR_Poll();
1964 #endif
1965 #endif
1966                 RWLOCK_RDLOCK(&rx_peerHashTable_lock);
1967                 /* XXX should copy out, then unlock and byteswap */
1968                 for (tp = rx_peerHashTable[i]; tp; tp = tp->next) {
1969                     if (tin.index-- <= 0) {
1970                         tpeer.host = tp->host;
1971                         tpeer.port = tp->port;
1972                         tpeer.ifMTU = htons(tp->ifMTU);
1973                         tpeer.idleWhen = htonl(tp->idleWhen);
1974                         tpeer.refCount = htons(tp->refCount);
1975                         tpeer.burstSize = tp->burstSize;
1976                         tpeer.burst = tp->burst;
1977                         tpeer.burstWait.sec = htonl(tp->burstWait.sec);
1978                         tpeer.burstWait.usec = htonl(tp->burstWait.usec);
1979                         tpeer.rtt = htonl(tp->rtt);
1980                         tpeer.rtt_dev = htonl(tp->rtt_dev);
1981                         tpeer.timeout.sec = htonl(tp->timeout.sec);
1982                         tpeer.timeout.usec = htonl(tp->timeout.usec);
1983                         tpeer.nSent = htonl(tp->nSent);
1984                         tpeer.reSends = htonl(tp->reSends);
1985                         tpeer.inPacketSkew = htonl(tp->inPacketSkew);
1986                         tpeer.outPacketSkew = htonl(tp->outPacketSkew);
1987                         tpeer.rateFlag = htonl(tp->rateFlag);
1988                         tpeer.natMTU = htons(tp->natMTU);
1989                         tpeer.maxMTU = htons(tp->maxMTU);
1990                         tpeer.maxDgramPackets = htons(tp->maxDgramPackets);
1991                         tpeer.ifDgramPackets = htons(tp->ifDgramPackets);
1992                         tpeer.MTU = htons(tp->MTU);
1993                         tpeer.cwind = htons(tp->cwind);
1994                         tpeer.nDgramPackets = htons(tp->nDgramPackets);
1995                         tpeer.congestSeq = htons(tp->congestSeq);
1996                         tpeer.bytesSent.high = htonl(tp->bytesSent.high);
1997                         tpeer.bytesSent.low = htonl(tp->bytesSent.low);
1998                         tpeer.bytesReceived.high =
1999                             htonl(tp->bytesReceived.high);
2000                         tpeer.bytesReceived.low =
2001                             htonl(tp->bytesReceived.low);
2002
2003                         RWLOCK_UNLOCK(&rx_peerHashTable_lock);
2004                         rx_packetwrite(ap, 0, sizeof(struct rx_debugPeer),
2005                                        (char *)&tpeer);
2006                         tl = ap->length;
2007                         ap->length = sizeof(struct rx_debugPeer);
2008                         rxi_SendDebugPacket(ap, asocket, ahost, aport,
2009                                             istack);
2010                         ap->length = tl;
2011                         return ap;
2012                     }
2013                 }
2014                 RWLOCK_UNLOCK(&rx_peerHashTable_lock);
2015             }
2016             /* if we make it here, there are no interesting packets */
2017             tpeer.host = htonl(0xffffffff);     /* means end */
2018             rx_packetwrite(ap, 0, sizeof(struct rx_debugPeer),
2019                            (char *)&tpeer);
2020             tl = ap->length;
2021             ap->length = sizeof(struct rx_debugPeer);
2022             rxi_SendDebugPacket(ap, asocket, ahost, aport, istack);
2023             ap->length = tl;
2024             break;
2025         }
2026
2027     case RX_DEBUGI_RXSTATS:{
2028             int i;
2029             afs_int32 *s;
2030
2031             tl = sizeof(rx_stats) - ap->length;
2032             if (tl > 0)
2033                 tl = rxi_AllocDataBuf(ap, tl, RX_PACKET_CLASS_SEND_CBUF);
2034             if (tl > 0)
2035                 return ap;
2036
2037             /* Since its all int32s convert to network order with a loop. */
2038             MUTEX_ENTER(&rx_stats_mutex);
2039             s = (afs_int32 *) & rx_stats;
2040             for (i = 0; i < sizeof(rx_stats) / sizeof(afs_int32); i++, s++)
2041                 rx_PutInt32(ap, i * sizeof(afs_int32), htonl(*s));
2042
2043             tl = ap->length;
2044             ap->length = sizeof(rx_stats);
2045             MUTEX_EXIT(&rx_stats_mutex);
2046             rxi_SendDebugPacket(ap, asocket, ahost, aport, istack);
2047             ap->length = tl;
2048             break;
2049         }
2050
2051     default:
2052         /* error response packet */
2053         tin.type = htonl(RX_DEBUGI_BADTYPE);
2054         tin.index = tin.type;
2055         rx_packetwrite(ap, 0, sizeof(struct rx_debugIn), (char *)&tin);
2056         tl = ap->length;
2057         ap->length = sizeof(struct rx_debugIn);
2058         rxi_SendDebugPacket(ap, asocket, ahost, aport, istack);
2059         ap->length = tl;
2060         break;
2061     }
2062     return ap;
2063 }
2064
2065 struct rx_packet *
2066 rxi_ReceiveVersionPacket(register struct rx_packet *ap, osi_socket asocket,
2067                          afs_int32 ahost, short aport, int istack)
2068 {
2069     afs_int32 tl;
2070
2071     /*
2072      * Only respond to client-initiated version requests, and
2073      * clear that flag in the response.
2074      */
2075     if (ap->header.flags & RX_CLIENT_INITIATED) {
2076         char buf[66];
2077
2078         ap->header.flags = ap->header.flags & ~RX_CLIENT_INITIATED;
2079         rxi_EncodePacketHeader(ap);
2080         memset(buf, 0, sizeof(buf));
2081         strncpy(buf, cml_version_number + 4, sizeof(buf) - 1);
2082         rx_packetwrite(ap, 0, 65, buf);
2083         tl = ap->length;
2084         ap->length = 65;
2085         rxi_SendDebugPacket(ap, asocket, ahost, aport, istack);
2086         ap->length = tl;
2087     }
2088
2089     return ap;
2090 }
2091
2092
2093 /* send a debug packet back to the sender */
2094 static void
2095 rxi_SendDebugPacket(struct rx_packet *apacket, osi_socket asocket,
2096                     afs_int32 ahost, short aport, afs_int32 istack)
2097 {
2098     struct sockaddr_in taddr;
2099     int i;
2100     int nbytes;
2101     int saven = 0;
2102     size_t savelen = 0;
2103 #ifdef KERNEL
2104     int waslocked = ISAFS_GLOCK();
2105 #endif
2106
2107     taddr.sin_family = AF_INET;
2108     taddr.sin_port = aport;
2109     taddr.sin_addr.s_addr = ahost;
2110 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
2111     taddr.sin_len = sizeof(struct sockaddr_in);
2112 #endif
2113
2114     /* We need to trim the niovecs. */
2115     nbytes = apacket->length;
2116     for (i = 1; i < apacket->niovecs; i++) {
2117         if (nbytes <= apacket->wirevec[i].iov_len) {
2118             savelen = apacket->wirevec[i].iov_len;
2119             saven = apacket->niovecs;
2120             apacket->wirevec[i].iov_len = nbytes;
2121             apacket->niovecs = i + 1;   /* so condition fails because i == niovecs */
2122         } else
2123             nbytes -= apacket->wirevec[i].iov_len;
2124     }
2125 #ifdef KERNEL
2126 #ifdef RX_KERNEL_TRACE
2127     if (ICL_SETACTIVE(afs_iclSetp)) {
2128         if (!waslocked)
2129             AFS_GLOCK();
2130         afs_Trace1(afs_iclSetp, CM_TRACE_TIMESTAMP, ICL_TYPE_STRING,
2131                    "before osi_NetSend()");
2132         AFS_GUNLOCK();
2133     } else
2134 #else
2135     if (waslocked)
2136         AFS_GUNLOCK();
2137 #endif
2138 #endif
2139     /* debug packets are not reliably delivered, hence the cast below. */
2140     (void)osi_NetSend(asocket, &taddr, apacket->wirevec, apacket->niovecs,
2141                       apacket->length + RX_HEADER_SIZE, istack);
2142 #ifdef KERNEL
2143 #ifdef RX_KERNEL_TRACE
2144     if (ICL_SETACTIVE(afs_iclSetp)) {
2145         AFS_GLOCK();
2146         afs_Trace1(afs_iclSetp, CM_TRACE_TIMESTAMP, ICL_TYPE_STRING,
2147                    "after osi_NetSend()");
2148         if (!waslocked)
2149             AFS_GUNLOCK();
2150     } else
2151 #else
2152     if (waslocked)
2153         AFS_GLOCK();
2154 #endif
2155 #endif
2156     if (saven) {                /* means we truncated the packet above. */
2157         apacket->wirevec[i - 1].iov_len = savelen;
2158         apacket->niovecs = saven;
2159     }
2160
2161 }
2162
2163 /* Send the packet to appropriate destination for the specified
2164  * call.  The header is first encoded and placed in the packet.
2165  */
2166 void
2167 rxi_SendPacket(struct rx_call *call, struct rx_connection *conn,
2168                struct rx_packet *p, int istack)
2169 {
2170 #if defined(KERNEL)
2171     int waslocked;
2172 #endif
2173     int code;
2174     struct sockaddr_in addr;
2175     register struct rx_peer *peer = conn->peer;
2176     osi_socket socket;
2177 #ifdef RXDEBUG
2178     char deliveryType = 'S';
2179 #endif
2180     /* The address we're sending the packet to */
2181     memset(&addr, 0, sizeof(addr));
2182     addr.sin_family = AF_INET;
2183     addr.sin_port = peer->port;
2184     addr.sin_addr.s_addr = peer->host;
2185
2186     /* This stuff should be revamped, I think, so that most, if not
2187      * all, of the header stuff is always added here.  We could
2188      * probably do away with the encode/decode routines. XXXXX */
2189
2190     /* Stamp each packet with a unique serial number.  The serial
2191      * number is maintained on a connection basis because some types
2192      * of security may be based on the serial number of the packet,
2193      * and security is handled on a per authenticated-connection
2194      * basis. */
2195     /* Pre-increment, to guarantee no zero serial number; a zero
2196      * serial number means the packet was never sent. */
2197     MUTEX_ENTER(&conn->conn_data_lock);
2198     p->header.serial = ++conn->serial;
2199     MUTEX_EXIT(&conn->conn_data_lock);
2200     /* This is so we can adjust retransmit time-outs better in the face of 
2201      * rapidly changing round-trip times.  RTO estimation is not a la Karn.
2202      */
2203     if (p->firstSerial == 0) {
2204         p->firstSerial = p->header.serial;
2205     }
2206 #ifdef RXDEBUG
2207     /* If an output tracer function is defined, call it with the packet and
2208      * network address.  Note this function may modify its arguments. */
2209     if (rx_almostSent) {
2210         int drop = (*rx_almostSent) (p, &addr);
2211         /* drop packet if return value is non-zero? */
2212         if (drop)
2213             deliveryType = 'D'; /* Drop the packet */
2214     }
2215 #endif
2216
2217     /* Get network byte order header */
2218     rxi_EncodePacketHeader(p);  /* XXX in the event of rexmit, etc, don't need to 
2219                                  * touch ALL the fields */
2220
2221     /* Send the packet out on the same socket that related packets are being
2222      * received on */
2223     socket =
2224         (conn->type ==
2225          RX_CLIENT_CONNECTION ? rx_socket : conn->service->socket);
2226
2227 #ifdef RXDEBUG
2228     /* Possibly drop this packet,  for testing purposes */
2229     if ((deliveryType == 'D')
2230         || ((rx_intentionallyDroppedPacketsPer100 > 0)
2231             && (random() % 100 < rx_intentionallyDroppedPacketsPer100))) {
2232         deliveryType = 'D';     /* Drop the packet */
2233     } else {
2234         deliveryType = 'S';     /* Send the packet */
2235 #endif /* RXDEBUG */
2236
2237         /* Loop until the packet is sent.  We'd prefer just to use a
2238          * blocking socket, but unfortunately the interface doesn't
2239          * allow us to have the socket block in send mode, and not
2240          * block in receive mode */
2241 #ifdef KERNEL
2242         waslocked = ISAFS_GLOCK();
2243 #ifdef RX_KERNEL_TRACE
2244         if (ICL_SETACTIVE(afs_iclSetp)) {
2245             if (!waslocked)
2246                 AFS_GLOCK();
2247             afs_Trace1(afs_iclSetp, CM_TRACE_TIMESTAMP, ICL_TYPE_STRING,
2248                        "before osi_NetSend()");
2249             AFS_GUNLOCK();
2250         } else
2251 #else
2252         if (waslocked)
2253             AFS_GUNLOCK();
2254 #endif
2255 #endif
2256         if ((code =
2257              osi_NetSend(socket, &addr, p->wirevec, p->niovecs,
2258                          p->length + RX_HEADER_SIZE, istack)) != 0) {
2259             /* send failed, so let's hurry up the resend, eh? */
2260             rx_MutexIncrement(rx_stats.netSendFailures, rx_stats_mutex);
2261             p->retryTime = p->timeSent; /* resend it very soon */
2262             clock_Addmsec(&(p->retryTime),
2263                           10 + (((afs_uint32) p->backoff) << 8));
2264             /* Some systems are nice and tell us right away that we cannot
2265              * reach this recipient by returning an error code. 
2266              * So, when this happens let's "down" the host NOW so
2267              * we don't sit around waiting for this host to timeout later.
2268              */
2269             if (call && 
2270 #ifdef AFS_NT40_ENV
2271                 code == -1 && WSAGetLastError() == WSAEHOSTUNREACH
2272 #elif defined(AFS_LINUX20_ENV) && defined(KERNEL)
2273                 code == -ENETUNREACH
2274 #elif defined(AFS_DARWIN_ENV) && defined(KERNEL)
2275                 code == EHOSTUNREACH
2276 #else
2277                 0
2278 #endif
2279                 )
2280                 call->lastReceiveTime = 0;
2281         }
2282 #ifdef KERNEL
2283 #ifdef RX_KERNEL_TRACE
2284         if (ICL_SETACTIVE(afs_iclSetp)) {
2285             AFS_GLOCK();
2286             afs_Trace1(afs_iclSetp, CM_TRACE_TIMESTAMP, ICL_TYPE_STRING,
2287                        "after osi_NetSend()");
2288             if (!waslocked)
2289                 AFS_GUNLOCK();
2290         } else
2291 #else
2292         if (waslocked)
2293             AFS_GLOCK();
2294 #endif
2295 #endif
2296 #ifdef RXDEBUG
2297     }
2298     dpf(("%c %d %s: %x.%u.%u.%u.%u.%u.%u flags %d, packet %lx resend %d.%0.3d len %d", deliveryType, p->header.serial, rx_packetTypes[p->header.type - 1], ntohl(peer->host), ntohs(peer->port), p->header.serial, p->header.epoch, p->header.cid, p->header.callNumber, p->header.seq, p->header.flags, (unsigned long)p, p->retryTime.sec, p->retryTime.usec / 1000, p->length));
2299 #endif
2300     rx_MutexIncrement(rx_stats.packetsSent[p->header.type - 1], rx_stats_mutex);
2301     MUTEX_ENTER(&peer->peer_lock);
2302     hadd32(peer->bytesSent, p->length);
2303     MUTEX_EXIT(&peer->peer_lock);
2304 }
2305
2306 /* Send a list of packets to appropriate destination for the specified
2307  * connection.  The headers are first encoded and placed in the packets.
2308  */
2309 void
2310 rxi_SendPacketList(struct rx_call *call, struct rx_connection *conn,
2311                    struct rx_packet **list, int len, int istack)
2312 {
2313 #if     defined(AFS_SUN5_ENV) && defined(KERNEL)
2314     int waslocked;
2315 #endif
2316     struct sockaddr_in addr;
2317     register struct rx_peer *peer = conn->peer;
2318     osi_socket socket;
2319     struct rx_packet *p = NULL;
2320     struct iovec wirevec[RX_MAXIOVECS];
2321     int i, length, code;
2322     afs_uint32 serial;
2323     afs_uint32 temp;
2324     struct rx_jumboHeader *jp;
2325 #ifdef RXDEBUG
2326     char deliveryType = 'S';
2327 #endif
2328     /* The address we're sending the packet to */
2329     addr.sin_family = AF_INET;
2330     addr.sin_port = peer->port;
2331     addr.sin_addr.s_addr = peer->host;
2332
2333     if (len + 1 > RX_MAXIOVECS) {
2334         osi_Panic("rxi_SendPacketList, len > RX_MAXIOVECS\n");
2335     }
2336
2337     /*
2338      * Stamp the packets in this jumbogram with consecutive serial numbers
2339      */
2340     MUTEX_ENTER(&conn->conn_data_lock);
2341     serial = conn->serial;
2342     conn->serial += len;
2343     MUTEX_EXIT(&conn->conn_data_lock);
2344
2345
2346     /* This stuff should be revamped, I think, so that most, if not
2347      * all, of the header stuff is always added here.  We could
2348      * probably do away with the encode/decode routines. XXXXX */
2349
2350     jp = NULL;
2351     length = RX_HEADER_SIZE;
2352     wirevec[0].iov_base = (char *)(&list[0]->wirehead[0]);
2353     wirevec[0].iov_len = RX_HEADER_SIZE;
2354     for (i = 0; i < len; i++) {
2355         p = list[i];
2356
2357         /* The whole 3.5 jumbogram scheme relies on packets fitting
2358          * in a single packet buffer. */
2359         if (p->niovecs > 2) {
2360             osi_Panic("rxi_SendPacketList, niovecs > 2\n");
2361         }
2362
2363         /* Set the RX_JUMBO_PACKET flags in all but the last packets
2364          * in this chunk.  */
2365         if (i < len - 1) {
2366             if (p->length != RX_JUMBOBUFFERSIZE) {
2367                 osi_Panic("rxi_SendPacketList, length != jumbo size\n");
2368             }
2369             p->header.flags |= RX_JUMBO_PACKET;
2370             length += RX_JUMBOBUFFERSIZE + RX_JUMBOHEADERSIZE;
2371             wirevec[i + 1].iov_len = RX_JUMBOBUFFERSIZE + RX_JUMBOHEADERSIZE;
2372         } else {
2373             wirevec[i + 1].iov_len = p->length;
2374             length += p->length;
2375         }
2376         wirevec[i + 1].iov_base = (char *)(&p->localdata[0]);
2377         if (jp != NULL) {
2378             /* Convert jumbo packet header to network byte order */
2379             temp = (afs_uint32) (p->header.flags) << 24;
2380             temp |= (afs_uint32) (p->header.spare);
2381             *(afs_uint32 *) jp = htonl(temp);
2382         }
2383         jp = (struct rx_jumboHeader *)
2384             ((char *)(&p->localdata[0]) + RX_JUMBOBUFFERSIZE);
2385
2386         /* Stamp each packet with a unique serial number.  The serial
2387          * number is maintained on a connection basis because some types
2388          * of security may be based on the serial number of the packet,
2389          * and security is handled on a per authenticated-connection
2390          * basis. */
2391         /* Pre-increment, to guarantee no zero serial number; a zero
2392          * serial number means the packet was never sent. */
2393         p->header.serial = ++serial;
2394         /* This is so we can adjust retransmit time-outs better in the face of 
2395          * rapidly changing round-trip times.  RTO estimation is not a la Karn.
2396          */
2397         if (p->firstSerial == 0) {
2398             p->firstSerial = p->header.serial;
2399         }
2400 #ifdef RXDEBUG
2401         /* If an output tracer function is defined, call it with the packet and
2402          * network address.  Note this function may modify its arguments. */
2403         if (rx_almostSent) {
2404             int drop = (*rx_almostSent) (p, &addr);
2405             /* drop packet if return value is non-zero? */
2406             if (drop)
2407                 deliveryType = 'D';     /* Drop the packet */
2408         }
2409 #endif
2410
2411         /* Get network byte order header */
2412         rxi_EncodePacketHeader(p);      /* XXX in the event of rexmit, etc, don't need to 
2413                                          * touch ALL the fields */
2414     }
2415
2416     /* Send the packet out on the same socket that related packets are being
2417      * received on */
2418     socket =
2419         (conn->type ==
2420          RX_CLIENT_CONNECTION ? rx_socket : conn->service->socket);
2421
2422 #ifdef RXDEBUG
2423     /* Possibly drop this packet,  for testing purposes */
2424     if ((deliveryType == 'D')
2425         || ((rx_intentionallyDroppedPacketsPer100 > 0)
2426             && (random() % 100 < rx_intentionallyDroppedPacketsPer100))) {
2427         deliveryType = 'D';     /* Drop the packet */
2428     } else {
2429         deliveryType = 'S';     /* Send the packet */
2430 #endif /* RXDEBUG */
2431
2432         /* Loop until the packet is sent.  We'd prefer just to use a
2433          * blocking socket, but unfortunately the interface doesn't
2434          * allow us to have the socket block in send mode, and not
2435          * block in receive mode */
2436 #if     defined(AFS_SUN5_ENV) && defined(KERNEL)
2437         waslocked = ISAFS_GLOCK();
2438         if (!istack && waslocked)
2439             AFS_GUNLOCK();
2440 #endif
2441         if ((code =
2442              osi_NetSend(socket, &addr, &wirevec[0], len + 1, length,
2443                          istack)) != 0) {
2444             /* send failed, so let's hurry up the resend, eh? */
2445             rx_MutexIncrement(rx_stats.netSendFailures, rx_stats_mutex);
2446             for (i = 0; i < len; i++) {
2447                 p = list[i];
2448                 p->retryTime = p->timeSent;     /* resend it very soon */
2449                 clock_Addmsec(&(p->retryTime),
2450                               10 + (((afs_uint32) p->backoff) << 8));
2451             }
2452             /* Some systems are nice and tell us right away that we cannot
2453              * reach this recipient by returning an error code. 
2454              * So, when this happens let's "down" the host NOW so
2455              * we don't sit around waiting for this host to timeout later.
2456              */
2457             if (call && 
2458 #ifdef AFS_NT40_ENV
2459                 code == -1 && WSAGetLastError() == WSAEHOSTUNREACH
2460 #elif defined(AFS_LINUX20_ENV) && defined(KERNEL)
2461                 code == -ENETUNREACH
2462 #elif defined(AFS_DARWIN_ENV) && defined(KERNEL)
2463                 code == EHOSTUNREACH
2464 #else
2465                 0
2466 #endif
2467                 )
2468                 call->lastReceiveTime = 0;
2469         }
2470 #if     defined(AFS_SUN5_ENV) && defined(KERNEL)
2471         if (!istack && waslocked)
2472             AFS_GLOCK();
2473 #endif
2474 #ifdef RXDEBUG
2475     }
2476
2477     assert(p != NULL);
2478
2479     dpf(("%c %d %s: %x.%u.%u.%u.%u.%u.%u flags %d, packet %lx resend %d.%0.3d len %d", deliveryType, p->header.serial, rx_packetTypes[p->header.type - 1], ntohl(peer->host), ntohs(peer->port), p->header.serial, p->header.epoch, p->header.cid, p->header.callNumber, p->header.seq, p->header.flags, (unsigned long)p, p->retryTime.sec, p->retryTime.usec / 1000, p->length));
2480
2481 #endif
2482     rx_MutexIncrement(rx_stats.packetsSent[p->header.type - 1], rx_stats_mutex);
2483     MUTEX_ENTER(&peer->peer_lock);
2484     hadd32(peer->bytesSent, p->length);
2485     MUTEX_EXIT(&peer->peer_lock);
2486 }
2487
2488
2489 /* Send a "special" packet to the peer connection.  If call is
2490  * specified, then the packet is directed to a specific call channel
2491  * associated with the connection, otherwise it is directed to the
2492  * connection only. Uses optionalPacket if it is supplied, rather than
2493  * allocating a new packet buffer.  Nbytes is the length of the data
2494  * portion of the packet.  If data is non-null, nbytes of data are
2495  * copied into the packet.  Type is the type of the packet, as defined
2496  * in rx.h.  Bug: there's a lot of duplication between this and other
2497  * routines.  This needs to be cleaned up. */
2498 struct rx_packet *
2499 rxi_SendSpecial(register struct rx_call *call,
2500                 register struct rx_connection *conn,
2501                 struct rx_packet *optionalPacket, int type, char *data,
2502                 int nbytes, int istack)
2503 {
2504     /* Some of the following stuff should be common code for all
2505      * packet sends (it's repeated elsewhere) */
2506     register struct rx_packet *p;
2507     unsigned int i = 0;
2508     int savelen = 0, saven = 0;
2509     int channel, callNumber;
2510     if (call) {
2511         channel = call->channel;
2512         callNumber = *call->callNumber;
2513         /* BUSY packets refer to the next call on this connection */
2514         if (type == RX_PACKET_TYPE_BUSY) {
2515             callNumber++;
2516         }
2517     } else {
2518         channel = 0;
2519         callNumber = 0;
2520     }
2521     p = optionalPacket;
2522     if (!p) {
2523         p = rxi_AllocPacket(RX_PACKET_CLASS_SPECIAL);
2524         if (!p)
2525             osi_Panic("rxi_SendSpecial failure");
2526     }
2527
2528     if (nbytes != -1)
2529         p->length = nbytes;
2530     else
2531         nbytes = p->length;
2532     p->header.serviceId = conn->serviceId;
2533     p->header.securityIndex = conn->securityIndex;
2534     p->header.cid = (conn->cid | channel);
2535     p->header.callNumber = callNumber;
2536     p->header.seq = 0;
2537     p->header.epoch = conn->epoch;
2538     p->header.type = type;
2539     p->header.flags = 0;
2540     if (conn->type == RX_CLIENT_CONNECTION)
2541         p->header.flags |= RX_CLIENT_INITIATED;
2542     if (data)
2543         rx_packetwrite(p, 0, nbytes, data);
2544
2545     for (i = 1; i < p->niovecs; i++) {
2546         if (nbytes <= p->wirevec[i].iov_len) {
2547             savelen = p->wirevec[i].iov_len;
2548             saven = p->niovecs;
2549             p->wirevec[i].iov_len = nbytes;
2550             p->niovecs = i + 1; /* so condition fails because i == niovecs */
2551         } else
2552             nbytes -= p->wirevec[i].iov_len;
2553     }
2554
2555     if (call)
2556         rxi_Send(call, p, istack);
2557     else
2558         rxi_SendPacket((struct rx_call *)0, conn, p, istack);
2559     if (saven) {                /* means we truncated the packet above.  We probably don't  */
2560         /* really need to do this, but it seems safer this way, given that  */
2561         /* sneaky optionalPacket... */
2562         p->wirevec[i - 1].iov_len = savelen;
2563         p->niovecs = saven;
2564     }
2565     if (!optionalPacket)
2566         rxi_FreePacket(p);
2567     return optionalPacket;
2568 }
2569
2570
2571 /* Encode the packet's header (from the struct header in the packet to
2572  * the net byte order representation in the wire representation of the
2573  * packet, which is what is actually sent out on the wire) */
2574 void
2575 rxi_EncodePacketHeader(register struct rx_packet *p)
2576 {
2577     register afs_uint32 *buf = (afs_uint32 *) (p->wirevec[0].iov_base); /* MTUXXX */
2578
2579     memset((char *)buf, 0, RX_HEADER_SIZE);
2580     *buf++ = htonl(p->header.epoch);
2581     *buf++ = htonl(p->header.cid);
2582     *buf++ = htonl(p->header.callNumber);
2583     *buf++ = htonl(p->header.seq);
2584     *buf++ = htonl(p->header.serial);
2585     *buf++ = htonl((((afs_uint32) p->header.type) << 24)
2586                    | (((afs_uint32) p->header.flags) << 16)
2587                    | (p->header.userStatus << 8) | p->header.securityIndex);
2588     /* Note: top 16 bits of this next word were reserved */
2589     *buf++ = htonl((p->header.spare << 16) | (p->header.serviceId & 0xffff));
2590 }
2591
2592 /* Decode the packet's header (from net byte order to a struct header) */
2593 void
2594 rxi_DecodePacketHeader(register struct rx_packet *p)
2595 {
2596     register afs_uint32 *buf = (afs_uint32 *) (p->wirevec[0].iov_base); /* MTUXXX */
2597     afs_uint32 temp;
2598
2599     p->header.epoch = ntohl(*buf);
2600     buf++;
2601     p->header.cid = ntohl(*buf);
2602     buf++;
2603     p->header.callNumber = ntohl(*buf);
2604     buf++;
2605     p->header.seq = ntohl(*buf);
2606     buf++;
2607     p->header.serial = ntohl(*buf);
2608     buf++;
2609
2610     temp = ntohl(*buf);
2611     buf++;
2612
2613     /* C will truncate byte fields to bytes for me */
2614     p->header.type = temp >> 24;
2615     p->header.flags = temp >> 16;
2616     p->header.userStatus = temp >> 8;
2617     p->header.securityIndex = temp >> 0;
2618
2619     temp = ntohl(*buf);
2620     buf++;
2621
2622     p->header.serviceId = (temp & 0xffff);
2623     p->header.spare = temp >> 16;
2624     /* Note: top 16 bits of this last word are the security checksum */
2625 }
2626
2627 void
2628 rxi_PrepareSendPacket(register struct rx_call *call,
2629                       register struct rx_packet *p, register int last)
2630 {
2631     register struct rx_connection *conn = call->conn;
2632     int i;
2633     ssize_t len;                /* len must be a signed type; it can go negative */
2634
2635     p->flags &= ~RX_PKTFLAG_ACKED;
2636     p->header.cid = (conn->cid | call->channel);
2637     p->header.serviceId = conn->serviceId;
2638     p->header.securityIndex = conn->securityIndex;
2639
2640     /* No data packets on call 0. Where do these come from? */
2641     if (*call->callNumber == 0)
2642         *call->callNumber = 1;
2643
2644     p->header.callNumber = *call->callNumber;
2645     p->header.seq = call->tnext++;
2646     p->header.epoch = conn->epoch;
2647     p->header.type = RX_PACKET_TYPE_DATA;
2648     p->header.flags = 0;
2649     p->header.spare = 0;
2650     if (conn->type == RX_CLIENT_CONNECTION)
2651         p->header.flags |= RX_CLIENT_INITIATED;
2652
2653     if (last)
2654         p->header.flags |= RX_LAST_PACKET;
2655
2656     clock_Zero(&p->retryTime);  /* Never yet transmitted */
2657     clock_Zero(&p->firstSent);  /* Never yet transmitted */
2658     p->header.serial = 0;       /* Another way of saying never transmitted... */
2659     p->backoff = 0;
2660
2661     /* Now that we're sure this is the last data on the call, make sure
2662      * that the "length" and the sum of the iov_lens matches. */
2663     len = p->length + call->conn->securityHeaderSize;
2664
2665     for (i = 1; i < p->niovecs && len > 0; i++) {
2666         len -= p->wirevec[i].iov_len;
2667     }
2668     if (len > 0) {
2669         osi_Panic("PrepareSendPacket 1\n");     /* MTUXXX */
2670     } else if (i < p->niovecs) {
2671         /* Free any extra elements in the wirevec */
2672 #if defined(RX_ENABLE_TSFPQ)
2673         rxi_FreeDataBufsTSFPQ(p, i, 1 /* allow global pool flush if overquota */);
2674 #else /* !RX_ENABLE_TSFPQ */
2675         MUTEX_ENTER(&rx_freePktQ_lock);
2676         rxi_FreeDataBufsNoLock(p, i);
2677         MUTEX_EXIT(&rx_freePktQ_lock);
2678 #endif /* !RX_ENABLE_TSFPQ */
2679
2680         p->niovecs = i;
2681     }
2682     if (len)
2683         p->wirevec[i - 1].iov_len += len;
2684     RXS_PreparePacket(conn->securityObject, call, p);
2685 }
2686
2687 /* Given an interface MTU size, calculate an adjusted MTU size that
2688  * will make efficient use of the RX buffers when the peer is sending
2689  * either AFS 3.4a jumbograms or AFS 3.5 jumbograms.  */
2690 int
2691 rxi_AdjustIfMTU(int mtu)
2692 {
2693     int adjMTU;
2694     int frags;
2695
2696     if (rxi_nRecvFrags == 1 && rxi_nSendFrags == 1)
2697         return mtu;
2698     adjMTU = RX_HEADER_SIZE + RX_JUMBOBUFFERSIZE + RX_JUMBOHEADERSIZE;
2699     if (mtu <= adjMTU) {
2700         return mtu;
2701     }
2702     mtu -= adjMTU;
2703     if (mtu <= 0) {
2704         return adjMTU;
2705     }
2706     frags = mtu / (RX_JUMBOBUFFERSIZE + RX_JUMBOHEADERSIZE);
2707     return (adjMTU + (frags * (RX_JUMBOBUFFERSIZE + RX_JUMBOHEADERSIZE)));
2708 }
2709
2710 /* Given an interface MTU size, and the peer's advertised max receive
2711  * size, calculate an adjisted maxMTU size that makes efficient use
2712  * of our packet buffers when we are sending AFS 3.4a jumbograms. */
2713 int
2714 rxi_AdjustMaxMTU(int mtu, int peerMaxMTU)
2715 {
2716     int maxMTU = mtu * rxi_nSendFrags;
2717     maxMTU = MIN(maxMTU, peerMaxMTU);
2718     return rxi_AdjustIfMTU(maxMTU);
2719 }
2720
2721 /* Given a packet size, figure out how many datagram packet will fit.
2722  * The first buffer always contains RX_HEADER_SIZE+RX_JUMBOBUFFERSIZE+
2723  * RX_JUMBOHEADERSIZE, the middle buffers contain RX_JUMBOBUFFERSIZE+
2724  * RX_JUMBOHEADERSIZE, and the last buffer contains RX_JUMBOBUFFERSIZE */
2725 int
2726 rxi_AdjustDgramPackets(int frags, int mtu)
2727 {
2728     int maxMTU;
2729     if (mtu + IPv6_FRAG_HDR_SIZE < RX_JUMBOBUFFERSIZE + RX_HEADER_SIZE) {
2730         return 1;
2731     }
2732     maxMTU = (frags * (mtu + UDP_HDR_SIZE)) - UDP_HDR_SIZE;
2733     maxMTU = MIN(maxMTU, RX_MAX_PACKET_SIZE);
2734     /* subtract the size of the first and last packets */
2735     maxMTU -= RX_HEADER_SIZE + (2 * RX_JUMBOBUFFERSIZE) + RX_JUMBOHEADERSIZE;
2736     if (maxMTU < 0) {
2737         return 1;
2738     }
2739     return (2 + (maxMTU / (RX_JUMBOBUFFERSIZE + RX_JUMBOHEADERSIZE)));
2740 }
2741
2742 #ifdef AFS_NT40_ENV
2743 /* 
2744  * This function can be used by the Windows Cache Manager
2745  * to dump the list of all rx packets so that we can determine
2746  * where the packet leakage is.
2747  */
2748 int rx_DumpPackets(FILE *outputFile, char *cookie)
2749 {
2750 #ifdef DEBUG
2751     int zilch;
2752     struct rx_packet *p;
2753     char output[2048];
2754
2755     NETPRI;
2756     MUTEX_ENTER(&rx_freePktQ_lock);
2757     sprintf(output, "%s - Start dumping all Rx Packets - count=%u\r\n", cookie, rx_packet_id);
2758     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
2759
2760     for (p = rx_mallocedP; p; p = p->allNextp) {
2761         sprintf(output, "%s - packet=0x%p, id=%u, firstSent=%u.%08u, timeSent=%u.%08u, retryTime=%u.%08u, firstSerial=%u, niovecs=%u, flags=0x%x, backoff=%u, length=%u  header: epoch=%u, cid=%u, callNum=%u, seq=%u, serial=%u, type=%u, flags=0x%x, userStatus=%u, securityIndex=%u, serviceId=%u\r\n",
2762                 cookie, p, p->packetId, p->firstSent.sec, p->firstSent.usec, p->timeSent.sec, p->timeSent.usec, p->retryTime.sec, p->retryTime.usec, 
2763                 p->firstSerial, p->niovecs, (afs_uint32)p->flags, (afs_uint32)p->backoff, (afs_uint32)p->length,
2764                 p->header.epoch, p->header.cid, p->header.callNumber, p->header.seq, p->header.serial,
2765                 (afs_uint32)p->header.type, (afs_uint32)p->header.flags, (afs_uint32)p->header.userStatus, 
2766                 (afs_uint32)p->header.securityIndex, (afs_uint32)p->header.serviceId);
2767         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
2768     }
2769
2770     sprintf(output, "%s - End dumping all Rx Packets\r\n", cookie);
2771     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
2772
2773     MUTEX_EXIT(&rx_freePktQ_lock);
2774     USERPRI;
2775 #endif /* DEBUG */
2776     return 0;
2777 }
2778 #endif /* AFS_NT40_ENV */
2779