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