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