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