e6b30660333d3b9bc1d5e3fea2d01722496b95cf
[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("$Header$");
18
19 #ifdef KERNEL
20 #if defined(UKERNEL)
21 #include "afs/sysincludes.h"
22 #include "afsincludes.h"
23 #include "rx/rx_kcommon.h"
24 #include "rx/rx_clock.h"
25 #include "rx/rx_queue.h"
26 #include "rx/rx_packet.h"
27 #else /* defined(UKERNEL) */
28 #include "h/types.h"
29 #ifndef AFS_LINUX20_ENV
30 #include "h/systm.h"
31 #endif
32 #if defined(AFS_SGI_ENV) || defined(AFS_HPUX110_ENV)
33 #include "afs/sysincludes.h"
34 #endif
35 #if defined(AFS_OBSD_ENV)
36 #include "h/proc.h"
37 #endif
38 #include "h/socket.h"
39 #if !defined(AFS_SUN5_ENV) &&  !defined(AFS_LINUX20_ENV)
40 #if     !defined(AFS_OSF_ENV) && !defined(AFS_AIX41_ENV)
41 #include "sys/mount.h"   /* it gets pulled in by something later anyway */
42 #endif
43 #include "h/mbuf.h"
44 #endif
45 #include "netinet/in.h"
46 #include "afs/afs_osi.h"
47 #include "rx_kmutex.h"
48 #include "rx/rx_clock.h"
49 #include "rx/rx_queue.h"
50 #ifdef  AFS_SUN5_ENV
51 #include <sys/sysmacros.h>
52 #endif
53 #include "rx/rx_packet.h"
54 #endif /* defined(UKERNEL) */
55 #include "rx/rx_globals.h"
56 #else /* KERNEL */
57 #include "sys/types.h"
58 #include <sys/stat.h>
59 #include <errno.h>
60 #if defined(AFS_NT40_ENV) || defined(AFS_DJGPP_ENV)
61 #ifdef AFS_NT40_ENV
62 #include <winsock2.h>
63 #else
64 #include <sys/socket.h>
65 #include <netinet/in.h>
66 #endif /* AFS_NT40_ENV */
67 #include "rx_xmit_nt.h"
68 #include <stdlib.h>
69 #else
70 #include <sys/socket.h>
71 #include <netinet/in.h>
72 #endif
73 #include "rx_clock.h"
74 #include "rx.h"
75 #include "rx_queue.h"
76 #ifdef  AFS_SUN5_ENV
77 #include <sys/sysmacros.h>
78 #endif
79 #include "rx_packet.h"
80 #include "rx_globals.h"
81 #include <lwp.h>
82 #ifdef HAVE_STRING_H
83 #include <string.h>
84 #else
85 #ifdef HAVE_STRINGS_H
86 #include <strings.h>
87 #endif
88 #endif
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 struct rx_packet *rx_mallocedP = 0;
99
100 extern char cml_version_number[];
101 extern int (*rx_almostSent)();
102
103 static void rxi_SendDebugPacket(struct rx_packet *apacket, osi_socket asocket,
104                                afs_int32 ahost, short aport, afs_int32 istack);
105
106 /* some rules about packets:
107  * 1.  When a packet is allocated, the final iov_buf contains room for
108  * a security trailer, but iov_len masks that fact.  If the security
109  * package wants to add the trailer, it may do so, and then extend
110  * iov_len appropriately.  For this reason, packet's niovecs and
111  * iov_len fields should be accurate before calling PreparePacket.
112 */
113
114 /* Preconditions:
115  *        all packet buffers (iov_base) are integral multiples of 
116  *        the word size.
117  *        offset is an integral multiple of the word size.
118  */ 
119 afs_int32 rx_SlowGetInt32(struct rx_packet *packet, size_t offset)
120 {
121   unsigned int i;
122   size_t l;
123   for (l=0, i=1; i< packet->niovecs ; i++ ) {
124     if (l + packet->wirevec[i].iov_len > offset) {
125       return *((afs_int32 *)((char*)(packet->wirevec[i].iov_base) + (offset-l)));
126     }      
127     l += packet->wirevec[i].iov_len;
128   }
129   
130   return 0;
131 }
132
133 /* Preconditions:
134  *        all packet buffers (iov_base) are integral multiples of the word size.
135  *        offset is an integral multiple of the word size.
136  */ 
137 afs_int32 rx_SlowPutInt32(struct rx_packet *packet, size_t offset, afs_int32 data)
138 {
139   unsigned int i;
140   size_t l;
141   for (l=0, i=1; i< packet->niovecs ; i++ ) {
142     if (l + packet->wirevec[i].iov_len > offset) {
143       *((afs_int32 *)((char*)(packet->wirevec[i].iov_base) + (offset - l))) =
144           data;
145       return 0;
146     }      
147     l += packet->wirevec[i].iov_len;
148   }
149   
150   return 0;
151 }
152
153 /* Preconditions:
154  *        all packet buffers (iov_base) are integral multiples of the
155  *        word size.
156  *        offset is an integral multiple of the word size.
157  * Packet Invariants:
158  *         all buffers are contiguously arrayed in the iovec from 0..niovecs-1
159  */ 
160 afs_int32 rx_SlowReadPacket(struct rx_packet *packet, unsigned int offset,
161         int resid, char *out)
162 {
163   unsigned int i, j, l, r;
164   for (l=0, i=1; i< packet->niovecs ; i++ ) {
165     if (l + packet->wirevec[i].iov_len > offset) {
166       break;
167     }      
168     l += packet->wirevec[i].iov_len;
169   }
170   
171   /* i is the iovec which contains the first little bit of data in which we
172    * are interested.  l is the total length of everything prior to this iovec.
173    * j is the number of bytes we can safely copy out of this iovec.
174    */
175   r = resid;
176   while ((resid > 0) && (i < packet->niovecs)) {
177     j = MIN (resid, packet->wirevec[i].iov_len - (offset - l));
178     memcpy(out, (char *)(packet->wirevec[i].iov_base) + (offset - l), j);
179     resid -= j;
180     l += packet->wirevec[i].iov_len;
181     i++;  
182   }
183   
184   return (resid ? (r - resid) : r);
185 }
186
187
188 /* Preconditions:
189  *        all packet buffers (iov_base) are integral multiples of the
190  *        word size.
191  *        offset is an integral multiple of the word size.
192  */ 
193 afs_int32 rx_SlowWritePacket(struct rx_packet *packet, int offset, int resid,
194         char *in)
195 {
196   int i, j, l, r;
197   char * b;
198   
199   for (l=0, i=1; i < packet->niovecs; i++ ) {
200     if (l + packet->wirevec[i].iov_len > offset) {
201       break;
202     }      
203     l += packet->wirevec[i].iov_len;
204   }
205   
206   /* i is the iovec which contains the first little bit of data in which we
207    * are interested.  l is the total length of everything prior to this iovec.
208    * j is the number of bytes we can safely copy out of this iovec.
209    */
210   r = resid;
211   while ((resid > 0) && (i < RX_MAXWVECS)) {
212     if (i >= packet->niovecs) 
213       if (rxi_AllocDataBuf(packet, resid, RX_PACKET_CLASS_SEND_CBUF) >0) /* ++niovecs as a side-effect */
214         break;
215     
216     b = (char*)(packet->wirevec[i].iov_base) + (offset - l);
217     j = MIN (resid, packet->wirevec[i].iov_len - (offset - l));
218     memcpy(b, in, j);
219     resid -= j;
220     l += packet->wirevec[i].iov_len;
221     i++;  
222   }
223   
224   return (resid ? (r - resid) : r);
225 }
226
227 static struct rx_packet *allocCBuf(int class)
228 {
229   struct rx_packet *c;
230   SPLVAR;
231   
232   NETPRI;
233   MUTEX_ENTER(&rx_freePktQ_lock);
234
235 #ifdef KERNEL
236   if (rxi_OverQuota(class)) {
237     c = NULL;
238     rxi_NeedMorePackets = TRUE;
239     MUTEX_ENTER(&rx_stats_mutex);
240     switch(class) {
241         case RX_PACKET_CLASS_RECEIVE:
242             rx_stats.receivePktAllocFailures++;
243             break;
244         case RX_PACKET_CLASS_SEND:
245             rx_stats.sendPktAllocFailures++;
246             break;
247         case RX_PACKET_CLASS_SPECIAL:
248             rx_stats.specialPktAllocFailures++;
249             break;
250         case RX_PACKET_CLASS_RECV_CBUF:
251             rx_stats.receiveCbufPktAllocFailures++;
252             break;
253         case RX_PACKET_CLASS_SEND_CBUF:
254             rx_stats.sendCbufPktAllocFailures++;
255             break;
256     }
257     MUTEX_EXIT(&rx_stats_mutex);
258     goto done;
259   }
260   
261   if (queue_IsEmpty(&rx_freePacketQueue)) {
262     c = NULL;
263     rxi_NeedMorePackets = TRUE;
264     goto done;
265   }
266 #else /* KERNEL */
267   if (queue_IsEmpty(&rx_freePacketQueue)) {
268     rxi_MorePacketsNoLock(rx_initSendWindow);
269   }
270 #endif /* KERNEL */
271   
272   rx_nFreePackets--;
273   c = queue_First(&rx_freePacketQueue, rx_packet);
274   queue_Remove(c);
275   if (!(c->flags & RX_PKTFLAG_FREE))
276     osi_Panic("rxi_AllocPacket: packet not free\n");
277   c->flags = 0;         /* clear RX_PKTFLAG_FREE, initialize the rest */
278   c->header.flags = 0;
279   
280 #ifdef KERNEL
281  done:
282 #endif
283   MUTEX_EXIT(&rx_freePktQ_lock);
284   
285   USERPRI;
286   return c;
287 }
288
289 /*
290  * Free a packet currently used as a continuation buffer
291  */
292 void rxi_freeCBuf(struct rx_packet *c)
293 {
294   SPLVAR;
295   
296   NETPRI;
297   MUTEX_ENTER(&rx_freePktQ_lock);
298   
299   rxi_FreePacketNoLock(c);
300   /* Wakeup anyone waiting for packets */
301   rxi_PacketsUnWait();
302   
303   MUTEX_EXIT(&rx_freePktQ_lock);
304   USERPRI;
305 }
306
307 /* this one is kind of awful.
308  * In rxkad, the packet has been all shortened, and everything, ready for 
309  * sending.  All of a sudden, we discover we need some of that space back.
310  * This isn't terribly general, because it knows that the packets are only
311  * rounded up to the EBS (userdata + security header).
312  */
313 int rxi_RoundUpPacket(struct rx_packet *p, unsigned int nb)
314 {
315   int i;
316   i = p->niovecs - 1;
317   if (p->wirevec[i].iov_base == (caddr_t) p->localdata) {
318     if (p->wirevec[i].iov_len <= RX_FIRSTBUFFERSIZE - nb) {
319       p->wirevec[i].iov_len += nb;
320       return 0;
321     }
322   }
323   else {
324     if (p->wirevec[i].iov_len <= RX_CBUFFERSIZE - nb) {
325       p->wirevec[i].iov_len += nb;
326       return 0;
327     }
328   }
329
330 return 0;
331 }
332 /* get sufficient space to store nb bytes of data (or more), and hook
333  * it into the supplied packet.  Return nbytes<=0 if successful, otherwise
334  * returns the number of bytes >0 which it failed to come up with.
335  * Don't need to worry about locking on packet, since only
336  * one thread can manipulate one at a time. Locking on continution
337  * packets is handled by allocCBuf */
338 /* MTUXXX don't need to go throught the for loop if we can trust niovecs */
339 int rxi_AllocDataBuf(struct rx_packet *p, int nb, int class) 
340 {
341   int i;
342   
343   for (i=p->niovecs; nb>0 && i<RX_MAXWVECS; i++) {  
344       register struct rx_packet *cb;
345       if ((cb = allocCBuf(class))) {
346           p->wirevec[i].iov_base = (caddr_t) cb->localdata;
347           p->wirevec[i].iov_len = RX_CBUFFERSIZE;
348           nb -= RX_CBUFFERSIZE;
349           p->length += RX_CBUFFERSIZE;
350           p->niovecs++;
351       }
352       else break;
353   }
354   
355   return nb; 
356 }
357
358 /* Add more packet buffers */
359 void rxi_MorePackets(int apackets)
360 {
361   struct rx_packet *p, *e;
362   int getme;
363   SPLVAR;
364
365   getme = apackets * sizeof(struct rx_packet);
366   p = rx_mallocedP = (struct rx_packet *) osi_Alloc(getme);
367
368   PIN(p, getme);        /* XXXXX */
369   memset((char *)p, 0, getme);
370   NETPRI;
371   AFS_RXGLOCK();
372   MUTEX_ENTER(&rx_freePktQ_lock);
373
374   for (e = p + apackets; p<e; p++) {
375     p->wirevec[0].iov_base = (char *) (p->wirehead);
376     p->wirevec[0].iov_len  = RX_HEADER_SIZE;
377     p->wirevec[1].iov_base = (char *) (p->localdata);
378     p->wirevec[1].iov_len  = RX_FIRSTBUFFERSIZE;
379     p->flags |= RX_PKTFLAG_FREE;
380     p->niovecs = 2;
381     
382     queue_Append(&rx_freePacketQueue, p);
383   }
384   rx_nFreePackets += apackets;
385   rxi_NeedMorePackets = FALSE;
386   rxi_PacketsUnWait();
387   
388   AFS_RXGUNLOCK();
389   MUTEX_EXIT(&rx_freePktQ_lock);
390   USERPRI;
391 }
392
393 #ifndef KERNEL
394 /* Add more packet buffers */
395 void rxi_MorePacketsNoLock(int apackets)
396 {
397   struct rx_packet *p, *e;
398   int getme;
399
400   /* allocate enough packets that 1/4 of the packets will be able
401    * to hold maximal amounts of data */ 
402   apackets += (apackets/4)
403               * ((rx_maxJumboRecvSize - RX_FIRSTBUFFERSIZE)/RX_CBUFFERSIZE);
404   getme = apackets * sizeof(struct rx_packet);
405   p = rx_mallocedP = (struct rx_packet *) osi_Alloc(getme);
406
407   memset((char *)p, 0, getme);
408
409   for (e = p + apackets; p<e; p++) {
410     p->wirevec[0].iov_base = (char *) (p->wirehead);
411     p->wirevec[0].iov_len  = RX_HEADER_SIZE;
412     p->wirevec[1].iov_base = (char *) (p->localdata);
413     p->wirevec[1].iov_len  = RX_FIRSTBUFFERSIZE;
414     p->flags |= RX_PKTFLAG_FREE;
415     p->niovecs = 2;
416     
417     queue_Append(&rx_freePacketQueue, p);
418   }
419   rx_nFreePackets += apackets;
420   rxi_NeedMorePackets = FALSE;
421   rxi_PacketsUnWait();
422 }
423 #endif /* !KERNEL */
424
425 void rxi_FreeAllPackets(void)
426 {
427   /* must be called at proper interrupt level, etcetera */
428   /* MTUXXX need to free all Packets */
429   osi_Free(rx_mallocedP, (rx_maxReceiveWindow+2) * sizeof(struct rx_packet));    
430   UNPIN(rx_mallocedP, (rx_maxReceiveWindow+2) * sizeof(struct rx_packet));    
431 }
432
433 /* Allocate more packets iff we need more continuation buffers */
434 /* In kernel, can't page in memory with interrupts disabled, so we
435  * don't use the event mechanism. */
436 void rx_CheckPackets(void)
437 {
438   if (rxi_NeedMorePackets) {
439     rxi_MorePackets(rx_initSendWindow); 
440   }
441 }
442
443 /* In the packet freeing routine below, the assumption is that
444    we want all of the packets to be used equally frequently, so that we
445    don't get packet buffers paging out.  It would be just as valid to
446    assume that we DO want them to page out if not many are being used.
447    In any event, we assume the former, and append the packets to the end
448    of the free list.  */
449 /* This explanation is bogus.  The free list doesn't remain in any kind of
450    useful order for afs_int32: the packets in use get pretty much randomly scattered 
451    across all the pages.  In order to permit unused {packets,bufs} to page out, they
452    must be stored so that packets which are adjacent in memory are adjacent in the 
453    free list.  An array springs rapidly to mind.
454    */
455
456 /* Actually free the packet p. */
457 void rxi_FreePacketNoLock(struct rx_packet *p)
458 {
459   dpf(("Free %x\n", p));
460
461   if (p->flags & RX_PKTFLAG_FREE)
462     osi_Panic("rxi_FreePacketNoLock: packet already free\n");
463   rx_nFreePackets++;
464   p->flags |= RX_PKTFLAG_FREE;
465   queue_Append(&rx_freePacketQueue, p);
466 }
467
468 int rxi_FreeDataBufsNoLock(struct rx_packet *p, int first)
469 {
470   struct iovec *iov, *end;
471   
472   if (first != 1)          /* MTUXXX */
473       osi_Panic("FreeDataBufs 1: first must be 1");
474   iov = &p->wirevec[1];
475   end = iov + (p->niovecs-1);
476   if (iov->iov_base != (caddr_t) p->localdata) /* MTUXXX */
477         osi_Panic("FreeDataBufs 2: vec 1 must be localdata");
478   for (iov++ ; iov < end ; iov++) {
479     if (!iov->iov_base)
480         osi_Panic("FreeDataBufs 3: vecs 2-niovecs must not be NULL");
481     rxi_FreePacketNoLock(RX_CBUF_TO_PACKET(iov->iov_base, p));
482   }
483   p->length = 0;
484   p->niovecs = 0;
485
486   return 0; 
487 }
488
489 int rxi_nBadIovecs = 0;
490
491 /* rxi_RestoreDataBufs 
492  *
493  * Restore the correct sizes to the iovecs. Called when reusing a packet
494  * for reading off the wire.
495  */
496 void rxi_RestoreDataBufs(struct rx_packet *p)
497 {
498     int i;
499     struct iovec *iov = &p->wirevec[2];
500
501     p->wirevec[0].iov_base = (char *) (p->wirehead);
502     p->wirevec[0].iov_len  = RX_HEADER_SIZE;
503     p->wirevec[1].iov_base = (char *) (p->localdata);
504     p->wirevec[1].iov_len  = RX_FIRSTBUFFERSIZE;
505
506     for (i=2, iov = &p->wirevec[2]; i < p->niovecs; i++, iov++) {
507         if (!iov->iov_base) {
508             rxi_nBadIovecs ++;
509             p->niovecs = i;
510             break;
511         }
512         iov->iov_len = RX_CBUFFERSIZE;
513     }
514 }
515
516 int rxi_TrimDataBufs(struct rx_packet *p, int first)
517 {
518   int length;
519   struct iovec *iov, *end;
520   SPLVAR;
521   
522   if (first != 1)
523       osi_Panic("TrimDataBufs 1: first must be 1");
524
525   /* Skip over continuation buffers containing message data */
526   iov = &p->wirevec[2];
527   end = iov + (p->niovecs-2);
528   length = p->length - p->wirevec[1].iov_len;
529   for (; iov < end && length > 0 ; iov++) {
530     if (!iov->iov_base)
531         osi_Panic("TrimDataBufs 3: vecs 1-niovecs must not be NULL");
532     length -= iov->iov_len;
533   }
534
535   /* iov now points to the first empty data buffer. */
536   if (iov >= end)
537     return 0;
538   
539   NETPRI;
540   MUTEX_ENTER(&rx_freePktQ_lock);
541
542   for (; iov < end ; iov++) {
543     if (!iov->iov_base)
544         osi_Panic("TrimDataBufs 4: vecs 2-niovecs must not be NULL");
545     rxi_FreePacketNoLock(RX_CBUF_TO_PACKET(iov->iov_base, p));
546     p->niovecs--;
547   }
548   rxi_PacketsUnWait();
549   
550   MUTEX_EXIT(&rx_freePktQ_lock);
551   USERPRI;
552
553   return 0; 
554 }
555
556 /* Free the packet p.  P is assumed not to be on any queue, i.e.
557  * remove it yourself first if you call this routine. */
558 void rxi_FreePacket(struct rx_packet *p)
559 {
560   SPLVAR;
561   
562   NETPRI;
563   MUTEX_ENTER(&rx_freePktQ_lock);
564   
565   rxi_FreeDataBufsNoLock(p,1);
566   rxi_FreePacketNoLock(p);
567   /* Wakeup anyone waiting for packets */
568   rxi_PacketsUnWait();
569   
570   MUTEX_EXIT(&rx_freePktQ_lock);
571   USERPRI;
572 }
573
574
575 /* rxi_AllocPacket sets up p->length so it reflects the number of 
576  * bytes in the packet at this point, **not including** the header.
577  * The header is absolutely necessary, besides, this is the way the
578  * length field is usually used */
579 struct rx_packet *rxi_AllocPacketNoLock(int class)
580 {
581   register struct rx_packet *p;
582   
583 #ifdef KERNEL
584   if (rxi_OverQuota(class)) {
585     rxi_NeedMorePackets = TRUE;
586     MUTEX_ENTER(&rx_stats_mutex);
587     switch(class) {
588         case RX_PACKET_CLASS_RECEIVE:
589             rx_stats.receivePktAllocFailures++;
590             break;
591         case RX_PACKET_CLASS_SEND:
592             rx_stats.sendPktAllocFailures++;
593             break;
594         case RX_PACKET_CLASS_SPECIAL:
595             rx_stats.specialPktAllocFailures++;
596             break;
597         case RX_PACKET_CLASS_RECV_CBUF:
598             rx_stats.receiveCbufPktAllocFailures++;
599             break;
600         case RX_PACKET_CLASS_SEND_CBUF:
601             rx_stats.sendCbufPktAllocFailures++;
602             break;
603     }
604     MUTEX_EXIT(&rx_stats_mutex);
605     return (struct rx_packet *) 0;
606   }
607 #endif /* KERNEL */
608
609   MUTEX_ENTER(&rx_stats_mutex);
610   rx_stats.packetRequests++;
611   MUTEX_EXIT(&rx_stats_mutex);
612   
613 #ifdef KERNEL
614   if (queue_IsEmpty(&rx_freePacketQueue)) 
615     osi_Panic("rxi_AllocPacket error");
616 #else /* KERNEL */
617   if (queue_IsEmpty(&rx_freePacketQueue)) 
618     rxi_MorePacketsNoLock(rx_initSendWindow);
619 #endif /* KERNEL */
620   
621   rx_nFreePackets--;
622   p = queue_First(&rx_freePacketQueue, rx_packet);
623   if (!(p->flags & RX_PKTFLAG_FREE))
624     osi_Panic("rxi_AllocPacket: packet not free\n");
625   
626   dpf(("Alloc %x, class %d\n", p, class));
627   
628   queue_Remove(p);
629   p->flags = 0;         /* clear RX_PKTFLAG_FREE, initialize the rest */
630   p->header.flags = 0;
631   
632   /* have to do this here because rx_FlushWrite fiddles with the iovs in
633    * order to truncate outbound packets.  In the near future, may need 
634    * to allocate bufs from a static pool here, and/or in AllocSendPacket
635    */
636   p->wirevec[0].iov_base = (char *) (p->wirehead);
637   p->wirevec[0].iov_len  = RX_HEADER_SIZE;
638   p->wirevec[1].iov_base = (char *) (p->localdata);
639   p->wirevec[1].iov_len  = RX_FIRSTBUFFERSIZE;
640   p->niovecs = 2;
641   p->length = RX_FIRSTBUFFERSIZE;
642   return p;
643 }
644
645 struct rx_packet *rxi_AllocPacket(int class)
646 {
647     register struct rx_packet *p;
648
649     MUTEX_ENTER(&rx_freePktQ_lock);
650     p = rxi_AllocPacketNoLock(class);
651     MUTEX_EXIT(&rx_freePktQ_lock);
652     return p;
653 }
654
655 /* This guy comes up with as many buffers as it {takes,can get} given
656  * the MTU for this call. It also sets the packet length before
657  * returning.  caution: this is often called at NETPRI
658  * Called with call locked.
659  */
660 struct rx_packet *rxi_AllocSendPacket(register struct rx_call *call, int want)
661 {
662     register struct rx_packet *p = (struct rx_packet *) 0;
663     register int mud;
664     register unsigned delta;
665
666     SPLVAR;
667     mud = call->MTU - RX_HEADER_SIZE;
668     delta = rx_GetSecurityHeaderSize(rx_ConnectionOf(call)) + 
669         rx_GetSecurityMaxTrailerSize(rx_ConnectionOf(call));
670
671     while (!(call->error)) {
672       MUTEX_ENTER(&rx_freePktQ_lock);
673       /* if an error occurred, or we get the packet we want, we're done */
674       if ((p = rxi_AllocPacketNoLock(RX_PACKET_CLASS_SEND))) {
675         MUTEX_EXIT(&rx_freePktQ_lock);
676
677         want += delta;
678         want = MIN(want, mud);
679
680         if ((unsigned) want > p->length) 
681           (void) rxi_AllocDataBuf(p, (want - p->length),
682                                   RX_PACKET_CLASS_SEND_CBUF);
683
684         if ((unsigned) p->length > mud)
685             p->length = mud;
686
687         if (delta >= p->length) {
688           rxi_FreePacket(p);
689           p = NULL; 
690         } else {
691             p->length -= delta;
692         }
693         break; 
694       }
695
696       /* no error occurred, and we didn't get a packet, so we sleep.
697        * At this point, we assume that packets will be returned
698        * sooner or later, as packets are acknowledged, and so we
699        * just wait.  */
700       NETPRI;
701       call->flags |= RX_CALL_WAIT_PACKETS;
702       CALL_HOLD(call, RX_CALL_REFCOUNT_PACKET);
703       MUTEX_EXIT(&call->lock);
704       rx_waitingForPackets = 1;
705       
706 #ifdef  RX_ENABLE_LOCKS
707       CV_WAIT(&rx_waitingForPackets_cv, &rx_freePktQ_lock);
708 #else
709       osi_rxSleep(&rx_waitingForPackets);
710 #endif
711       MUTEX_EXIT(&rx_freePktQ_lock);
712       MUTEX_ENTER(&call->lock);
713       CALL_RELE(call, RX_CALL_REFCOUNT_PACKET);
714       call->flags &= ~RX_CALL_WAIT_PACKETS;
715       USERPRI;
716     }
717
718     return p;
719 }
720
721 #ifndef KERNEL
722
723 /* count the number of used FDs */
724 static int CountFDs(register int amax)
725 {
726     struct stat tstat;
727     register int i, code;
728     register int count;
729
730     count = 0;
731     for(i=0;i<amax;i++) {
732         code = fstat(i, &tstat);
733         if (code == 0) count++;
734     }
735     return count;
736 }
737
738 #else /* KERNEL */
739
740 #define CountFDs(amax) amax
741
742 #endif /* KERNEL */
743
744 #if !defined(KERNEL) || defined(UKERNEL)
745
746 /* This function reads a single packet from the interface into the
747  * supplied packet buffer (*p).  Return 0 if the packet is bogus.  The
748  * (host,port) of the sender are stored in the supplied variables, and
749  * the data length of the packet is stored in the packet structure.
750  * The header is decoded. */
751 int rxi_ReadPacket(int socket, register struct rx_packet *p, afs_uint32 *host, u_short *port)
752 {
753     struct sockaddr_in from;
754     int nbytes;
755     afs_int32 rlen;
756     register afs_int32 tlen, savelen;
757     struct msghdr msg;
758     rx_computelen(p, tlen);
759     rx_SetDataSize(p, tlen);  /* this is the size of the user data area */
760
761     tlen += RX_HEADER_SIZE;   /* now this is the size of the entire packet */
762     rlen = rx_maxJumboRecvSize; /* this is what I am advertising.  Only check
763                                  * it once in order to avoid races.  */
764     tlen = rlen - tlen;
765     if (tlen > 0) {
766       tlen = rxi_AllocDataBuf(p, tlen, RX_PACKET_CLASS_SEND_CBUF);
767       if (tlen >0) {
768         tlen = rlen - tlen;
769       }
770       else tlen = rlen;
771     }
772     else tlen = rlen;
773
774    /* Extend the last iovec for padding, it's just to make sure that the 
775     * read doesn't return more data than we expect, and is done to get around
776     * our problems caused by the lack of a length field in the rx header.
777     * Use the extra buffer that follows the localdata in each packet
778     * structure. */
779     savelen = p->wirevec[p->niovecs-1].iov_len;
780     p->wirevec[p->niovecs-1].iov_len += RX_EXTRABUFFERSIZE;
781
782     memset((char *)&msg, 0, sizeof(msg));
783     msg.msg_name = (char *) &from;
784     msg.msg_namelen = sizeof(struct sockaddr_in);
785     msg.msg_iov = p->wirevec;
786     msg.msg_iovlen = p->niovecs;
787     nbytes = rxi_Recvmsg(socket, &msg, 0);
788
789    /* restore the vec to its correct state */
790     p->wirevec[p->niovecs-1].iov_len = savelen;
791
792     p->length = (nbytes - RX_HEADER_SIZE);
793     if ((nbytes > tlen) || (p->length  & 0x8000)) {  /* Bogus packet */
794       if (nbytes > 0)
795         rxi_MorePackets(rx_initSendWindow);
796 #ifndef AFS_NT40_ENV
797       else if (nbytes < 0 && errno == EWOULDBLOCK) {
798         MUTEX_ENTER(&rx_stats_mutex);
799         rx_stats.noPacketOnRead++;
800         MUTEX_EXIT(&rx_stats_mutex);
801       }
802 #endif
803       else {
804         MUTEX_ENTER(&rx_stats_mutex);
805         rx_stats.bogusPacketOnRead++;
806         rx_stats.bogusHost = from.sin_addr.s_addr;
807         MUTEX_EXIT(&rx_stats_mutex);
808         dpf(("B: bogus packet from [%x,%d] nb=%d", from.sin_addr.s_addr,
809              from.sin_port,nbytes));
810       }
811       return  0;
812     }
813     else {
814       /* Extract packet header. */
815       rxi_DecodePacketHeader(p);
816       
817       *host = from.sin_addr.s_addr;
818       *port = from.sin_port;
819       if (p->header.type > 0 && p->header.type < RX_N_PACKET_TYPES) {
820         struct rx_peer *peer;
821         MUTEX_ENTER(&rx_stats_mutex);
822         rx_stats.packetsRead[p->header.type-1]++;
823         MUTEX_EXIT(&rx_stats_mutex);
824         /*
825          * Try to look up this peer structure.  If it doesn't exist,
826          * don't create a new one - 
827          * we don't keep count of the bytes sent/received if a peer
828          * structure doesn't already exist.
829          *
830          * The peer/connection cleanup code assumes that there is 1 peer
831          * per connection.  If we actually created a peer structure here
832          * and this packet was an rxdebug packet, the peer structure would
833          * never be cleaned up.
834          */
835         peer = rxi_FindPeer(*host, *port, 0, 0);
836         if (peer) {
837             MUTEX_ENTER(&peer->peer_lock);
838             hadd32(peer->bytesReceived, p->length);
839             MUTEX_EXIT(&peer->peer_lock);
840         }
841       }
842
843       /* Free any empty packet buffers at the end of this packet */
844       rxi_TrimDataBufs(p, 1);
845       
846       return  1;
847     }
848 }
849
850 #endif /* !KERNEL || UKERNEL */
851
852 /* This function splits off the first packet in a jumbo packet.
853  * As of AFS 3.5, jumbograms contain more than one fixed size
854  * packet, and the RX_JUMBO_PACKET flag is set in all but the
855  * last packet header. All packets (except the last) are padded to
856  * fall on RX_CBUFFERSIZE boundaries.
857  * HACK: We store the length of the first n-1 packets in the
858  * last two pad bytes. */
859
860 struct rx_packet *rxi_SplitJumboPacket(register struct rx_packet *p, afs_int32 host, 
861         short port, int first)
862 {
863     struct rx_packet *np;
864     struct rx_jumboHeader *jp;
865     int niov, i;
866     struct iovec *iov;
867     int length;
868     afs_uint32 temp;
869
870     /* All but the last packet in each jumbogram are RX_JUMBOBUFFERSIZE
871      * bytes in length. All but the first packet are preceded by
872      * an abbreviated four byte header. The length of the last packet
873      * is calculated from the size of the jumbogram. */
874     length = RX_JUMBOBUFFERSIZE + RX_JUMBOHEADERSIZE;
875
876     if ((int)p->length < length) {
877         dpf(("rxi_SplitJumboPacket: bogus length %d\n", p->length));
878         return NULL;
879     }
880     niov = p->niovecs - 2;
881     if (niov < 1) {
882         dpf(("rxi_SplitJumboPacket: bogus niovecs %d\n", p->niovecs));
883         return NULL;
884     }
885     iov = &p->wirevec[2];
886     np = RX_CBUF_TO_PACKET(iov->iov_base, p);
887
888     /* Get a pointer to the abbreviated packet header */
889     jp = (struct rx_jumboHeader *)
890          ((char *)(p->wirevec[1].iov_base) + RX_JUMBOBUFFERSIZE);
891
892     /* Set up the iovecs for the next packet */
893     np->wirevec[0].iov_base = (char *)(&np->wirehead[0]);
894     np->wirevec[0].iov_len = sizeof(struct rx_header);
895     np->wirevec[1].iov_base = (char *)(&np->localdata[0]);
896     np->wirevec[1].iov_len = length - RX_JUMBOHEADERSIZE;
897     np->niovecs = niov+1;
898     for (i = 2 , iov++ ; i <= niov ; i++ , iov++) {
899         np->wirevec[i] = *iov;
900     }
901     np->length = p->length - length;
902     p->length = RX_JUMBOBUFFERSIZE;
903     p->niovecs = 2;
904
905     /* Convert the jumbo packet header to host byte order */
906     temp = ntohl(*(afs_uint32 *)jp);
907     jp->flags = (u_char)(temp >> 24);
908     jp->cksum = (u_short)(temp);
909
910     /* Fill in the packet header */
911     np->header = p->header;
912     np->header.serial = p->header.serial + 1;
913     np->header.seq = p->header.seq + 1;
914     np->header.flags = jp->flags;
915     np->header.spare = jp->cksum;
916       
917     return np;
918 }
919
920 #ifndef KERNEL
921 /* Send a udp datagram */
922 int osi_NetSend(osi_socket socket, void *addr, struct iovec *dvec, int nvecs, 
923         int length, int istack)
924 {
925     struct msghdr msg;
926
927     memset(&msg, 0, sizeof(msg));
928     msg.msg_iov = dvec;
929     msg.msg_iovlen = nvecs;
930     msg.msg_name = addr;
931     msg.msg_namelen = sizeof(struct sockaddr_in);
932
933     rxi_Sendmsg(socket, &msg, 0);
934
935     return 0;
936 }
937 #elif !defined(UKERNEL)
938 /*
939  * message receipt is done in rxk_input or rx_put.
940  */
941
942 #ifdef AFS_SUN5_ENV
943 /*
944  * Copy an mblock to the contiguous area pointed to by cp.
945  * MTUXXX Supposed to skip <off> bytes and copy <len> bytes,
946  * but it doesn't really.
947  * Returns the number of bytes not transferred.
948  * The message is NOT changed.
949  */
950 static int cpytoc(mblk_t *mp, register int off, register int len, register char *cp)
951 {
952     register int n;
953
954     for (;mp && len > 0; mp = mp->b_cont) {
955         if (mp->b_datap->db_type != M_DATA) {
956             return -1;
957         }
958         n = MIN(len, (mp->b_wptr - mp->b_rptr));
959         memcpy(cp, (char *)mp->b_rptr, n);
960         cp += n;
961         len -= n;
962         mp->b_rptr += n;
963     }
964     return (len);
965 }
966
967 /* MTUXXX Supposed to skip <off> bytes and copy <len> bytes,
968  * but it doesn't really.  
969  * This sucks, anyway, do it like m_cpy.... below 
970  */
971 static int cpytoiovec(mblk_t *mp, int off, int len, register struct iovec *iovs, int niovs)
972 {
973     register int m,n,o,t,i;
974
975     for (i = -1, t = 0; i < niovs && mp && len > 0; mp = mp->b_cont) {
976         if (mp->b_datap->db_type != M_DATA) {
977             return -1;
978         }
979         n = MIN(len, (mp->b_wptr - mp->b_rptr));
980         len -= n;
981         while (n) {
982           if (!t) {
983             o=0;
984             i++;
985             t = iovs[i].iov_len;
986           }
987           m = MIN(n,t);
988           memcpy(iovs[i].iov_base + o, (char *)mp->b_rptr, m);
989           mp->b_rptr += m;
990           o += m;
991           t -= m;
992           n -= m;
993         }
994     }
995     return (len);
996 }
997 #define m_cpytoc(a, b, c, d)  cpytoc(a, b, c, d)
998 #define m_cpytoiovec(a, b, c, d, e) cpytoiovec(a, b, c, d, e)
999 #else
1000 #if !defined(AFS_LINUX20_ENV)
1001 static int m_cpytoiovec(struct mbuf *m, int off, int len, struct iovec iovs[], int niovs)
1002 {
1003   caddr_t p1, p2;
1004   unsigned int l1, l2, i, t;
1005   
1006   if (m == NULL || off < 0 || len < 0 || iovs == NULL)
1007     osi_Panic("m_cpytoiovec");  /* MTUXXX probably don't need this check */
1008   
1009   while (off && m)
1010     if (m->m_len <= off) {
1011       off -= m->m_len;
1012       m = m->m_next;
1013       continue;
1014     } else
1015       break;
1016   
1017   if (m == NULL)
1018     return len;
1019   
1020   p1 = mtod(m, caddr_t)+off;
1021   l1 = m->m_len - off;
1022   i = 0;
1023   p2 = iovs[0].iov_base;
1024   l2 = iovs[0].iov_len;
1025   
1026   while (len) {
1027     t = MIN(l1, MIN(l2, (unsigned int)len));
1028     memcpy(p2, p1, t);
1029     p1 += t;    p2 += t;
1030     l1 -= t;    l2 -= t;
1031     len -= t;
1032     if (!l1) {
1033       m = m->m_next; 
1034       if (!m)
1035         break;
1036       p1 = mtod(m, caddr_t);
1037       l1 = m->m_len;
1038     }
1039     if (!l2) {
1040       if (++i >= niovs)
1041         break;
1042       p2 = iovs[i].iov_base;
1043       l2 = iovs[i].iov_len;
1044     }
1045     
1046   }
1047
1048 return len;  
1049 }
1050 #endif /* LINUX */
1051 #endif /* AFS_SUN5_ENV */
1052
1053 #if !defined(AFS_LINUX20_ENV)
1054 int rx_mb_to_packet(amb, free, hdr_len, data_len, phandle)
1055 #ifdef  AFS_SUN5_ENV
1056 mblk_t *amb;
1057 #else
1058 struct mbuf *amb;
1059 #endif
1060 void (*free)();
1061 struct rx_packet *phandle;
1062 int hdr_len, data_len;
1063 {
1064   register int code;
1065
1066   code = m_cpytoiovec(amb, hdr_len, data_len, phandle->wirevec, phandle->niovecs); 
1067   (*free)(amb);
1068
1069   return code;
1070 }
1071 #endif /* LINUX */
1072 #endif /*KERNEL && !UKERNEL*/
1073
1074
1075 /* send a response to a debug packet */
1076
1077 struct rx_packet *rxi_ReceiveDebugPacket(register struct rx_packet *ap, 
1078         osi_socket asocket, afs_int32 ahost, short aport, int istack)
1079 {
1080     struct rx_debugIn tin;
1081     afs_int32 tl;
1082     struct rx_serverQueueEntry *np, *nqe;
1083
1084     /*
1085      * Only respond to client-initiated Rx debug packets,
1086      * and clear the client flag in the response.
1087      */
1088     if (ap->header.flags & RX_CLIENT_INITIATED) {
1089         ap->header.flags = ap->header.flags & ~RX_CLIENT_INITIATED;
1090         rxi_EncodePacketHeader(ap);
1091     } else {
1092         return ap;
1093     }
1094
1095     rx_packetread(ap, 0, sizeof(struct rx_debugIn), (char *)&tin);
1096     /* all done with packet, now set length to the truth, so we can 
1097      * reuse this packet */
1098     rx_computelen(ap, ap->length);
1099
1100     tin.type = ntohl(tin.type);
1101     tin.index = ntohl(tin.index);
1102     switch(tin.type) {
1103         case RX_DEBUGI_GETSTATS: {
1104             struct rx_debugStats tstat;
1105
1106             /* get basic stats */
1107             memset((char *)&tstat, 0, sizeof(tstat)); /* make sure spares are zero */
1108             tstat.version = RX_DEBUGI_VERSION;
1109 #ifndef RX_ENABLE_LOCKS
1110             tstat.waitingForPackets = rx_waitingForPackets;
1111 #endif
1112             tstat.nFreePackets = htonl(rx_nFreePackets);
1113             tstat.callsExecuted = htonl(rxi_nCalls);
1114             tstat.packetReclaims = htonl(rx_packetReclaims);
1115             tstat.usedFDs = CountFDs(64);
1116             tstat.nWaiting = htonl(rx_nWaiting);
1117             queue_Count( &rx_idleServerQueue, np, nqe, 
1118                                 rx_serverQueueEntry, tstat.idleThreads); 
1119             tstat.idleThreads = htonl(tstat.idleThreads);
1120             tl = sizeof(struct rx_debugStats) - ap->length;
1121             if (tl > 0)
1122               tl = rxi_AllocDataBuf(ap, tl, RX_PACKET_CLASS_SEND_CBUF);
1123
1124             if (tl <= 0) {
1125               rx_packetwrite(ap, 0, sizeof(struct rx_debugStats), (char *)&tstat);
1126               ap->length = sizeof(struct rx_debugStats);
1127               rxi_SendDebugPacket(ap, asocket, ahost, aport, istack);
1128               rx_computelen(ap, ap->length);
1129             }
1130             break;
1131         }
1132
1133         case RX_DEBUGI_GETALLCONN:
1134         case RX_DEBUGI_GETCONN: {
1135             int i, j;
1136             register struct rx_connection *tc;
1137             struct rx_call *tcall;
1138             struct rx_debugConn tconn;
1139             int all = (tin.type == RX_DEBUGI_GETALLCONN);
1140
1141
1142             tl = sizeof(struct rx_debugConn) - ap->length;
1143             if (tl > 0)
1144               tl = rxi_AllocDataBuf(ap, tl, RX_PACKET_CLASS_SEND_CBUF);
1145             if (tl > 0)
1146               return ap;
1147
1148             memset((char *)&tconn, 0, sizeof(tconn)); /* make sure spares are zero */
1149             /* get N'th (maybe) "interesting" connection info */
1150             for(i=0;i<rx_hashTableSize;i++) {
1151 #if !defined(KERNEL)
1152                 /* the time complexity of the algorithm used here
1153                  * exponentially increses with the number of connections.
1154                  */
1155 #ifdef AFS_PTHREAD_ENV
1156                 pthread_yield();
1157 #else
1158                 (void) IOMGR_Poll();
1159 #endif
1160 #endif
1161                 MUTEX_ENTER(&rx_connHashTable_lock);
1162                 /* We might be slightly out of step since we are not 
1163                  * locking each call, but this is only debugging output.
1164                  */
1165                 for(tc=rx_connHashTable[i]; tc; tc=tc->next) {
1166                     if ((all || rxi_IsConnInteresting(tc)) && tin.index-- <= 0) {
1167                         tconn.host = tc->peer->host;
1168                         tconn.port = tc->peer->port;
1169                         tconn.cid = htonl(tc->cid);
1170                         tconn.epoch = htonl(tc->epoch);
1171                         tconn.serial = htonl(tc->serial);
1172                         for(j=0;j<RX_MAXCALLS;j++) {
1173                             tconn.callNumber[j] = htonl(tc->callNumber[j]);
1174                             if ((tcall=tc->call[j])) {
1175                                 tconn.callState[j] = tcall->state;
1176                                 tconn.callMode[j] = tcall->mode;
1177                                 tconn.callFlags[j] = tcall->flags;
1178                                 if (queue_IsNotEmpty(&tcall->rq))
1179                                     tconn.callOther[j] |= RX_OTHER_IN;
1180                                 if (queue_IsNotEmpty(&tcall->tq))
1181                                     tconn.callOther[j] |= RX_OTHER_OUT;
1182                             }
1183                             else tconn.callState[j] = RX_STATE_NOTINIT;
1184                         }
1185
1186                         tconn.natMTU = htonl(tc->peer->natMTU);
1187                         tconn.error = htonl(tc->error);
1188                         tconn.flags = tc->flags;
1189                         tconn.type = tc->type;
1190                         tconn.securityIndex = tc->securityIndex;
1191                         if (tc->securityObject) {
1192                             RXS_GetStats (tc->securityObject, tc,
1193                                           &tconn.secStats);
1194 #define DOHTONL(a) (tconn.secStats.a = htonl(tconn.secStats.a))
1195 #define DOHTONS(a) (tconn.secStats.a = htons(tconn.secStats.a))
1196                             DOHTONL(flags);
1197                             DOHTONL(expires);
1198                             DOHTONL(packetsReceived);
1199                             DOHTONL(packetsSent);
1200                             DOHTONL(bytesReceived);
1201                             DOHTONL(bytesSent);
1202                             for (i=0;
1203                                  i<sizeof(tconn.secStats.spares)/sizeof(short);
1204                                  i++)
1205                                 DOHTONS(spares[i]);
1206                             for (i=0;
1207                                  i<sizeof(tconn.secStats.sparel)/sizeof(afs_int32);
1208                                  i++)
1209                                 DOHTONL(sparel[i]);
1210                         }
1211
1212                         MUTEX_EXIT(&rx_connHashTable_lock);
1213                         rx_packetwrite(ap, 0, sizeof(struct rx_debugConn), (char*)&tconn);
1214                         tl = ap->length;
1215                         ap->length = sizeof(struct rx_debugConn);
1216                         rxi_SendDebugPacket(ap, asocket, ahost, aport, istack);
1217                         ap->length = tl;
1218                         return ap;
1219                     }
1220                 }
1221                 MUTEX_EXIT(&rx_connHashTable_lock);
1222             }
1223             /* if we make it here, there are no interesting packets */
1224             tconn.cid = htonl(0xffffffff); /* means end */
1225             rx_packetwrite(ap, 0, sizeof(struct rx_debugConn), (char *)&tconn);
1226             tl = ap->length;
1227             ap->length = sizeof(struct rx_debugConn);
1228             rxi_SendDebugPacket(ap, asocket, ahost, aport, istack);
1229             ap->length = tl;
1230             break;
1231         }
1232
1233         /*
1234          * Pass back all the peer structures we have available
1235          */
1236
1237         case RX_DEBUGI_GETPEER: {
1238             int i;
1239             register struct rx_peer *tp;
1240             struct rx_debugPeer tpeer;
1241
1242
1243             tl = sizeof(struct rx_debugPeer) - ap->length;
1244             if (tl > 0)
1245               tl = rxi_AllocDataBuf(ap, tl, RX_PACKET_CLASS_SEND_CBUF);
1246             if (tl > 0)
1247               return ap;
1248
1249             memset((char *)&tpeer, 0, sizeof(tpeer));
1250             for(i=0;i<rx_hashTableSize;i++) {
1251 #if !defined(KERNEL)
1252                 /* the time complexity of the algorithm used here
1253                  * exponentially increses with the number of peers.
1254                  *
1255                  * Yielding after processing each hash table entry
1256                  * and dropping rx_peerHashTable_lock.
1257                  * also increases the risk that we will miss a new
1258                  * entry - but we are willing to live with this
1259                  * limitation since this is meant for debugging only
1260                  */
1261 #ifdef AFS_PTHREAD_ENV
1262                 pthread_yield();
1263 #else
1264                 (void) IOMGR_Poll();
1265 #endif
1266 #endif
1267                 MUTEX_ENTER(&rx_peerHashTable_lock);
1268                 for(tp=rx_peerHashTable[i]; tp; tp=tp->next) {
1269                     if (tin.index-- <= 0) {
1270                         tpeer.host = tp->host;
1271                         tpeer.port = tp->port;
1272                         tpeer.ifMTU = htons(tp->ifMTU);
1273                         tpeer.idleWhen = htonl(tp->idleWhen);
1274                         tpeer.refCount = htons(tp->refCount);
1275                         tpeer.burstSize = tp->burstSize;
1276                         tpeer.burst = tp->burst;
1277                         tpeer.burstWait.sec = htonl(tp->burstWait.sec);
1278                         tpeer.burstWait.usec = htonl(tp->burstWait.usec);
1279                         tpeer.rtt = htonl(tp->rtt);
1280                         tpeer.rtt_dev = htonl(tp->rtt_dev);
1281                         tpeer.timeout.sec = htonl(tp->timeout.sec);
1282                         tpeer.timeout.usec = htonl(tp->timeout.usec);
1283                         tpeer.nSent = htonl(tp->nSent);
1284                         tpeer.reSends = htonl(tp->reSends);
1285                         tpeer.inPacketSkew = htonl(tp->inPacketSkew);
1286                         tpeer.outPacketSkew = htonl(tp->outPacketSkew);
1287                         tpeer.rateFlag = htonl(tp->rateFlag);
1288                         tpeer.natMTU = htons(tp->natMTU);
1289                         tpeer.maxMTU = htons(tp->maxMTU);
1290                         tpeer.maxDgramPackets = htons(tp->maxDgramPackets);
1291                         tpeer.ifDgramPackets = htons(tp->ifDgramPackets);
1292                         tpeer.MTU = htons(tp->MTU);
1293                         tpeer.cwind = htons(tp->cwind);
1294                         tpeer.nDgramPackets = htons(tp->nDgramPackets);
1295                         tpeer.congestSeq = htons(tp->congestSeq);
1296                         tpeer.bytesSent.high = htonl(tp->bytesSent.high);
1297                         tpeer.bytesSent.low = htonl(tp->bytesSent.low);
1298                         tpeer.bytesReceived.high = htonl(tp->bytesReceived.high);
1299                         tpeer.bytesReceived.low = htonl(tp->bytesReceived.low);
1300
1301                         MUTEX_EXIT(&rx_peerHashTable_lock);
1302                         rx_packetwrite(ap, 0, sizeof(struct rx_debugPeer), (char*)&tpeer);
1303                         tl = ap->length;
1304                         ap->length = sizeof(struct rx_debugPeer);
1305                         rxi_SendDebugPacket(ap, asocket, ahost, aport, istack);
1306                         ap->length = tl;
1307                         return ap;
1308                     }
1309                 }
1310                 MUTEX_EXIT(&rx_peerHashTable_lock);
1311             }
1312             /* if we make it here, there are no interesting packets */
1313             tpeer.host = htonl(0xffffffff); /* means end */
1314             rx_packetwrite(ap, 0, sizeof(struct rx_debugPeer), (char *)&tpeer);
1315             tl = ap->length;
1316             ap->length = sizeof(struct rx_debugPeer);
1317             rxi_SendDebugPacket(ap, asocket, ahost, aport, istack);
1318             ap->length = tl;
1319             break;
1320         }
1321
1322         case RX_DEBUGI_RXSTATS: {
1323             int i;
1324             afs_int32 *s;
1325
1326             tl = sizeof(rx_stats) - ap->length;
1327             if (tl > 0)
1328               tl = rxi_AllocDataBuf(ap, tl, RX_PACKET_CLASS_SEND_CBUF);
1329             if (tl > 0)
1330               return ap;
1331
1332             /* Since its all int32s convert to network order with a loop. */
1333             MUTEX_ENTER(&rx_stats_mutex);
1334             s = (afs_int32 *)&rx_stats;
1335             for (i=0; i<sizeof(rx_stats)/sizeof(afs_int32); i++,s++)
1336                 rx_PutInt32(ap, i*sizeof(afs_int32), htonl(*s));
1337
1338             tl = ap->length;
1339             ap->length = sizeof(rx_stats);
1340             MUTEX_EXIT(&rx_stats_mutex);
1341             rxi_SendDebugPacket(ap, asocket, ahost, aport, istack);
1342             ap->length = tl;
1343             break;
1344         }
1345
1346         default:
1347             /* error response packet */
1348             tin.type = htonl(RX_DEBUGI_BADTYPE);
1349             tin.index = tin.type;
1350             rx_packetwrite(ap, 0, sizeof(struct rx_debugIn), (char *)&tin);
1351             tl = ap->length;
1352             ap->length = sizeof(struct rx_debugIn);
1353             rxi_SendDebugPacket(ap, asocket, ahost, aport, istack);
1354             ap->length = tl;
1355             break;
1356     }
1357     return ap;
1358 }
1359
1360 struct rx_packet *rxi_ReceiveVersionPacket(register struct rx_packet *ap, 
1361         osi_socket asocket, afs_int32 ahost, short aport, int istack)
1362 {
1363     afs_int32 tl;
1364
1365     /*
1366      * Only respond to client-initiated version requests, and
1367      * clear that flag in the response.
1368      */
1369     if (ap->header.flags & RX_CLIENT_INITIATED) {
1370         char buf[66];
1371
1372         ap->header.flags = ap->header.flags & ~RX_CLIENT_INITIATED;
1373         rxi_EncodePacketHeader(ap);
1374         memset(buf, 0, sizeof(buf));
1375         strncpy(buf, cml_version_number+4, sizeof(buf)-1);
1376         rx_packetwrite(ap, 0, 65, buf);
1377         tl = ap->length;
1378         ap->length = 65;
1379         rxi_SendDebugPacket(ap, asocket, ahost, aport, istack);
1380         ap->length = tl;
1381     }
1382
1383     return ap;
1384 }
1385
1386
1387 /* send a debug packet back to the sender */
1388 static void rxi_SendDebugPacket(struct rx_packet *apacket, osi_socket asocket,
1389                                afs_int32 ahost, short aport, afs_int32 istack)
1390 {
1391     struct sockaddr_in taddr;
1392     int i;
1393     int nbytes;
1394     int saven = 0;
1395     size_t savelen = 0;
1396 #ifdef KERNEL
1397     int waslocked = ISAFS_GLOCK();
1398 #endif
1399
1400     taddr.sin_family = AF_INET;
1401     taddr.sin_port = aport;
1402     taddr.sin_addr.s_addr = ahost;
1403 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
1404     taddr.sin_len = sizeof(struct sockaddr_in);
1405 #endif
1406
1407     /* We need to trim the niovecs. */
1408     nbytes = apacket->length;
1409     for (i=1; i < apacket->niovecs; i++) {
1410       if (nbytes <= apacket->wirevec[i].iov_len) {
1411         savelen = apacket->wirevec[i].iov_len;
1412         saven = apacket->niovecs;
1413         apacket->wirevec[i].iov_len = nbytes;
1414         apacket->niovecs = i+1;   /* so condition fails because i == niovecs */
1415       }
1416       else nbytes -= apacket->wirevec[i].iov_len;
1417     }
1418     AFS_RXGUNLOCK();
1419 #ifdef KERNEL
1420     if (waslocked) AFS_GUNLOCK();
1421 #endif
1422     /* debug packets are not reliably delivered, hence the cast below. */
1423     (void) osi_NetSend(asocket, &taddr, apacket->wirevec, apacket->niovecs,
1424                        apacket->length+RX_HEADER_SIZE, istack);
1425 #ifdef KERNEL
1426     if (waslocked) AFS_GLOCK();
1427 #endif
1428     AFS_RXGLOCK();
1429     if (saven) {  /* means we truncated the packet above. */
1430       apacket->wirevec[i-1].iov_len = savelen;
1431       apacket->niovecs = saven;
1432     }
1433
1434 }
1435
1436 /* Send the packet to appropriate destination for the specified
1437  * connection.  The header is first encoded and placed in the packet.
1438  */
1439 void rxi_SendPacket(struct rx_connection * conn, struct rx_packet *p,
1440                     int istack)
1441 {
1442 #if defined(KERNEL)
1443     int waslocked;
1444 #endif
1445     struct sockaddr_in addr;
1446     register struct rx_peer *peer = conn->peer;
1447     osi_socket socket;
1448 #ifdef RXDEBUG
1449     char deliveryType = 'S';
1450 #endif
1451     /* The address we're sending the packet to */
1452     memset(&addr, 0, sizeof (addr));
1453     addr.sin_family = AF_INET;
1454     addr.sin_port = peer->port;
1455     addr.sin_addr.s_addr = peer->host;
1456
1457     /* This stuff should be revamped, I think, so that most, if not
1458      * all, of the header stuff is always added here.  We could
1459      * probably do away with the encode/decode routines. XXXXX */
1460
1461     /* Stamp each packet with a unique serial number.  The serial
1462      * number is maintained on a connection basis because some types
1463      * of security may be based on the serial number of the packet,
1464      * and security is handled on a per authenticated-connection
1465      * basis. */
1466     /* Pre-increment, to guarantee no zero serial number; a zero
1467      * serial number means the packet was never sent. */
1468     MUTEX_ENTER(&conn->conn_data_lock);
1469     p->header.serial = ++conn->serial; 
1470     MUTEX_EXIT(&conn->conn_data_lock);
1471     /* This is so we can adjust retransmit time-outs better in the face of 
1472      * rapidly changing round-trip times.  RTO estimation is not a la Karn.
1473      */
1474     if (p->firstSerial == 0) {
1475        p->firstSerial = p->header.serial;
1476      }
1477
1478 #ifdef RXDEBUG
1479     /* If an output tracer function is defined, call it with the packet and
1480      * network address.  Note this function may modify its arguments. */
1481     if (rx_almostSent) {
1482         int drop = (*rx_almostSent) (p, &addr);
1483         /* drop packet if return value is non-zero? */
1484         if (drop) deliveryType = 'D';   /* Drop the packet */
1485     }
1486 #endif
1487
1488     /* Get network byte order header */
1489     rxi_EncodePacketHeader(p);  /* XXX in the event of rexmit, etc, don't need to 
1490                                  * touch ALL the fields */
1491
1492     /* Send the packet out on the same socket that related packets are being
1493      * received on */
1494     socket = (conn->type == RX_CLIENT_CONNECTION
1495               ? rx_socket : conn->service->socket);
1496
1497 #ifdef RXDEBUG
1498     /* Possibly drop this packet,  for testing purposes */
1499     if ((deliveryType == 'D') ||
1500         ((rx_intentionallyDroppedPacketsPer100 > 0) &&
1501          (random() % 100 < rx_intentionallyDroppedPacketsPer100))) {
1502         deliveryType = 'D';             /* Drop the packet */
1503     }
1504     else {
1505         deliveryType = 'S';             /* Send the packet */
1506 #endif /* RXDEBUG */
1507
1508         /* Loop until the packet is sent.  We'd prefer just to use a
1509          * blocking socket, but unfortunately the interface doesn't
1510          * allow us to have the socket block in send mode, and not
1511          * block in receive mode */
1512         AFS_RXGUNLOCK();
1513 #ifdef KERNEL
1514         waslocked = ISAFS_GLOCK();
1515         if (waslocked) AFS_GUNLOCK();
1516 #endif
1517         if (osi_NetSend(socket, &addr, p->wirevec, p->niovecs, 
1518                         p->length+RX_HEADER_SIZE, istack)){
1519           /* send failed, so let's hurry up the resend, eh? */
1520           MUTEX_ENTER(&rx_stats_mutex);
1521           rx_stats.netSendFailures++;      
1522           MUTEX_EXIT(&rx_stats_mutex);
1523           p->retryTime = p->timeSent;  /* resend it very soon */
1524           clock_Addmsec(&(p->retryTime), 10 + (((afs_uint32) p->backoff) << 8));
1525         }
1526 #ifdef KERNEL
1527         if (waslocked) AFS_GLOCK();
1528 #endif
1529         AFS_RXGLOCK();
1530 #ifdef RXDEBUG    
1531     }
1532     dpf(("%c %d %s: %x.%u.%u.%u.%u.%u.%u flags %d, packet %x resend %d.%0.3d len %d",
1533          deliveryType, p->header.serial, rx_packetTypes[p->header.type-1],
1534          peer->host, peer->port, p->header.serial, p->header.epoch,
1535          p->header.cid, p->header.callNumber, p->header.seq, p->header.flags,
1536          p, p->retryTime.sec, p->retryTime.usec/1000, p->length));
1537 #endif
1538     MUTEX_ENTER(&rx_stats_mutex);
1539     rx_stats.packetsSent[p->header.type-1]++;
1540     MUTEX_EXIT(&rx_stats_mutex);
1541     MUTEX_ENTER(&peer->peer_lock);
1542     hadd32(peer->bytesSent, p->length);
1543     MUTEX_EXIT(&peer->peer_lock);
1544 }
1545
1546 /* Send a list of packets to appropriate destination for the specified
1547  * connection.  The headers are first encoded and placed in the packets.
1548  */
1549 void rxi_SendPacketList(struct rx_connection * conn, struct rx_packet **list,
1550         int len, int istack)
1551 {
1552 #if     defined(AFS_SUN5_ENV) && defined(KERNEL)
1553     int waslocked;
1554 #endif
1555     struct sockaddr_in addr;
1556     register struct rx_peer *peer = conn->peer;
1557     osi_socket socket;
1558     struct rx_packet *p = NULL;
1559     struct iovec wirevec[RX_MAXIOVECS];
1560     int i, length;
1561     afs_uint32 serial;
1562     afs_uint32 temp;
1563     struct rx_jumboHeader *jp;
1564 #ifdef RXDEBUG
1565     char deliveryType = 'S';
1566 #endif
1567     /* The address we're sending the packet to */
1568     addr.sin_family = AF_INET;
1569     addr.sin_port = peer->port;
1570     addr.sin_addr.s_addr = peer->host;
1571
1572     if (len+1 > RX_MAXIOVECS) {
1573         osi_Panic("rxi_SendPacketList, len > RX_MAXIOVECS\n");
1574     }
1575
1576     /*
1577      * Stamp the packets in this jumbogram with consecutive serial numbers
1578      */
1579     MUTEX_ENTER(&conn->conn_data_lock);
1580     serial = conn->serial; 
1581     conn->serial += len;
1582     MUTEX_EXIT(&conn->conn_data_lock);
1583
1584
1585     /* This stuff should be revamped, I think, so that most, if not
1586      * all, of the header stuff is always added here.  We could
1587      * probably do away with the encode/decode routines. XXXXX */
1588
1589     jp = NULL;
1590     length = RX_HEADER_SIZE;
1591     wirevec[0].iov_base = (char *)(&list[0]->wirehead[0]);
1592     wirevec[0].iov_len = RX_HEADER_SIZE;
1593     for (i = 0 ; i < len ; i++) {
1594         p = list[i];
1595
1596         /* The whole 3.5 jumbogram scheme relies on packets fitting
1597          * in a single packet buffer. */
1598         if (p->niovecs > 2) {
1599             osi_Panic("rxi_SendPacketList, niovecs > 2\n");
1600         }
1601
1602         /* Set the RX_JUMBO_PACKET flags in all but the last packets
1603          * in this chunk.  */
1604         if (i < len-1) {
1605             if (p->length != RX_JUMBOBUFFERSIZE) {
1606                 osi_Panic("rxi_SendPacketList, length != jumbo size\n");
1607             }
1608             p->header.flags |= RX_JUMBO_PACKET;
1609             length += RX_JUMBOBUFFERSIZE + RX_JUMBOHEADERSIZE;
1610             wirevec[i+1].iov_len = RX_JUMBOBUFFERSIZE + RX_JUMBOHEADERSIZE;
1611         } else {
1612             wirevec[i+1].iov_len = p->length;
1613             length += p->length;
1614         }
1615         wirevec[i+1].iov_base = (char *)(&p->localdata[0]);
1616         if (jp != NULL) {
1617             /* Convert jumbo packet header to network byte order */
1618             temp = (afs_uint32)(p->header.flags) << 24;
1619             temp |= (afs_uint32)(p->header.spare);
1620             *(afs_uint32 *)jp = htonl(temp);
1621         }
1622         jp = (struct rx_jumboHeader *)
1623              ((char *)(&p->localdata[0]) + RX_JUMBOBUFFERSIZE);
1624
1625         /* Stamp each packet with a unique serial number.  The serial
1626          * number is maintained on a connection basis because some types
1627          * of security may be based on the serial number of the packet,
1628          * and security is handled on a per authenticated-connection
1629          * basis. */
1630         /* Pre-increment, to guarantee no zero serial number; a zero
1631          * serial number means the packet was never sent. */
1632         p->header.serial = ++serial; 
1633         /* This is so we can adjust retransmit time-outs better in the face of 
1634          * rapidly changing round-trip times.  RTO estimation is not a la Karn.
1635          */
1636         if (p->firstSerial == 0) {
1637            p->firstSerial = p->header.serial;
1638         }
1639
1640 #ifdef RXDEBUG
1641         /* If an output tracer function is defined, call it with the packet and
1642          * network address.  Note this function may modify its arguments. */
1643         if (rx_almostSent) {
1644             int drop = (*rx_almostSent) (p, &addr);
1645             /* drop packet if return value is non-zero? */
1646             if (drop) deliveryType = 'D';       /* Drop the packet */
1647         }
1648 #endif
1649
1650         /* Get network byte order header */
1651         rxi_EncodePacketHeader(p);      /* XXX in the event of rexmit, etc, don't need to 
1652                                      * touch ALL the fields */
1653     }
1654
1655     /* Send the packet out on the same socket that related packets are being
1656      * received on */
1657     socket = (conn->type == RX_CLIENT_CONNECTION
1658               ? rx_socket : conn->service->socket);
1659
1660 #ifdef RXDEBUG
1661     /* Possibly drop this packet,  for testing purposes */
1662     if ((deliveryType == 'D') ||
1663         ((rx_intentionallyDroppedPacketsPer100 > 0) &&
1664          (random() % 100 < rx_intentionallyDroppedPacketsPer100))) {
1665         deliveryType = 'D';             /* Drop the packet */
1666     }
1667     else {
1668         deliveryType = 'S';             /* Send the packet */
1669 #endif /* RXDEBUG */
1670
1671         /* Loop until the packet is sent.  We'd prefer just to use a
1672          * blocking socket, but unfortunately the interface doesn't
1673          * allow us to have the socket block in send mode, and not
1674          * block in receive mode */
1675         AFS_RXGUNLOCK();
1676 #if     defined(AFS_SUN5_ENV) && defined(KERNEL)
1677         waslocked = ISAFS_GLOCK();
1678         if (!istack && waslocked) AFS_GUNLOCK();
1679 #endif
1680         if (osi_NetSend(socket, &addr, &wirevec[0], len+1, length, istack)){
1681           /* send failed, so let's hurry up the resend, eh? */
1682           MUTEX_ENTER(&rx_stats_mutex);
1683           rx_stats.netSendFailures++;      
1684           MUTEX_EXIT(&rx_stats_mutex);
1685           for (i = 0 ; i < len ; i++) {
1686             p = list[i];
1687             p->retryTime = p->timeSent;  /* resend it very soon */
1688             clock_Addmsec(&(p->retryTime), 10 + (((afs_uint32) p->backoff) << 8));
1689           }
1690         }
1691 #if     defined(AFS_SUN5_ENV) && defined(KERNEL)
1692         if (!istack && waslocked) AFS_GLOCK();
1693 #endif
1694         AFS_RXGLOCK();
1695 #ifdef RXDEBUG    
1696     }
1697     dpf(("%c %d %s: %x.%u.%u.%u.%u.%u.%u flags %d, packet %x resend %d.%0.3d len %d",
1698          deliveryType, p->header.serial, rx_packetTypes[p->header.type-1],
1699          peer->host, peer->port, p->header.serial, p->header.epoch,
1700          p->header.cid, p->header.callNumber, p->header.seq, p->header.flags,
1701          p, p->retryTime.sec, p->retryTime.usec/1000, p->length));
1702 #endif
1703     MUTEX_ENTER(&rx_stats_mutex);
1704     rx_stats.packetsSent[p->header.type-1]++;
1705     MUTEX_EXIT(&rx_stats_mutex);
1706     MUTEX_ENTER(&peer->peer_lock);
1707     hadd32(peer->bytesSent, p->length);
1708     MUTEX_EXIT(&peer->peer_lock);
1709 }
1710
1711
1712 /* Send a "special" packet to the peer connection.  If call is
1713  * specified, then the packet is directed to a specific call channel
1714  * associated with the connection, otherwise it is directed to the
1715  * connection only. Uses optionalPacket if it is supplied, rather than
1716  * allocating a new packet buffer.  Nbytes is the length of the data
1717  * portion of the packet.  If data is non-null, nbytes of data are
1718  * copied into the packet.  Type is the type of the packet, as defined
1719  * in rx.h.  Bug: there's a lot of duplication between this and other
1720  * routines.  This needs to be cleaned up. */
1721 struct rx_packet *rxi_SendSpecial(register struct rx_call *call, 
1722         register struct rx_connection *conn, struct rx_packet *optionalPacket, 
1723         int type, char *data, int nbytes, int istack)
1724 {
1725     /* Some of the following stuff should be common code for all
1726      * packet sends (it's repeated elsewhere) */
1727     register struct rx_packet *p;
1728     unsigned int i = 0;
1729     int savelen = 0, saven = 0;
1730     int channel, callNumber;
1731     if (call) {
1732         channel = call->channel;
1733         callNumber = *call->callNumber;
1734         /* BUSY packets refer to the next call on this connection */
1735         if (type == RX_PACKET_TYPE_BUSY) {
1736             callNumber++;
1737         }
1738     } else {
1739         channel = 0;
1740         callNumber = 0;
1741     }
1742     p = optionalPacket;
1743     if (!p) {
1744         p = rxi_AllocPacket(RX_PACKET_CLASS_SPECIAL);
1745         if (!p) osi_Panic("rxi_SendSpecial failure");
1746     }
1747
1748     if (nbytes != -1) 
1749       p->length = nbytes;
1750     else
1751       nbytes = p->length;
1752     p->header.serviceId = conn->serviceId;
1753     p->header.securityIndex = conn->securityIndex;
1754     p->header.cid = (conn->cid | channel);
1755     p->header.callNumber = callNumber;
1756     p->header.seq = 0;
1757     p->header.epoch = conn->epoch;
1758     p->header.type = type;
1759     p->header.flags = 0;
1760     if (conn->type == RX_CLIENT_CONNECTION) 
1761        p->header.flags |= RX_CLIENT_INITIATED;
1762     if (data) 
1763       rx_packetwrite(p, 0, nbytes, data);
1764
1765     for (i=1; i < p->niovecs; i++) {
1766       if (nbytes <= p->wirevec[i].iov_len) {
1767         savelen = p->wirevec[i].iov_len;
1768         saven = p->niovecs;
1769         p->wirevec[i].iov_len = nbytes;
1770         p->niovecs = i+1;   /* so condition fails because i == niovecs */
1771       }
1772       else nbytes -= p->wirevec[i].iov_len;
1773     }
1774
1775     if (call) rxi_Send(call, p, istack);
1776     else rxi_SendPacket(conn, p, istack);
1777     if (saven) {  /* means we truncated the packet above.  We probably don't  */
1778       /* really need to do this, but it seems safer this way, given that  */
1779       /* sneaky optionalPacket... */
1780       p->wirevec[i-1].iov_len = savelen;
1781       p->niovecs = saven;
1782     }
1783     if (!optionalPacket) rxi_FreePacket(p);
1784     return optionalPacket;
1785 }
1786
1787
1788 /* Encode the packet's header (from the struct header in the packet to
1789  * the net byte order representation in the wire representation of the
1790  * packet, which is what is actually sent out on the wire) */
1791 void rxi_EncodePacketHeader(register struct rx_packet *p)
1792 {
1793     register afs_uint32 *buf = (afs_uint32 *)(p->wirevec[0].iov_base);      /* MTUXXX */
1794
1795     memset((char *)buf, 0, RX_HEADER_SIZE);
1796     *buf++ = htonl(p->header.epoch);
1797     *buf++ = htonl(p->header.cid);
1798     *buf++ = htonl(p->header.callNumber);
1799     *buf++ = htonl(p->header.seq);
1800     *buf++ = htonl(p->header.serial);
1801     *buf++ = htonl(  (((afs_uint32)p->header.type)<<24) 
1802                    | (((afs_uint32)p->header.flags)<<16) 
1803                    | (p->header.userStatus<<8) | p->header.securityIndex);
1804     /* Note: top 16 bits of this next word were reserved */
1805     *buf++ = htonl((p->header.spare << 16) | (p->header.serviceId&0xffff));
1806 }
1807
1808 /* Decode the packet's header (from net byte order to a struct header) */
1809 void rxi_DecodePacketHeader(register struct rx_packet *p)
1810 {
1811     register afs_uint32 *buf = (afs_uint32*)(p->wirevec[0].iov_base);      /* MTUXXX */
1812     afs_uint32 temp;
1813
1814     p->header.epoch = ntohl(*buf);
1815     buf++;
1816     p->header.cid = ntohl(*buf);
1817     buf++;
1818     p->header.callNumber = ntohl(*buf);
1819     buf++;
1820     p->header.seq = ntohl(*buf);
1821     buf++;
1822     p->header.serial = ntohl(*buf);
1823     buf++;
1824
1825     temp = ntohl(*buf);
1826     buf++;
1827
1828     /* C will truncate byte fields to bytes for me */
1829     p->header.type = temp>>24;
1830     p->header.flags = temp>>16;
1831     p->header.userStatus = temp>>8;
1832     p->header.securityIndex = temp>>0;
1833
1834     temp = ntohl(*buf);
1835     buf++;
1836
1837     p->header.serviceId = (temp&0xffff);
1838     p->header.spare = temp>>16;
1839     /* Note: top 16 bits of this last word are the security checksum */
1840 }
1841
1842 void rxi_PrepareSendPacket(register struct rx_call *call, register struct rx_packet *p, 
1843         register int last)
1844 {
1845     register struct rx_connection *conn = call->conn;
1846     int i, j;
1847     ssize_t len;        /* len must be a signed type; it can go negative */
1848
1849     p->flags &= ~RX_PKTFLAG_ACKED;
1850     p->header.cid = (conn->cid | call->channel);
1851     p->header.serviceId = conn->serviceId;
1852     p->header.securityIndex = conn->securityIndex;
1853     p->header.callNumber = *call->callNumber;
1854     p->header.seq = call->tnext++;
1855     p->header.epoch = conn->epoch;
1856     p->header.type = RX_PACKET_TYPE_DATA;
1857     p->header.flags = 0;
1858     p->header.spare = 0;
1859     if (conn->type == RX_CLIENT_CONNECTION) 
1860       p->header.flags |= RX_CLIENT_INITIATED;
1861
1862     if (last)
1863       p->header.flags |= RX_LAST_PACKET;
1864
1865     clock_Zero(&p->retryTime); /* Never yet transmitted */
1866     clock_Zero(&p->firstSent); /* Never yet transmitted */
1867     p->header.serial = 0;      /* Another way of saying never transmitted... */
1868     p->backoff = 0;
1869
1870     /* Now that we're sure this is the last data on the call, make sure
1871      * that the "length" and the sum of the iov_lens matches. */
1872     len = p->length + call->conn->securityHeaderSize;
1873
1874     for (i=1; i < p->niovecs && len > 0; i++) {
1875       len -=  p->wirevec[i].iov_len;
1876     }
1877     if (len > 0) {
1878       osi_Panic("PrepareSendPacket 1\n"); /* MTUXXX */
1879     }
1880     else {
1881       /* Free any extra elements in the wirevec */
1882       for (j = MAX(2,i) ; j < p->niovecs ; j++) {
1883         rxi_freeCBuf(RX_CBUF_TO_PACKET(p->wirevec[j].iov_base, p));
1884       }
1885       p->niovecs = i;
1886       p->wirevec[i-1].iov_len += len;
1887     }
1888     RXS_PreparePacket(conn->securityObject, call, p);
1889 }
1890
1891 /* Given an interface MTU size, calculate an adjusted MTU size that
1892  * will make efficient use of the RX buffers when the peer is sending
1893  * either AFS 3.4a jumbograms or AFS 3.5 jumbograms.  */
1894 int rxi_AdjustIfMTU(int mtu)
1895 {
1896     int adjMTU;
1897     int frags;
1898
1899     adjMTU = RX_HEADER_SIZE + RX_JUMBOBUFFERSIZE + RX_JUMBOHEADERSIZE;
1900     if (mtu <= adjMTU) {
1901         return mtu;
1902     }
1903     mtu -= adjMTU;
1904     if (mtu <= 0) {
1905         return adjMTU;
1906     }
1907     frags = mtu / (RX_JUMBOBUFFERSIZE + RX_JUMBOHEADERSIZE);
1908     return (adjMTU + (frags * (RX_JUMBOBUFFERSIZE + RX_JUMBOHEADERSIZE)));
1909 }
1910
1911 /* Given an interface MTU size, and the peer's advertised max receive
1912  * size, calculate an adjisted maxMTU size that makes efficient use
1913  * of our packet buffers when we are sending AFS 3.4a jumbograms. */
1914 int rxi_AdjustMaxMTU(int mtu, int peerMaxMTU)
1915 {
1916     int maxMTU = mtu * rxi_nSendFrags;
1917     maxMTU = MIN(maxMTU, peerMaxMTU);
1918     return rxi_AdjustIfMTU(maxMTU);
1919 }
1920
1921 /* Given a packet size, figure out how many datagram packet will fit.
1922  * The first buffer always contains RX_HEADER_SIZE+RX_JUMBOBUFFERSIZE+
1923  * RX_JUMBOHEADERSIZE, the middle buffers contain RX_JUMBOBUFFERSIZE+
1924  * RX_JUMBOHEADERSIZE, and the last buffer contains RX_JUMBOBUFFERSIZE */
1925 int rxi_AdjustDgramPackets(int frags, int mtu)
1926 {
1927     int maxMTU;
1928     if (mtu + IPv6_FRAG_HDR_SIZE < RX_JUMBOBUFFERSIZE + RX_HEADER_SIZE) {
1929         return 1;
1930     }
1931     maxMTU = (frags * (mtu + UDP_HDR_SIZE)) - UDP_HDR_SIZE;
1932     maxMTU = MIN(maxMTU, RX_MAX_PACKET_SIZE);
1933     /* subtract the size of the first and last packets */
1934     maxMTU -= RX_HEADER_SIZE + (2 * RX_JUMBOBUFFERSIZE) + RX_JUMBOHEADERSIZE;
1935     if (maxMTU < 0) {
1936         return 1;
1937     }
1938     return (2 + (maxMTU / (RX_JUMBOBUFFERSIZE + RX_JUMBOHEADERSIZE)));
1939 }