fpq-bulk-free-math-error-20051101
[openafs.git] / src / rx / rx_packet.c
index 362e6fa..33eed24 100644 (file)
@@ -7,48 +7,70 @@
  * directory or online at http://www.openafs.org/dl/license10.html
  */
 
+#include <afsconfig.h>
+#ifdef KERNEL
+#include "afs/param.h"
+#else
+#include <afs/param.h>
+#endif
+
+RCSID
+    ("$Header$");
+
 #ifdef KERNEL
-#include "../afs/param.h"
 #if defined(UKERNEL)
-#include "../afs/sysincludes.h"
-#include "../afs/afsincludes.h"
-#include "../rx/rx_kcommon.h"
-#include "../rx/rx_clock.h"
-#include "../rx/rx_queue.h"
-#include "../rx/rx_packet.h"
+#include "afs/sysincludes.h"
+#include "afsincludes.h"
+#include "rx/rx_kcommon.h"
+#include "rx/rx_clock.h"
+#include "rx/rx_queue.h"
+#include "rx/rx_packet.h"
 #else /* defined(UKERNEL) */
-#include "../h/types.h"
+#ifdef RX_KERNEL_TRACE
+#include "../rx/rx_kcommon.h"
+#endif
+#include "h/types.h"
 #ifndef AFS_LINUX20_ENV
-#include "../h/systm.h"
+#include "h/systm.h"
 #endif
 #if defined(AFS_SGI_ENV) || defined(AFS_HPUX110_ENV)
-#include "../afs/sysincludes.h"
+#include "afs/sysincludes.h"
 #endif
-#include "../h/socket.h"
-#include "../netinet/in.h"
-#include "../afs/afs_osi.h"
-#include "../rx/rx_kmutex.h"
-#include "../rx/rx_clock.h"
-#include "../rx/rx_queue.h"
-#ifdef AFS_SUN5_ENV
-#include <sys/sysmacros.h>
+#if defined(AFS_OBSD_ENV)
+#include "h/proc.h"
 #endif
-#include "../rx/rx_packet.h"
-#if !defined(AFS_SUN5_ENV) &&  !defined(AFS_LINUX20_ENV)
+#include "h/socket.h"
+#if !defined(AFS_SUN5_ENV) &&  !defined(AFS_LINUX20_ENV) && !defined(AFS_HPUX110_ENV)
 #if    !defined(AFS_OSF_ENV) && !defined(AFS_AIX41_ENV)
-#include "../sys/mount.h"   /* it gets pulled in by something later anyway */
+#include "sys/mount.h"         /* it gets pulled in by something later anyway */
+#endif
+#include "h/mbuf.h"
 #endif
-#include "../h/mbuf.h"
+#include "netinet/in.h"
+#include "afs/afs_osi.h"
+#include "rx_kmutex.h"
+#include "rx/rx_clock.h"
+#include "rx/rx_queue.h"
+#ifdef AFS_SUN5_ENV
+#include <sys/sysmacros.h>
 #endif
+#include "rx/rx_packet.h"
 #endif /* defined(UKERNEL) */
-#include "../rx/rx_globals.h"
+#include "rx/rx_globals.h"
 #else /* KERNEL */
-#include <afs/param.h>
 #include "sys/types.h"
 #include <sys/stat.h>
 #include <errno.h>
+#if defined(AFS_NT40_ENV) || defined(AFS_DJGPP_ENV)
 #ifdef AFS_NT40_ENV
 #include <winsock2.h>
+#ifndef EWOULDBLOCK
+#define EWOULDBLOCK WSAEWOULDBLOCK
+#endif
+#else
+#include <sys/socket.h>
+#include <netinet/in.h>
+#endif /* AFS_NT40_ENV */
 #include "rx_xmit_nt.h"
 #include <stdlib.h>
 #else
 #include "rx_packet.h"
 #include "rx_globals.h"
 #include <lwp.h>
-#include "rx_internal.h"
+#include <assert.h>
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
 #endif /* KERNEL */
 
-
 #ifdef RX_LOCKS_DB
 /* rxdb_fileID is used to identify the lock location, along with line#. */
 static int rxdb_fileID = RXDB_FILE_RX_PACKET;
@@ -75,14 +106,14 @@ static int rxdb_fileID = RXDB_FILE_RX_PACKET;
 struct rx_packet *rx_mallocedP = 0;
 
 extern char cml_version_number[];
-extern int (*rx_almostSent)();
+extern int (*rx_almostSent) ();
+
+static int AllocPacketBufs(int class, int num_pkts, struct rx_queue *q);
 
-void rxi_FreePacketNoLock(struct rx_packet *p);
 static void rxi_SendDebugPacket(struct rx_packet *apacket, osi_socket asocket,
-                              afs_int32 ahost, short aport, afs_int32 istack);
+                               afs_int32 ahost, short aport,
+                               afs_int32 istack);
 
-extern char cml_version_number[];
-extern int (*rx_almostSent)();
 /* some rules about packets:
  * 1.  When a packet is allocated, the final iov_buf contains room for
  * a security trailer, but iov_len masks that fact.  If the security
@@ -95,39 +126,43 @@ extern int (*rx_almostSent)();
  *        all packet buffers (iov_base) are integral multiples of 
  *       the word size.
  *        offset is an integral multiple of the word size.
- */ 
-afs_int32 rx_SlowGetInt32(struct rx_packet *packet, size_t offset)
+ */
+afs_int32
+rx_SlowGetInt32(struct rx_packet *packet, size_t offset)
 {
-  unsigned int i;
-  size_t l;
-  for (l=0, i=1; i< packet->niovecs ; i++ ) {
-    if (l + packet->wirevec[i].iov_len > offset) {
-      return *((afs_int32 *)((char*)(packet->wirevec[i].iov_base) + (offset-l)));
-    }      
-    l += packet->wirevec[i].iov_len;
-  }
-  
-  return 0;
+    unsigned int i;
+    size_t l;
+    for (l = 0, i = 1; i < packet->niovecs; i++) {
+       if (l + packet->wirevec[i].iov_len > offset) {
+           return
+               *((afs_int32 *) ((char *)(packet->wirevec[i].iov_base) +
+                                (offset - l)));
+       }
+       l += packet->wirevec[i].iov_len;
+    }
+
+    return 0;
 }
 
 /* Preconditions:
  *        all packet buffers (iov_base) are integral multiples of the word size.
  *        offset is an integral multiple of the word size.
- */ 
-afs_int32 rx_SlowPutInt32(struct rx_packet *packet, size_t offset, afs_int32 data)
+ */
+afs_int32
+rx_SlowPutInt32(struct rx_packet * packet, size_t offset, afs_int32 data)
 {
-  unsigned int i;
-  size_t l;
-  for (l=0, i=1; i< packet->niovecs ; i++ ) {
-    if (l + packet->wirevec[i].iov_len > offset) {
-      *((afs_int32 *)((char*)(packet->wirevec[i].iov_base) + (offset - l))) =
-         data;
-      return 0;
-    }      
-    l += packet->wirevec[i].iov_len;
-  }
-  
-  return 0;
+    unsigned int i;
+    size_t l;
+    for (l = 0, i = 1; i < packet->niovecs; i++) {
+       if (l + packet->wirevec[i].iov_len > offset) {
+           *((afs_int32 *) ((char *)(packet->wirevec[i].iov_base) +
+                            (offset - l))) = data;
+           return 0;
+       }
+       l += packet->wirevec[i].iov_len;
+    }
+
+    return 0;
 }
 
 /* Preconditions:
@@ -136,32 +171,36 @@ afs_int32 rx_SlowPutInt32(struct rx_packet *packet, size_t offset, afs_int32 dat
  *        offset is an integral multiple of the word size.
  * Packet Invariants:
  *         all buffers are contiguously arrayed in the iovec from 0..niovecs-1
- */ 
-afs_int32 rx_SlowReadPacket(struct rx_packet *packet, unsigned int offset,
-                       int resid, char *out)
+ */
+afs_int32
+rx_SlowReadPacket(struct rx_packet * packet, unsigned int offset, int resid,
+                 char *out)
 {
-  unsigned int i, j, l, r;
-  for (l=0, i=1; i< packet->niovecs ; i++ ) {
-    if (l + packet->wirevec[i].iov_len > offset) {
-      break;
-    }      
-    l += packet->wirevec[i].iov_len;
-  }
-  
-  /* i is the iovec which contains the first little bit of data in which we
-   * are interested.  l is the total length of everything prior to this iovec.
-   * j is the number of bytes we can safely copy out of this iovec.
-   */
-  r = resid;
-  while ((resid > 0) && (i < packet->niovecs)) {
-    j = MIN (resid, packet->wirevec[i].iov_len - (offset - l));
-    bcopy ((char *)(packet->wirevec[i].iov_base) + (offset - l), out, j);
-    resid -= j;
-    l += packet->wirevec[i].iov_len;
-    i++;  
-  }
-  
-  return (resid ? (r - resid) : r);
+    unsigned int i, j, l, r;
+    for (l = 0, i = 1; i < packet->niovecs; i++) {
+       if (l + packet->wirevec[i].iov_len > offset) {
+           break;
+       }
+       l += packet->wirevec[i].iov_len;
+    }
+
+    /* i is the iovec which contains the first little bit of data in which we
+     * are interested.  l is the total length of everything prior to this iovec.
+     * j is the number of bytes we can safely copy out of this iovec.
+     * offset only applies to the first iovec.
+     */
+    r = resid;
+    while ((resid > 0) && (i < packet->niovecs)) {
+       j = MIN(resid, packet->wirevec[i].iov_len - (offset - l));
+       memcpy(out, (char *)(packet->wirevec[i].iov_base) + (offset - l), j);
+       resid -= j;
+        out += j;
+       l += packet->wirevec[i].iov_len;
+       offset = l;
+       i++;
+    }
+
+    return (resid ? (r - resid) : r);
 }
 
 
@@ -169,58 +208,115 @@ afs_int32 rx_SlowReadPacket(struct rx_packet *packet, unsigned int offset,
  *        all packet buffers (iov_base) are integral multiples of the
  *        word size.
  *        offset is an integral multiple of the word size.
- */ 
-afs_int32 rx_SlowWritePacket(struct rx_packet *packet, int offset, int resid,
-                        char *in)
+ */
+afs_int32
+rx_SlowWritePacket(struct rx_packet * packet, int offset, int resid, char *in)
 {
-  int i, j, l, r;
-  char * b;
-  
-  for (l=0, i=1; i < packet->niovecs; i++ ) {
-    if (l + packet->wirevec[i].iov_len > offset) {
-      break;
-    }      
-    l += packet->wirevec[i].iov_len;
-  }
-  
-  /* i is the iovec which contains the first little bit of data in which we
-   * are interested.  l is the total length of everything prior to this iovec.
-   * j is the number of bytes we can safely copy out of this iovec.
-   */
-  r = resid;
-  while ((resid > 0) && (i < RX_MAXWVECS)) {
-    if (i >= packet->niovecs) 
-      if (rxi_AllocDataBuf(packet, resid, RX_PACKET_CLASS_SEND_CBUF) >0) /* ++niovecs as a side-effect */
-       break;
-    
-    b = (char*)(packet->wirevec[i].iov_base) + (offset - l);
-    j = MIN (resid, packet->wirevec[i].iov_len - (offset - l));
-    bcopy (in, b, j);
-    resid -= j;
-    l += packet->wirevec[i].iov_len;
-    i++;  
-  }
-  
-  return (resid ? (r - resid) : r);
+    int i, j, l, r;
+    char *b;
+
+    for (l = 0, i = 1; i < packet->niovecs; i++) {
+       if (l + packet->wirevec[i].iov_len > offset) {
+           break;
+       }
+       l += packet->wirevec[i].iov_len;
+    }
+
+    /* i is the iovec which contains the first little bit of data in which we
+     * are interested.  l is the total length of everything prior to this iovec.
+     * j is the number of bytes we can safely copy out of this iovec.
+     * offset only applies to the first iovec.
+     */
+    r = resid;
+    while ((resid > 0) && (i < RX_MAXWVECS)) {
+       if (i >= packet->niovecs)
+           if (rxi_AllocDataBuf(packet, resid, RX_PACKET_CLASS_SEND_CBUF) > 0) /* ++niovecs as a side-effect */
+               break;
+
+       b = (char *)(packet->wirevec[i].iov_base) + (offset - l);
+       j = MIN(resid, packet->wirevec[i].iov_len - (offset - l));
+       memcpy(b, in, j);
+       resid -= j;
+        in += j;
+       l += packet->wirevec[i].iov_len;
+       offset = l;
+       i++;
+    }
+
+    return (resid ? (r - resid) : r);
 }
 
-static struct rx_packet * allocCBuf(int class)
+int
+rxi_AllocPackets(int class, int num_pkts, struct rx_queue * q)
 {
-  struct rx_packet *c;
-#ifndef KERNEL
-  extern void rxi_MorePacketsNoLock();
-#endif /* !KERNEL */
-  SPLVAR;
-  
-  NETPRI;
-  MUTEX_ENTER(&rx_freePktQ_lock);
+    register struct rx_packet *p, *np;
+
+    num_pkts = AllocPacketBufs(class, num_pkts, q);
+
+    for (queue_Scan(q, p, np, rx_packet)) {
+        RX_PACKET_IOV_FULLINIT(p);
+    }
+
+    return num_pkts;
+}
+
+#ifdef RX_ENABLE_TSFPQ
+static int
+AllocPacketBufs(int class, int num_pkts, struct rx_queue * q)
+{
+    register struct rx_packet *c;
+    register struct rx_ts_info_t * rx_ts_info;
+    int transfer, alloc;
+    SPLVAR;
+
+    RX_TS_INFO_GET(rx_ts_info);
+
+    transfer = num_pkts - rx_ts_info->_FPQ.len;
+    if (transfer > 0) {
+        NETPRI;
+        MUTEX_ENTER(&rx_freePktQ_lock);
+       
+       if ((transfer + rx_TSFPQGlobSize) <= rx_nFreePackets) {
+           transfer += rx_TSFPQGlobSize;
+       } else if (transfer <= rx_nFreePackets) {
+           transfer = rx_nFreePackets;
+       } else {
+           /* alloc enough for us, plus a few globs for other threads */
+           alloc = transfer + (3 * rx_TSFPQGlobSize) - rx_nFreePackets;
+           rxi_MorePacketsNoLock(MAX(alloc, rx_initSendWindow));
+           transfer += rx_TSFPQGlobSize;
+       }
+
+       RX_TS_FPQ_GTOL2(rx_ts_info, transfer);
+
+       MUTEX_EXIT(&rx_freePktQ_lock);
+       USERPRI;
+    }
+
+    RX_TS_FPQ_CHECKOUT2(rx_ts_info, num_pkts, q);
+
+    return num_pkts;
+}
+#else /* RX_ENABLE_TSFPQ */
+static int
+AllocPacketBufs(int class, int num_pkts, struct rx_queue * q)
+{
+    struct rx_packet *c;
+    int i, overq = 0;
+    SPLVAR;
+
+    NETPRI;
+
+    MUTEX_ENTER(&rx_freePktQ_lock);
 
 #ifdef KERNEL
-  if (rxi_OverQuota(class)) {
-    c = NULL;
-    rxi_NeedMorePackets = TRUE;
-    MUTEX_ENTER(&rx_stats_mutex);
-    switch(class) {
+    for (; (num_pkts > 0) && (rxi_OverQuota2(class,num_pkts)); 
+        num_pkts--, overq++);
+
+    if (overq) {
+       rxi_NeedMorePackets = TRUE;
+       MUTEX_ENTER(&rx_stats_mutex);
+       switch (class) {
        case RX_PACKET_CLASS_RECEIVE:
            rx_stats.receivePktAllocFailures++;
            break;
@@ -236,54 +332,114 @@ static struct rx_packet * allocCBuf(int class)
        case RX_PACKET_CLASS_SEND_CBUF:
            rx_stats.sendCbufPktAllocFailures++;
            break;
+       }
+       MUTEX_EXIT(&rx_stats_mutex);
+    }
+
+    if (rx_nFreePackets < num_pkts)
+        num_pkts = rx_nFreePackets;
+
+    if (!num_pkts) {
+       rxi_NeedMorePackets = TRUE;
+       goto done;
     }
-    MUTEX_EXIT(&rx_stats_mutex);
-    goto done;
-  }
-  
-  if (queue_IsEmpty(&rx_freePacketQueue)) {
-    c = NULL;
-    rxi_NeedMorePackets = TRUE;
-    goto done;
-  }
 #else /* KERNEL */
-  if (queue_IsEmpty(&rx_freePacketQueue)) {
-    rxi_MorePacketsNoLock(rx_initSendWindow);
-  }
+    if (rx_nFreePackets < num_pkts) {
+        rxi_MorePacketsNoLock(MAX((num_pkts-rx_nFreePackets), rx_initSendWindow));
+    }
 #endif /* KERNEL */
-  
-  rx_nFreePackets--;
-  c = queue_First(&rx_freePacketQueue, rx_packet);
-  queue_Remove(c);
-  if (c->header.flags != RX_FREE_PACKET)
-    osi_Panic("rxi_AllocPacket: packet not free\n");
-  c->header.flags = 0;
-  
- done:
-  MUTEX_EXIT(&rx_freePktQ_lock);
-  
-  USERPRI;
-  return c;
+
+    for (i=0, c=queue_First(&rx_freePacketQueue, rx_packet);
+        i < num_pkts; 
+        i++, c=queue_Next(c, rx_packet)) {
+        RX_FPQ_MARK_USED(c);
+    }
+
+    queue_SplitBeforeAppend(&rx_freePacketQueue,q,c);
+
+    rx_nFreePackets -= num_pkts;
+
+#ifdef KERNEL
+  done:
+#endif
+    MUTEX_EXIT(&rx_freePktQ_lock);
+
+    USERPRI;
+    return num_pkts;
 }
+#endif /* RX_ENABLE_TSFPQ */
 
 /*
  * Free a packet currently used as a continuation buffer
  */
-void rxi_freeCBuf(struct rx_packet *c)
+#ifdef RX_ENABLE_TSFPQ
+/* num_pkts=0 means queue length is unknown */
+int
+rxi_FreePackets(int num_pkts, struct rx_queue * q)
 {
-  extern void rxi_PacketsUnWait();
-  SPLVAR;
-  
-  NETPRI;
-  MUTEX_ENTER(&rx_freePktQ_lock);
-  
-  rxi_FreePacketNoLock(c);
-  /* Wakeup anyone waiting for packets */
-  rxi_PacketsUnWait();
-  
-  MUTEX_EXIT(&rx_freePktQ_lock);
-  USERPRI;
+    register struct rx_ts_info_t * rx_ts_info;
+    register struct rx_packet *c, *nc;
+    SPLVAR;
+
+    if (!num_pkts) {
+       queue_Count(q, c, nc, rx_packet, num_pkts);
+       if (!num_pkts)
+           return 0;
+    }
+
+    RX_TS_INFO_GET(rx_ts_info);
+    RX_TS_FPQ_CHECKIN2(rx_ts_info, num_pkts, q);
+
+    if (rx_ts_info->_FPQ.len > rx_TSFPQLocalMax) {
+        NETPRI;
+       MUTEX_ENTER(&rx_freePktQ_lock);
+
+       RX_TS_FPQ_LTOG(rx_ts_info);
+
+       /* Wakeup anyone waiting for packets */
+       rxi_PacketsUnWait();
+
+       MUTEX_EXIT(&rx_freePktQ_lock);
+       USERPRI;
+    }
+
+    return num_pkts;
+}
+#else /* RX_ENABLE_TSFPQ */
+/* num_pkts=0 means queue length is unknown */
+int
+rxi_FreePackets(int num_pkts, struct rx_queue *q)
+{
+    register struct rx_packet *p, *np;
+    SPLVAR;
+
+    if (!num_pkts) {
+        for (queue_Scan(q, p, np, rx_packet), num_pkts++) {
+            RX_FPQ_MARK_FREE(p);
+       }
+       if (!num_pkts)
+           return 0;
+    } else {
+        for (queue_Scan(q, p, np, rx_packet)) {
+            RX_FPQ_MARK_FREE(p);
+       }
+    }
+
+    NETPRI;
+    MUTEX_ENTER(&rx_freePktQ_lock);
+
+    queue_SpliceAppend(&rx_freePacketQueue, q);
+    rx_nFreePackets += num_pkts;
+
+    /* Wakeup anyone waiting for packets */
+    rxi_PacketsUnWait();
+
+    MUTEX_EXIT(&rx_freePktQ_lock);
+    USERPRI;
+
+    return num_pkts;
 }
+#endif /* RX_ENABLE_TSFPQ */
 
 /* this one is kind of awful.
  * In rxkad, the packet has been all shortened, and everything, ready for 
@@ -291,138 +447,270 @@ void rxi_freeCBuf(struct rx_packet *c)
  * This isn't terribly general, because it knows that the packets are only
  * rounded up to the EBS (userdata + security header).
  */
-int rxi_RoundUpPacket(p, nb)
-     struct rx_packet * p;
-     unsigned int nb;
+int
+rxi_RoundUpPacket(struct rx_packet *p, unsigned int nb)
 {
-  int i;
-  i = p->niovecs - 1;
-  if (p->wirevec[i].iov_base == (caddr_t) p->localdata) {
-    if (p->wirevec[i].iov_len <= RX_FIRSTBUFFERSIZE - nb) {
-      p->wirevec[i].iov_len += nb;
-      return 0;
-    }
-  }
-  else {
-    if (p->wirevec[i].iov_len <= RX_CBUFFERSIZE - nb) {
-      p->wirevec[i].iov_len += nb;
-      return 0;
-    }
-  }
-
-return 0;
+    int i;
+    i = p->niovecs - 1;
+    if (p->wirevec[i].iov_base == (caddr_t) p->localdata) {
+       if (p->wirevec[i].iov_len <= RX_FIRSTBUFFERSIZE - nb) {
+           p->wirevec[i].iov_len += nb;
+           return 0;
+       }
+    } else {
+       if (p->wirevec[i].iov_len <= RX_CBUFFERSIZE - nb) {
+           p->wirevec[i].iov_len += nb;
+           return 0;
+       }
+    }
+
+    return 0;
 }
+
 /* get sufficient space to store nb bytes of data (or more), and hook
  * it into the supplied packet.  Return nbytes<=0 if successful, otherwise
  * returns the number of bytes >0 which it failed to come up with.
  * Don't need to worry about locking on packet, since only
  * one thread can manipulate one at a time. Locking on continution
- * packets is handled by allocCBuf */
+ * packets is handled by AllocPacketBufs */
 /* MTUXXX don't need to go throught the for loop if we can trust niovecs */
-int rxi_AllocDataBuf(struct rx_packet *p, int nb, int class) 
+int
+rxi_AllocDataBuf(struct rx_packet *p, int nb, int class)
 {
-  int i;
-  
-  for (i=p->niovecs; nb>0 && i<RX_MAXWVECS; i++) {  
-      register struct rx_packet *cb;
-      if (cb = allocCBuf(class)) {
-         p->wirevec[i].iov_base = (caddr_t) cb->localdata;
-         p->wirevec[i].iov_len = RX_CBUFFERSIZE;
-         nb -= RX_CBUFFERSIZE;
-         p->length += RX_CBUFFERSIZE;
-         p->niovecs++;
-      }
-      else break;
-  }
-  
-  return nb; 
+    int i, nv;
+    struct rx_queue q;
+    register struct rx_packet *cb, *ncb;
+
+    /* compute the number of cbuf's we need */
+    nv = nb / RX_CBUFFERSIZE;
+    if ((nv * RX_CBUFFERSIZE) < nb)
+        nv++;
+    if ((nv + p->niovecs) > RX_MAXWVECS)
+        nv = RX_MAXWVECS - p->niovecs;
+    if (nv < 1)
+        return nb;
+
+    /* allocate buffers */
+    queue_Init(&q);
+    nv = AllocPacketBufs(class, nv, &q);
+
+    /* setup packet iovs */
+    for (i = p->niovecs, queue_Scan(&q, cb, ncb, rx_packet), i++) {
+        queue_Remove(cb);
+        p->wirevec[i].iov_base = (caddr_t) cb->localdata;
+        p->wirevec[i].iov_len = RX_CBUFFERSIZE;
+    }
+
+    nb -= (nv * RX_CBUFFERSIZE);
+    p->length += (nv * RX_CBUFFERSIZE);
+    p->niovecs += nv;
+
+    return nb;
 }
 
 /* Add more packet buffers */
-void rxi_MorePackets(int apackets)
+#ifdef RX_ENABLE_TSFPQ
+void
+rxi_MorePackets(int apackets)
 {
-  extern void rxi_PacketsUnWait();
-  struct rx_packet *p, *e;
-  int getme;
-  SPLVAR;
-
-  getme = apackets * sizeof(struct rx_packet);
-  p = rx_mallocedP = (struct rx_packet *) osi_Alloc(getme);
-
-  PIN(p, getme);       /* XXXXX */
-  bzero((char *)p, getme);
-  NETPRI;
-  AFS_RXGLOCK();
-  MUTEX_ENTER(&rx_freePktQ_lock);
-
-  for (e = p + apackets; p<e; p++) {
-    p->wirevec[0].iov_base = (char *) (p->wirehead);
-    p->wirevec[0].iov_len  = RX_HEADER_SIZE;
-    p->wirevec[1].iov_base = (char *) (p->localdata);
-    p->wirevec[1].iov_len  = RX_FIRSTBUFFERSIZE;
-    p->header.flags = RX_FREE_PACKET;
-    p->niovecs = 2;
-    
-    queue_Append(&rx_freePacketQueue, p);
-  }
-  rx_nFreePackets += apackets;
-  rxi_NeedMorePackets = FALSE;
-  rxi_PacketsUnWait();
-  
-  AFS_RXGUNLOCK();
-  MUTEX_EXIT(&rx_freePktQ_lock);
-  USERPRI;
+    struct rx_packet *p, *e;
+    register struct rx_ts_info_t * rx_ts_info;
+    int getme;
+    SPLVAR;
+
+    getme = apackets * sizeof(struct rx_packet);
+    p = rx_mallocedP = (struct rx_packet *)osi_Alloc(getme);
+
+    PIN(p, getme);             /* XXXXX */
+    memset((char *)p, 0, getme);
+    RX_TS_INFO_GET(rx_ts_info);
+
+    for (e = p + apackets; p < e; p++) {
+        RX_PACKET_IOV_INIT(p);
+       p->niovecs = 2;
+
+       RX_TS_FPQ_CHECKIN(rx_ts_info,p);
+    }
+    rx_ts_info->_FPQ.delta += apackets;
+
+    if (rx_ts_info->_FPQ.len > rx_TSFPQLocalMax) {
+        NETPRI;
+       MUTEX_ENTER(&rx_freePktQ_lock);
+
+       RX_TS_FPQ_LTOG(rx_ts_info);
+       rxi_NeedMorePackets = FALSE;
+       rxi_PacketsUnWait();
+
+       MUTEX_EXIT(&rx_freePktQ_lock);
+       USERPRI;
+    }
 }
+#else /* RX_ENABLE_TSFPQ */
+void
+rxi_MorePackets(int apackets)
+{
+    struct rx_packet *p, *e;
+    int getme;
+    SPLVAR;
+
+    getme = apackets * sizeof(struct rx_packet);
+    p = rx_mallocedP = (struct rx_packet *)osi_Alloc(getme);
+
+    PIN(p, getme);             /* XXXXX */
+    memset((char *)p, 0, getme);
+    NETPRI;
+    MUTEX_ENTER(&rx_freePktQ_lock);
+
+    for (e = p + apackets; p < e; p++) {
+        RX_PACKET_IOV_INIT(p);
+       p->flags |= RX_PKTFLAG_FREE;
+       p->niovecs = 2;
+
+       queue_Append(&rx_freePacketQueue, p);
+    }
+    rx_nFreePackets += apackets;
+    rxi_NeedMorePackets = FALSE;
+    rxi_PacketsUnWait();
+
+    MUTEX_EXIT(&rx_freePktQ_lock);
+    USERPRI;
+}
+#endif /* RX_ENABLE_TSFPQ */
+
+#ifdef RX_ENABLE_TSFPQ
+void
+rxi_MorePacketsTSFPQ(int apackets, int flush_global, int num_keep_local)
+{
+    struct rx_packet *p, *e;
+    register struct rx_ts_info_t * rx_ts_info;
+    int getme;
+    SPLVAR;
+
+    getme = apackets * sizeof(struct rx_packet);
+    p = rx_mallocedP = (struct rx_packet *)osi_Alloc(getme);
+
+    PIN(p, getme);             /* XXXXX */
+    memset((char *)p, 0, getme);
+    RX_TS_INFO_GET(rx_ts_info);
+
+    for (e = p + apackets; p < e; p++) {
+        RX_PACKET_IOV_INIT(p);
+       p->niovecs = 2;
+
+       RX_TS_FPQ_CHECKIN(rx_ts_info,p);
+    }
+    rx_ts_info->_FPQ.delta += apackets;
+
+    if (flush_global && 
+        (num_keep_local < apackets)) {
+        NETPRI;
+       MUTEX_ENTER(&rx_freePktQ_lock);
+
+       RX_TS_FPQ_LTOG2(rx_ts_info, (apackets - num_keep_local));
+       rxi_NeedMorePackets = FALSE;
+       rxi_PacketsUnWait();
+
+       MUTEX_EXIT(&rx_freePktQ_lock);
+       USERPRI;
+    }
+}
+#endif /* RX_ENABLE_TSFPQ */
 
 #ifndef KERNEL
 /* Add more packet buffers */
-void rxi_MorePacketsNoLock(int apackets)
+void
+rxi_MorePacketsNoLock(int apackets)
 {
-  extern void rxi_PacketsUnWait();
-  struct rx_packet *p, *e;
-  int getme;
-
-  /* allocate enough packets that 1/4 of the packets will be able
-   * to hold maximal amounts of data */ 
-  apackets += (apackets/4)
-             * ((rx_maxJumboRecvSize - RX_FIRSTBUFFERSIZE)/RX_CBUFFERSIZE);
-  getme = apackets * sizeof(struct rx_packet);
-  p = rx_mallocedP = (struct rx_packet *) osi_Alloc(getme);
-
-  bzero((char *)p, getme);
-
-  for (e = p + apackets; p<e; p++) {
-    p->wirevec[0].iov_base = (char *) (p->wirehead);
-    p->wirevec[0].iov_len  = RX_HEADER_SIZE;
-    p->wirevec[1].iov_base = (char *) (p->localdata);
-    p->wirevec[1].iov_len  = RX_FIRSTBUFFERSIZE;
-    p->header.flags = RX_FREE_PACKET;
-    p->niovecs = 2;
-    
-    queue_Append(&rx_freePacketQueue, p);
-  }
-  rx_nFreePackets += apackets;
-  rxi_NeedMorePackets = FALSE;
-  rxi_PacketsUnWait();
+    struct rx_packet *p, *e;
+    int getme;
+
+    /* allocate enough packets that 1/4 of the packets will be able
+     * to hold maximal amounts of data */
+    apackets += (apackets / 4)
+       * ((rx_maxJumboRecvSize - RX_FIRSTBUFFERSIZE) / RX_CBUFFERSIZE);
+    getme = apackets * sizeof(struct rx_packet);
+    p = rx_mallocedP = (struct rx_packet *)osi_Alloc(getme);
+
+    memset((char *)p, 0, getme);
+
+    for (e = p + apackets; p < e; p++) {
+        RX_PACKET_IOV_INIT(p);
+       p->flags |= RX_PKTFLAG_FREE;
+       p->niovecs = 2;
+
+       queue_Append(&rx_freePacketQueue, p);
+    }
+
+    rx_nFreePackets += apackets;
+#ifdef RX_ENABLE_TSFPQ
+    /* TSFPQ patch also needs to keep track of total packets */
+    MUTEX_ENTER(&rx_stats_mutex);
+    rx_nPackets += apackets;
+    RX_TS_FPQ_COMPUTE_LIMITS;
+    MUTEX_EXIT(&rx_stats_mutex);
+#endif /* RX_ENABLE_TSFPQ */
+    rxi_NeedMorePackets = FALSE;
+    rxi_PacketsUnWait();
 }
 #endif /* !KERNEL */
 
-void rxi_FreeAllPackets(void)
+void
+rxi_FreeAllPackets(void)
 {
-  /* must be called at proper interrupt level, etcetera */
-  /* MTUXXX need to free all Packets */
-  osi_Free(rx_mallocedP, (rx_maxReceiveWindow+2) * sizeof(struct rx_packet));    
-  UNPIN(rx_mallocedP, (rx_maxReceiveWindow+2) * sizeof(struct rx_packet));    
+    /* must be called at proper interrupt level, etcetera */
+    /* MTUXXX need to free all Packets */
+    osi_Free(rx_mallocedP,
+            (rx_maxReceiveWindow + 2) * sizeof(struct rx_packet));
+    UNPIN(rx_mallocedP, (rx_maxReceiveWindow + 2) * sizeof(struct rx_packet));
 }
 
+#ifdef RX_ENABLE_TSFPQ
+void
+rxi_AdjustLocalPacketsTSFPQ(int num_keep_local, int allow_overcommit)
+{
+    register struct rx_ts_info_t * rx_ts_info;
+    register int xfer;
+    SPLVAR;
+
+    RX_TS_INFO_GET(rx_ts_info);
+
+    if (num_keep_local != rx_ts_info->_FPQ.len) {
+        NETPRI;
+       MUTEX_ENTER(&rx_freePktQ_lock);
+        if (num_keep_local < rx_ts_info->_FPQ.len) {
+            xfer = rx_ts_info->_FPQ.len - num_keep_local;
+           RX_TS_FPQ_LTOG2(rx_ts_info, xfer);
+           rxi_PacketsUnWait();
+        } else {
+            xfer = num_keep_local - rx_ts_info->_FPQ.len;
+            if ((num_keep_local > rx_TSFPQLocalMax) && !allow_overcommit)
+                xfer = rx_TSFPQLocalMax - rx_ts_info->_FPQ.len;
+            if (rx_nFreePackets < xfer) {
+                rxi_MorePacketsNoLock(xfer - rx_nFreePackets);
+            }
+            RX_TS_FPQ_GTOL2(rx_ts_info, xfer);
+        }
+       MUTEX_EXIT(&rx_freePktQ_lock);
+       USERPRI;
+    }
+}
+
+void
+rxi_FlushLocalPacketsTSFPQ(void)
+{
+    rxi_AdjustLocalPacketsTSFPQ(0, 0);
+}
+#endif /* RX_ENABLE_TSFPQ */
+
 /* Allocate more packets iff we need more continuation buffers */
 /* In kernel, can't page in memory with interrupts disabled, so we
  * don't use the event mechanism. */
-void rx_CheckPackets()
+void
+rx_CheckPackets(void)
 {
-  if (rxi_NeedMorePackets) {
-    rxi_MorePackets(rx_initSendWindow); 
-  }
+    if (rxi_NeedMorePackets) {
+       rxi_MorePackets(rx_initSendWindow);
+    }
 }
 
 /* In the packet freeing routine below, the assumption is that
@@ -439,39 +727,116 @@ void rx_CheckPackets()
    */
 
 /* Actually free the packet p. */
-void rxi_FreePacketNoLock(struct rx_packet *p)
+#ifdef RX_ENABLE_TSFPQ
+void
+rxi_FreePacketNoLock(struct rx_packet *p)
+{
+    register struct rx_ts_info_t * rx_ts_info;
+    dpf(("Free %lx\n", (unsigned long)p));
+
+    RX_TS_INFO_GET(rx_ts_info);
+    RX_TS_FPQ_CHECKIN(rx_ts_info,p);
+    if (rx_ts_info->_FPQ.len > rx_TSFPQLocalMax) {
+        RX_TS_FPQ_LTOG(rx_ts_info);
+    }
+}
+#else /* RX_ENABLE_TSFPQ */
+void
+rxi_FreePacketNoLock(struct rx_packet *p)
 {
-  dpf(("Free %x\n", p));
+    dpf(("Free %lx\n", (unsigned long)p));
+
+    RX_FPQ_MARK_FREE(p);
+    rx_nFreePackets++;
+    queue_Append(&rx_freePacketQueue, p);
+}
+#endif /* RX_ENABLE_TSFPQ */
+
+#ifdef RX_ENABLE_TSFPQ
+void
+rxi_FreePacketTSFPQ(struct rx_packet *p, int flush_global)
+{
+    register struct rx_ts_info_t * rx_ts_info;
+    dpf(("Free %lx\n", (unsigned long)p));
+
+    RX_TS_INFO_GET(rx_ts_info);
+    RX_TS_FPQ_CHECKIN(rx_ts_info,p);
+
+    if (flush_global && (rx_ts_info->_FPQ.len > rx_TSFPQLocalMax)) {
+        NETPRI;
+       MUTEX_ENTER(&rx_freePktQ_lock);
+
+       RX_TS_FPQ_LTOG(rx_ts_info);
+
+       /* Wakeup anyone waiting for packets */
+       rxi_PacketsUnWait();
+
+       MUTEX_EXIT(&rx_freePktQ_lock);
+       USERPRI;
+    }
+}
+#endif /* RX_ENABLE_TSFPQ */
+
+int
+rxi_FreeDataBufsNoLock(struct rx_packet *p, int first)
+{
+    struct iovec *iov, *end;
+
+    if (first != 1)            /* MTUXXX */
+       osi_Panic("FreeDataBufs 1: first must be 1");
+    iov = &p->wirevec[1];
+    end = iov + (p->niovecs - 1);
+    if (iov->iov_base != (caddr_t) p->localdata)       /* MTUXXX */
+       osi_Panic("FreeDataBufs 2: vec 1 must be localdata");
+    for (iov++; iov < end; iov++) {
+       if (!iov->iov_base)
+           osi_Panic("FreeDataBufs 3: vecs 2-niovecs must not be NULL");
+       rxi_FreePacketNoLock(RX_CBUF_TO_PACKET(iov->iov_base, p));
+    }
+    p->length = 0;
+    p->niovecs = 0;
 
-  if (p->header.flags & RX_FREE_PACKET)
-    osi_Panic("rxi_FreePacketNoLock: packet already free\n");
-  rx_nFreePackets++;
-  p->header.flags = RX_FREE_PACKET;
-  queue_Append(&rx_freePacketQueue, p);
+    return 0;
 }
 
-int rxi_FreeDataBufsNoLock(p, first)
-     struct rx_packet * p;
-     int first;
+#ifdef RX_ENABLE_TSFPQ
+int
+rxi_FreeDataBufsTSFPQ(struct rx_packet *p, int first, int flush_global)
 {
-  struct iovec *iov, *end;
-  
-  if (first != 1)          /* MTUXXX */
-      osi_Panic("FreeDataBufs 1: first must be 1");
-  iov = &p->wirevec[1];
-  end = iov + (p->niovecs-1);
-  if (iov->iov_base != (caddr_t) p->localdata) /* MTUXXX */
+    struct iovec *iov, *end;
+    register struct rx_ts_info_t * rx_ts_info;
+
+    RX_TS_INFO_GET(rx_ts_info);
+
+    if (first != 1)            /* MTUXXX */
+       osi_Panic("FreeDataBufs 1: first must be 1");
+    iov = &p->wirevec[1];
+    end = iov + (p->niovecs - 1);
+    if (iov->iov_base != (caddr_t) p->localdata)       /* MTUXXX */
        osi_Panic("FreeDataBufs 2: vec 1 must be localdata");
-  for (iov++ ; iov < end ; iov++) {
-    if (!iov->iov_base)
-       osi_Panic("FreeDataBufs 3: vecs 2-niovecs must not be NULL");
-    rxi_FreePacketNoLock(RX_CBUF_TO_PACKET(iov->iov_base, p));
-  }
-  p->length = 0;
-  p->niovecs = 0;
-
-  return 0; 
+    for (iov++; iov < end; iov++) {
+       if (!iov->iov_base)
+           osi_Panic("FreeDataBufs 3: vecs 2-niovecs must not be NULL");
+       RX_TS_FPQ_CHECKIN(rx_ts_info,RX_CBUF_TO_PACKET(iov->iov_base, p));
+    }
+    p->length = 0;
+    p->niovecs = 0;
+
+    if (flush_global && (rx_ts_info->_FPQ.len > rx_TSFPQLocalMax)) {
+        NETPRI;
+       MUTEX_ENTER(&rx_freePktQ_lock);
+
+       RX_TS_FPQ_LTOG(rx_ts_info);
+
+       /* Wakeup anyone waiting for packets */
+       rxi_PacketsUnWait();
+
+       MUTEX_EXIT(&rx_freePktQ_lock);
+       USERPRI;
+    }
+    return 0;
 }
+#endif /* RX_ENABLE_TSFPQ */
 
 int rxi_nBadIovecs = 0;
 
@@ -480,19 +845,17 @@ int rxi_nBadIovecs = 0;
  * Restore the correct sizes to the iovecs. Called when reusing a packet
  * for reading off the wire.
  */
-void rxi_RestoreDataBufs(struct rx_packet *p)
+void
+rxi_RestoreDataBufs(struct rx_packet *p)
 {
     int i;
     struct iovec *iov = &p->wirevec[2];
 
-    p->wirevec[0].iov_base = (char *) (p->wirehead);
-    p->wirevec[0].iov_len  = RX_HEADER_SIZE;
-    p->wirevec[1].iov_base = (char *) (p->localdata);
-    p->wirevec[1].iov_len  = RX_FIRSTBUFFERSIZE;
+    RX_PACKET_IOV_INIT(p);
 
-    for (i=2, iov = &p->wirevec[2]; i < p->niovecs; i++, iov++) {
+    for (i = 2, iov = &p->wirevec[2]; i < p->niovecs; i++, iov++) {
        if (!iov->iov_base) {
-           rxi_nBadIovecs ++;
+           rxi_nBadIovecs++;
            p->niovecs = i;
            break;
        }
@@ -500,83 +863,141 @@ void rxi_RestoreDataBufs(struct rx_packet *p)
     }
 }
 
-int rxi_TrimDataBufs(p, first)
-     struct rx_packet * p;
-     int first;
+#ifdef RX_ENABLE_TSFPQ
+int
+rxi_TrimDataBufs(struct rx_packet *p, int first)
 {
-  extern void rxi_PacketsUnWait();
-  int length;
-  struct iovec *iov, *end;
-  SPLVAR;
-  
-  if (first != 1)
-      osi_Panic("TrimDataBufs 1: first must be 1");
-
-  /* Skip over continuation buffers containing message data */
-  iov = &p->wirevec[2];
-  end = iov + (p->niovecs-2);
-  length = p->length - p->wirevec[1].iov_len;
-  for (; iov < end && length > 0 ; iov++) {
-    if (!iov->iov_base)
-       osi_Panic("TrimDataBufs 3: vecs 1-niovecs must not be NULL");
-    length -= iov->iov_len;
-  }
-
-  /* iov now points to the first empty data buffer. */
-  if (iov >= end)
+    int length;
+    struct iovec *iov, *end;
+    register struct rx_ts_info_t * rx_ts_info;
+    SPLVAR;
+
+    if (first != 1)
+       osi_Panic("TrimDataBufs 1: first must be 1");
+
+    /* Skip over continuation buffers containing message data */
+    iov = &p->wirevec[2];
+    end = iov + (p->niovecs - 2);
+    length = p->length - p->wirevec[1].iov_len;
+    for (; iov < end && length > 0; iov++) {
+       if (!iov->iov_base)
+           osi_Panic("TrimDataBufs 3: vecs 1-niovecs must not be NULL");
+       length -= iov->iov_len;
+    }
+
+    /* iov now points to the first empty data buffer. */
+    if (iov >= end)
+       return 0;
+
+    RX_TS_INFO_GET(rx_ts_info);
+    for (; iov < end; iov++) {
+       if (!iov->iov_base)
+           osi_Panic("TrimDataBufs 4: vecs 2-niovecs must not be NULL");
+       RX_TS_FPQ_CHECKIN(rx_ts_info,RX_CBUF_TO_PACKET(iov->iov_base, p));
+       p->niovecs--;
+    }
+    if (rx_ts_info->_FPQ.len > rx_TSFPQLocalMax) {
+        NETPRI;
+        MUTEX_ENTER(&rx_freePktQ_lock);
+
+       RX_TS_FPQ_LTOG(rx_ts_info);
+        rxi_PacketsUnWait();
+
+        MUTEX_EXIT(&rx_freePktQ_lock);
+       USERPRI;
+    }
+
     return 0;
-  
-  NETPRI;
-  MUTEX_ENTER(&rx_freePktQ_lock);
-
-  for (; iov < end ; iov++) {
-    if (!iov->iov_base)
-       osi_Panic("TrimDataBufs 4: vecs 2-niovecs must not be NULL");
-    rxi_FreePacketNoLock(RX_CBUF_TO_PACKET(iov->iov_base, p));
-    p->niovecs--;
-  }
-  rxi_PacketsUnWait();
-  
-  MUTEX_EXIT(&rx_freePktQ_lock);
-  USERPRI;
-
-  return 0; 
 }
+#else /* RX_ENABLE_TSFPQ */
+int
+rxi_TrimDataBufs(struct rx_packet *p, int first)
+{
+    int length;
+    struct iovec *iov, *end;
+    SPLVAR;
+
+    if (first != 1)
+       osi_Panic("TrimDataBufs 1: first must be 1");
+
+    /* Skip over continuation buffers containing message data */
+    iov = &p->wirevec[2];
+    end = iov + (p->niovecs - 2);
+    length = p->length - p->wirevec[1].iov_len;
+    for (; iov < end && length > 0; iov++) {
+       if (!iov->iov_base)
+           osi_Panic("TrimDataBufs 3: vecs 1-niovecs must not be NULL");
+       length -= iov->iov_len;
+    }
+
+    /* iov now points to the first empty data buffer. */
+    if (iov >= end)
+       return 0;
+
+    NETPRI;
+    MUTEX_ENTER(&rx_freePktQ_lock);
+
+    for (; iov < end; iov++) {
+       if (!iov->iov_base)
+           osi_Panic("TrimDataBufs 4: vecs 2-niovecs must not be NULL");
+       rxi_FreePacketNoLock(RX_CBUF_TO_PACKET(iov->iov_base, p));
+       p->niovecs--;
+    }
+    rxi_PacketsUnWait();
+
+    MUTEX_EXIT(&rx_freePktQ_lock);
+    USERPRI;
+
+    return 0;
+}
+#endif /* RX_ENABLE_TSFPQ */
 
 /* Free the packet p.  P is assumed not to be on any queue, i.e.
  * remove it yourself first if you call this routine. */
-void rxi_FreePacket(struct rx_packet *p)
+#ifdef RX_ENABLE_TSFPQ
+void
+rxi_FreePacket(struct rx_packet *p)
 {
-  extern void rxi_PacketsUnWait();
-  SPLVAR;
-  
-  NETPRI;
-  MUTEX_ENTER(&rx_freePktQ_lock);
-  
-  rxi_FreeDataBufsNoLock(p,1);
-  rxi_FreePacketNoLock(p);
-  /* Wakeup anyone waiting for packets */
-  rxi_PacketsUnWait();
-  
-  MUTEX_EXIT(&rx_freePktQ_lock);
-  USERPRI;
+    rxi_FreeDataBufsTSFPQ(p, 1, 0);
+    rxi_FreePacketTSFPQ(p, RX_TS_FPQ_FLUSH_GLOBAL);
 }
+#else /* RX_ENABLE_TSFPQ */
+void
+rxi_FreePacket(struct rx_packet *p)
+{
+    SPLVAR;
+
+    NETPRI;
+    MUTEX_ENTER(&rx_freePktQ_lock);
+
+    rxi_FreeDataBufsNoLock(p, 1);
+    rxi_FreePacketNoLock(p);
+    /* Wakeup anyone waiting for packets */
+    rxi_PacketsUnWait();
 
+    MUTEX_EXIT(&rx_freePktQ_lock);
+    USERPRI;
+}
+#endif /* RX_ENABLE_TSFPQ */
 
 /* rxi_AllocPacket sets up p->length so it reflects the number of 
  * bytes in the packet at this point, **not including** the header.
  * The header is absolutely necessary, besides, this is the way the
  * length field is usually used */
-struct rx_packet *rxi_AllocPacketNoLock(class)
-     int class;
+#ifdef RX_ENABLE_TSFPQ
+struct rx_packet *
+rxi_AllocPacketNoLock(int class)
 {
-  register struct rx_packet *p;
-  
+    register struct rx_packet *p;
+    register struct rx_ts_info_t * rx_ts_info;
+
+    RX_TS_INFO_GET(rx_ts_info);
+
 #ifdef KERNEL
-  if (rxi_OverQuota(class)) {
-    rxi_NeedMorePackets = TRUE;
-    MUTEX_ENTER(&rx_stats_mutex);
-    switch(class) {
+    if (rxi_OverQuota(class)) {
+       rxi_NeedMorePackets = TRUE;
+       MUTEX_ENTER(&rx_stats_mutex);
+       switch (class) {
        case RX_PACKET_CLASS_RECEIVE:
            rx_stats.receivePktAllocFailures++;
            break;
@@ -592,49 +1013,154 @@ struct rx_packet *rxi_AllocPacketNoLock(class)
        case RX_PACKET_CLASS_SEND_CBUF:
            rx_stats.sendCbufPktAllocFailures++;
            break;
+       }
+       MUTEX_EXIT(&rx_stats_mutex);
+       return (struct rx_packet *)0;
     }
+#endif /* KERNEL */
+
+    MUTEX_ENTER(&rx_stats_mutex);
+    rx_stats.packetRequests++;
     MUTEX_EXIT(&rx_stats_mutex);
-    return (struct rx_packet *) 0;
-  }
+
+    if (queue_IsEmpty(&rx_ts_info->_FPQ)) {
+
+#ifdef KERNEL
+        if (queue_IsEmpty(&rx_freePacketQueue))
+           osi_Panic("rxi_AllocPacket error");
+#else /* KERNEL */
+        if (queue_IsEmpty(&rx_freePacketQueue))
+           rxi_MorePacketsNoLock(rx_initSendWindow);
 #endif /* KERNEL */
 
-  MUTEX_ENTER(&rx_stats_mutex);
-  rx_stats.packetRequests++;
-  MUTEX_EXIT(&rx_stats_mutex);
-  
+
+       RX_TS_FPQ_GTOL(rx_ts_info);
+    }
+
+    RX_TS_FPQ_CHECKOUT(rx_ts_info,p);
+
+    dpf(("Alloc %lx, class %d\n", (unsigned long)p, class));
+
+
+    /* have to do this here because rx_FlushWrite fiddles with the iovs in
+     * order to truncate outbound packets.  In the near future, may need 
+     * to allocate bufs from a static pool here, and/or in AllocSendPacket
+     */
+    RX_PACKET_IOV_FULLINIT(p);
+    return p;
+}
+#else /* RX_ENABLE_TSFPQ */
+struct rx_packet *
+rxi_AllocPacketNoLock(int class)
+{
+    register struct rx_packet *p;
+
 #ifdef KERNEL
-  if (queue_IsEmpty(&rx_freePacketQueue)) 
-    osi_Panic("rxi_AllocPacket error");
+    if (rxi_OverQuota(class)) {
+       rxi_NeedMorePackets = TRUE;
+       MUTEX_ENTER(&rx_stats_mutex);
+       switch (class) {
+       case RX_PACKET_CLASS_RECEIVE:
+           rx_stats.receivePktAllocFailures++;
+           break;
+       case RX_PACKET_CLASS_SEND:
+           rx_stats.sendPktAllocFailures++;
+           break;
+       case RX_PACKET_CLASS_SPECIAL:
+           rx_stats.specialPktAllocFailures++;
+           break;
+       case RX_PACKET_CLASS_RECV_CBUF:
+           rx_stats.receiveCbufPktAllocFailures++;
+           break;
+       case RX_PACKET_CLASS_SEND_CBUF:
+           rx_stats.sendCbufPktAllocFailures++;
+           break;
+       }
+       MUTEX_EXIT(&rx_stats_mutex);
+       return (struct rx_packet *)0;
+    }
+#endif /* KERNEL */
+
+    MUTEX_ENTER(&rx_stats_mutex);
+    rx_stats.packetRequests++;
+    MUTEX_EXIT(&rx_stats_mutex);
+
+#ifdef KERNEL
+    if (queue_IsEmpty(&rx_freePacketQueue))
+       osi_Panic("rxi_AllocPacket error");
 #else /* KERNEL */
-  if (queue_IsEmpty(&rx_freePacketQueue)) 
-    rxi_MorePacketsNoLock(rx_initSendWindow);
+    if (queue_IsEmpty(&rx_freePacketQueue))
+       rxi_MorePacketsNoLock(rx_initSendWindow);
 #endif /* KERNEL */
-  
-  rx_nFreePackets--;
-  p = queue_First(&rx_freePacketQueue, rx_packet);
-  if (p->header.flags != RX_FREE_PACKET)
-    osi_Panic("rxi_AllocPacket: packet not free\n");
-  
-  dpf(("Alloc %x, class %d\n", p, class));
-  
-  queue_Remove(p);
-  p->header.flags = 0;
-  
-  /* have to do this here because rx_FlushWrite fiddles with the iovs in
-   * order to truncate outbound packets.  In the near future, may need 
-   * to allocate bufs from a static pool here, and/or in AllocSendPacket
-   */
-  p->wirevec[0].iov_base = (char *) (p->wirehead);
-  p->wirevec[0].iov_len  = RX_HEADER_SIZE;
-  p->wirevec[1].iov_base = (char *) (p->localdata);
-  p->wirevec[1].iov_len  = RX_FIRSTBUFFERSIZE;
-  p->niovecs = 2;
-  p->length = RX_FIRSTBUFFERSIZE;
-  return p;
+
+    rx_nFreePackets--;
+    p = queue_First(&rx_freePacketQueue, rx_packet);
+    queue_Remove(p);
+    RX_FPQ_MARK_USED(p);
+
+    dpf(("Alloc %lx, class %d\n", (unsigned long)p, class));
+
+
+    /* have to do this here because rx_FlushWrite fiddles with the iovs in
+     * order to truncate outbound packets.  In the near future, may need 
+     * to allocate bufs from a static pool here, and/or in AllocSendPacket
+     */
+    RX_PACKET_IOV_FULLINIT(p);
+    return p;
+}
+#endif /* RX_ENABLE_TSFPQ */
+
+#ifdef RX_ENABLE_TSFPQ
+struct rx_packet *
+rxi_AllocPacketTSFPQ(int class, int pull_global)
+{
+    register struct rx_packet *p;
+    register struct rx_ts_info_t * rx_ts_info;
+
+    RX_TS_INFO_GET(rx_ts_info);
+
+    MUTEX_ENTER(&rx_stats_mutex);
+    rx_stats.packetRequests++;
+    MUTEX_EXIT(&rx_stats_mutex);
+
+    if (pull_global && queue_IsEmpty(&rx_ts_info->_FPQ)) {
+        MUTEX_ENTER(&rx_freePktQ_lock);
+
+        if (queue_IsEmpty(&rx_freePacketQueue))
+            rxi_MorePacketsNoLock(rx_initSendWindow);
+
+       RX_TS_FPQ_GTOL(rx_ts_info);
+
+        MUTEX_EXIT(&rx_freePktQ_lock);
+    } else if (queue_IsEmpty(&rx_ts_info->_FPQ)) {
+        return NULL;
+    }
+
+    RX_TS_FPQ_CHECKOUT(rx_ts_info,p);
+
+    dpf(("Alloc %lx, class %d\n", (unsigned long)p, class));
+
+    /* have to do this here because rx_FlushWrite fiddles with the iovs in
+     * order to truncate outbound packets.  In the near future, may need 
+     * to allocate bufs from a static pool here, and/or in AllocSendPacket
+     */
+    RX_PACKET_IOV_FULLINIT(p);
+    return p;
 }
+#endif /* RX_ENABLE_TSFPQ */
+
+#ifdef RX_ENABLE_TSFPQ
+struct rx_packet *
+rxi_AllocPacket(int class)
+{
+    register struct rx_packet *p;
 
-struct rx_packet *rxi_AllocPacket(class)
-     int class;
+    p = rxi_AllocPacketTSFPQ(class, RX_TS_FPQ_PULL_GLOBAL);
+    return p;
+}
+#else /* RX_ENABLE_TSFPQ */
+struct rx_packet *
+rxi_AllocPacket(int class)
 {
     register struct rx_packet *p;
 
@@ -643,70 +1169,93 @@ struct rx_packet *rxi_AllocPacket(class)
     MUTEX_EXIT(&rx_freePktQ_lock);
     return p;
 }
+#endif /* RX_ENABLE_TSFPQ */
 
 /* This guy comes up with as many buffers as it {takes,can get} given
  * the MTU for this call. It also sets the packet length before
  * returning.  caution: this is often called at NETPRI
  * Called with call locked.
  */
-struct rx_packet *rxi_AllocSendPacket(call, want)
-register struct rx_call *call;
-int want;
+struct rx_packet *
+rxi_AllocSendPacket(register struct rx_call *call, int want)
 {
-    register struct rx_packet *p = (struct rx_packet *) 0;
+    register struct rx_packet *p = (struct rx_packet *)0;
     register int mud;
     register unsigned delta;
 
     SPLVAR;
     mud = call->MTU - RX_HEADER_SIZE;
-    delta = rx_GetSecurityHeaderSize(rx_ConnectionOf(call)) + 
+    delta =
+       rx_GetSecurityHeaderSize(rx_ConnectionOf(call)) +
        rx_GetSecurityMaxTrailerSize(rx_ConnectionOf(call));
 
-    while (!(call->error)) {
-      MUTEX_ENTER(&rx_freePktQ_lock);
-      /* if an error occurred, or we get the packet we want, we're done */
-      if (p = rxi_AllocPacketNoLock(RX_PACKET_CLASS_SEND)) {
-       MUTEX_EXIT(&rx_freePktQ_lock);
-
-       want += delta;
+#ifdef RX_ENABLE_TSFPQ
+    if ((p = rxi_AllocPacketTSFPQ(RX_PACKET_CLASS_SEND, 0))) {
+        want += delta;
        want = MIN(want, mud);
 
-       if ((unsigned) want > p->length) 
-         (void) rxi_AllocDataBuf(p, (want - p->length),
-                                 RX_PACKET_CLASS_SEND_CBUF);
+       if ((unsigned)want > p->length)
+           (void)rxi_AllocDataBuf(p, (want - p->length),
+                                  RX_PACKET_CLASS_SEND_CBUF);
 
-       if ((unsigned) p->length > mud)
-           p->length = mud;
+       if ((unsigned)p->length > mud)
+            p->length = mud;
 
        if (delta >= p->length) {
-         rxi_FreePacket(p);
-         p = NULL; 
+           rxi_FreePacket(p);
+           p = NULL;
        } else {
            p->length -= delta;
        }
-       break; 
-      }
-
-      /* no error occurred, and we didn't get a packet, so we sleep.
-       * At this point, we assume that packets will be returned
-       * sooner or later, as packets are acknowledged, and so we
-       * just wait.  */
-      NETPRI;
-      call->flags |= RX_CALL_WAIT_PACKETS;
-      CALL_HOLD(call, RX_CALL_REFCOUNT_PACKET);
-      MUTEX_EXIT(&call->lock);
-      rx_waitingForPackets = 1;
-      
+       return p;
+    }
+#endif /* RX_ENABLE_TSFPQ */
+
+    while (!(call->error)) {
+       MUTEX_ENTER(&rx_freePktQ_lock);
+       /* if an error occurred, or we get the packet we want, we're done */
+       if ((p = rxi_AllocPacketNoLock(RX_PACKET_CLASS_SEND))) {
+           MUTEX_EXIT(&rx_freePktQ_lock);
+
+           want += delta;
+           want = MIN(want, mud);
+
+           if ((unsigned)want > p->length)
+               (void)rxi_AllocDataBuf(p, (want - p->length),
+                                      RX_PACKET_CLASS_SEND_CBUF);
+
+           if ((unsigned)p->length > mud)
+               p->length = mud;
+
+           if (delta >= p->length) {
+               rxi_FreePacket(p);
+               p = NULL;
+           } else {
+               p->length -= delta;
+           }
+           break;
+       }
+
+       /* no error occurred, and we didn't get a packet, so we sleep.
+        * At this point, we assume that packets will be returned
+        * sooner or later, as packets are acknowledged, and so we
+        * just wait.  */
+       NETPRI;
+       call->flags |= RX_CALL_WAIT_PACKETS;
+       CALL_HOLD(call, RX_CALL_REFCOUNT_PACKET);
+       MUTEX_EXIT(&call->lock);
+       rx_waitingForPackets = 1;
+
 #ifdef RX_ENABLE_LOCKS
-      CV_WAIT(&rx_waitingForPackets_cv, &rx_freePktQ_lock);
+       CV_WAIT(&rx_waitingForPackets_cv, &rx_freePktQ_lock);
 #else
-      osi_rxSleep(&rx_waitingForPackets);
+       osi_rxSleep(&rx_waitingForPackets);
 #endif
-      MUTEX_EXIT(&rx_freePktQ_lock);
-      MUTEX_ENTER(&call->lock);
-      CALL_RELE(call, RX_CALL_REFCOUNT_PACKET);
-      call->flags &= ~RX_CALL_WAIT_PACKETS;
-      USERPRI;
+       MUTEX_EXIT(&rx_freePktQ_lock);
+       MUTEX_ENTER(&call->lock);
+       CALL_RELE(call, RX_CALL_REFCOUNT_PACKET);
+       call->flags &= ~RX_CALL_WAIT_PACKETS;
+       USERPRI;
     }
 
     return p;
@@ -715,16 +1264,18 @@ int want;
 #ifndef KERNEL
 
 /* count the number of used FDs */
-static int CountFDs(amax)
-register int amax; {
+static int
+CountFDs(register int amax)
+{
     struct stat tstat;
     register int i, code;
     register int count;
 
     count = 0;
-    for(i=0;i<amax;i++) {
+    for (i = 0; i < amax; i++) {
        code = fstat(i, &tstat);
-       if (code == 0) count++;
+       if (code == 0)
+           count++;
     }
     return count;
 }
@@ -742,11 +1293,9 @@ register int amax; {
  * (host,port) of the sender are stored in the supplied variables, and
  * the data length of the packet is stored in the packet structure.
  * The header is decoded. */
-int rxi_ReadPacket(socket, p, host, port)
-     int socket;
-     register struct rx_packet *p;
-     afs_uint32 *host;
-     u_short *port;
+int
+rxi_ReadPacket(int socket, register struct rx_packet *p, afs_uint32 * host,
+              u_short * port)
 {
     struct sockaddr_in from;
     int nbytes;
@@ -754,94 +1303,94 @@ int rxi_ReadPacket(socket, p, host, port)
     register afs_int32 tlen, savelen;
     struct msghdr msg;
     rx_computelen(p, tlen);
-    rx_SetDataSize(p, tlen);  /* this is the size of the user data area */
+    rx_SetDataSize(p, tlen);   /* this is the size of the user data area */
 
-    tlen += RX_HEADER_SIZE;   /* now this is the size of the entire packet */
-    rlen = rx_maxJumboRecvSize; /* this is what I am advertising.  Only check
-                                * it once in order to avoid races.  */
+    tlen += RX_HEADER_SIZE;    /* now this is the size of the entire packet */
+    rlen = rx_maxJumboRecvSize;        /* this is what I am advertising.  Only check
+                                * it once in order to avoid races.  */
     tlen = rlen - tlen;
     if (tlen > 0) {
-      tlen = rxi_AllocDataBuf(p, tlen, RX_PACKET_CLASS_SEND_CBUF);
-      if (tlen >0) {
-       tlen = rlen - tlen;
-      }
-      else tlen = rlen;
-    }
-    else tlen = rlen;
-
-   /* Extend the last iovec for padding, it's just to make sure that the 
-    * read doesn't return more data than we expect, and is done to get around
-    * our problems caused by the lack of a length field in the rx header.
-    * Use the extra buffer that follows the localdata in each packet
-    * structure. */
-    savelen = p->wirevec[p->niovecs].iov_len;
-    p->wirevec[p->niovecs].iov_len += RX_EXTRABUFFERSIZE;
-
-    bzero((char *)&msg, sizeof(msg));
-    msg.msg_name = (char *) &from;
+       tlen = rxi_AllocDataBuf(p, tlen, RX_PACKET_CLASS_SEND_CBUF);
+       if (tlen > 0) {
+           tlen = rlen - tlen;
+       } else
+           tlen = rlen;
+    } else
+       tlen = rlen;
+
+    /* Extend the last iovec for padding, it's just to make sure that the 
+     * read doesn't return more data than we expect, and is done to get around
+     * our problems caused by the lack of a length field in the rx header.
+     * Use the extra buffer that follows the localdata in each packet
+     * structure. */
+    savelen = p->wirevec[p->niovecs - 1].iov_len;
+    p->wirevec[p->niovecs - 1].iov_len += RX_EXTRABUFFERSIZE;
+
+    memset((char *)&msg, 0, sizeof(msg));
+    msg.msg_name = (char *)&from;
     msg.msg_namelen = sizeof(struct sockaddr_in);
     msg.msg_iov = p->wirevec;
     msg.msg_iovlen = p->niovecs;
     nbytes = rxi_Recvmsg(socket, &msg, 0);
 
-   /* restore the vec to its correct state */
-    p->wirevec[p->niovecs].iov_len = savelen;
+    /* restore the vec to its correct state */
+    p->wirevec[p->niovecs - 1].iov_len = savelen;
 
     p->length = (nbytes - RX_HEADER_SIZE);
-    if ((nbytes > tlen) || (p->length  & 0x8000)) {  /* Bogus packet */
-      if (nbytes > 0)
-       rxi_MorePackets(rx_initSendWindow);
-#ifndef AFS_NT40_ENV
-      else if (nbytes < 0 && errno == EWOULDBLOCK) {
-       MUTEX_ENTER(&rx_stats_mutex);
-       rx_stats.noPacketOnRead++;
-       MUTEX_EXIT(&rx_stats_mutex);
-      }
-#endif
-      else {
-       MUTEX_ENTER(&rx_stats_mutex);
-       rx_stats.bogusPacketOnRead++;
-       rx_stats.bogusHost = from.sin_addr.s_addr;
-       MUTEX_EXIT(&rx_stats_mutex);
-       dpf(("B: bogus packet from [%x,%d] nb=%d", from.sin_addr.s_addr,
-            from.sin_port,nbytes));
-      }
-      return  0;
-    }
-    else {
-      /* Extract packet header. */
-      rxi_DecodePacketHeader(p);
-      
-      *host = from.sin_addr.s_addr;
-      *port = from.sin_port;
-      if (p->header.type > 0 && p->header.type < RX_N_PACKET_TYPES) {
-       struct rx_peer *peer;
-       MUTEX_ENTER(&rx_stats_mutex);
-       rx_stats.packetsRead[p->header.type-1]++;
-       MUTEX_EXIT(&rx_stats_mutex);
-       /*
-        * Try to look up this peer structure.  If it doesn't exist,
-        * don't create a new one - 
-        * we don't keep count of the bytes sent/received if a peer
-        * structure doesn't already exist.
-        *
-        * The peer/connection cleanup code assumes that there is 1 peer
-        * per connection.  If we actually created a peer structure here
-        * and this packet was an rxdebug packet, the peer structure would
-        * never be cleaned up.
-        */
-       peer = rxi_FindPeer(*host, *port, 0, 0);
-       if (peer) {
-           MUTEX_ENTER(&peer->peer_lock);
-           hadd32(peer->bytesReceived, p->length);
-           MUTEX_EXIT(&peer->peer_lock);
+    if ((nbytes > tlen) || (p->length & 0x8000)) {     /* Bogus packet */
+       if (nbytes > 0)
+           rxi_MorePackets(rx_initSendWindow);
+       else if (nbytes < 0 && errno == EWOULDBLOCK) {
+           MUTEX_ENTER(&rx_stats_mutex);
+           rx_stats.noPacketOnRead++;
+           MUTEX_EXIT(&rx_stats_mutex);
+       } else {
+           MUTEX_ENTER(&rx_stats_mutex);
+           rx_stats.bogusPacketOnRead++;
+           rx_stats.bogusHost = from.sin_addr.s_addr;
+           MUTEX_EXIT(&rx_stats_mutex);
+           dpf(("B: bogus packet from [%x,%d] nb=%d", from.sin_addr.s_addr,
+                from.sin_port, nbytes));
+       }
+       return 0;
+    } else {
+       /* Extract packet header. */
+       rxi_DecodePacketHeader(p);
+
+       *host = from.sin_addr.s_addr;
+       *port = from.sin_port;
+       if (p->header.type > 0 && p->header.type < RX_N_PACKET_TYPES) {
+           struct rx_peer *peer;
+           MUTEX_ENTER(&rx_stats_mutex);
+           rx_stats.packetsRead[p->header.type - 1]++;
+           MUTEX_EXIT(&rx_stats_mutex);
+           /*
+            * Try to look up this peer structure.  If it doesn't exist,
+            * don't create a new one - 
+            * we don't keep count of the bytes sent/received if a peer
+            * structure doesn't already exist.
+            *
+            * The peer/connection cleanup code assumes that there is 1 peer
+            * per connection.  If we actually created a peer structure here
+            * and this packet was an rxdebug packet, the peer structure would
+            * never be cleaned up.
+            */
+           peer = rxi_FindPeer(*host, *port, 0, 0);
+           /* Since this may not be associated with a connection,
+            * it may have no refCount, meaning we could race with
+            * ReapConnections
+            */
+           if (peer && (peer->refCount > 0)) {
+               MUTEX_ENTER(&peer->peer_lock);
+               hadd32(peer->bytesReceived, p->length);
+               MUTEX_EXIT(&peer->peer_lock);
+           }
        }
-      }
 
-      /* Free any empty packet buffers at the end of this packet */
-      rxi_TrimDataBufs(p, 1);
-      
-      return  1;
+       /* Free any empty packet buffers at the end of this packet */
+       rxi_TrimDataBufs(p, 1);
+
+       return 1;
     }
 }
 
@@ -855,11 +1404,9 @@ int rxi_ReadPacket(socket, p, host, port)
  * HACK: We store the length of the first n-1 packets in the
  * last two pad bytes. */
 
-struct rx_packet *rxi_SplitJumboPacket(p, host, port, first)
-     register struct rx_packet *p;
-     afs_int32 host;
-     short port;
-     int first;
+struct rx_packet *
+rxi_SplitJumboPacket(register struct rx_packet *p, afs_int32 host, short port,
+                    int first)
 {
     struct rx_packet *np;
     struct rx_jumboHeader *jp;
@@ -888,15 +1435,15 @@ struct rx_packet *rxi_SplitJumboPacket(p, host, port, first)
 
     /* Get a pointer to the abbreviated packet header */
     jp = (struct rx_jumboHeader *)
-        ((char *)(p->wirevec[1].iov_base) + RX_JUMBOBUFFERSIZE);
+       ((char *)(p->wirevec[1].iov_base) + RX_JUMBOBUFFERSIZE);
 
     /* Set up the iovecs for the next packet */
     np->wirevec[0].iov_base = (char *)(&np->wirehead[0]);
     np->wirevec[0].iov_len = sizeof(struct rx_header);
     np->wirevec[1].iov_base = (char *)(&np->localdata[0]);
     np->wirevec[1].iov_len = length - RX_JUMBOHEADERSIZE;
-    np->niovecs = niov+1;
-    for (i = 2 , iov++ ; i <= niov ; i++ , iov++) {
+    np->niovecs = niov + 1;
+    for (i = 2, iov++; i <= niov; i++, iov++) {
        np->wirevec[i] = *iov;
     }
     np->length = p->length - length;
@@ -904,9 +1451,9 @@ struct rx_packet *rxi_SplitJumboPacket(p, host, port, first)
     p->niovecs = 2;
 
     /* Convert the jumbo packet header to host byte order */
-    temp = ntohl(*(afs_uint32 *)jp);
-    jp->flags = (u_char)(temp >> 24);
-    jp->cksum = (u_short)(temp);
+    temp = ntohl(*(afs_uint32 *) jp);
+    jp->flags = (u_char) (temp >> 24);
+    jp->cksum = (u_short) (temp);
 
     /* Fill in the packet header */
     np->header = p->header;
@@ -914,21 +1461,18 @@ struct rx_packet *rxi_SplitJumboPacket(p, host, port, first)
     np->header.seq = p->header.seq + 1;
     np->header.flags = jp->flags;
     np->header.spare = jp->cksum;
-      
+
     return np;
 }
 
 #ifndef KERNEL
 /* Send a udp datagram */
-int osi_NetSend(socket, addr, dvec, nvecs, length, istack)
-    osi_socket socket;
-    char * addr;
-    struct iovec *dvec;
-    int nvecs;
-    int length;
-    int istack;
+int
+osi_NetSend(osi_socket socket, void *addr, struct iovec *dvec, int nvecs,
+           int length, int istack)
 {
     struct msghdr msg;
+       int ret;
 
     memset(&msg, 0, sizeof(msg));
     msg.msg_iov = dvec;
@@ -936,16 +1480,16 @@ int osi_NetSend(socket, addr, dvec, nvecs, length, istack)
     msg.msg_name = addr;
     msg.msg_namelen = sizeof(struct sockaddr_in);
 
-    rxi_Sendmsg(socket, &msg, 0);
+    ret = rxi_Sendmsg(socket, &msg, 0);
 
-    return 0;
+    return ret;
 }
 #elif !defined(UKERNEL)
-/* osi_NetSend is defined in afs/afs_osinet.c
+/*
  * message receipt is done in rxk_input or rx_put.
  */
 
-#ifdef AFS_SUN5_ENV
+#if defined(AFS_SUN5_ENV) || defined(AFS_HPUX110_ENV)
 /*
  * Copy an mblock to the contiguous area pointed to by cp.
  * MTUXXX Supposed to skip <off> bytes and copy <len> bytes,
@@ -953,19 +1497,17 @@ int osi_NetSend(socket, addr, dvec, nvecs, length, istack)
  * Returns the number of bytes not transferred.
  * The message is NOT changed.
  */
-static int cpytoc(mp, off, len, cp)
-    mblk_t *mp;
-    register int off, len;
-    register char * cp;
+static int
+cpytoc(mblk_t * mp, register int off, register int len, register char *cp)
 {
     register int n;
 
-    for (;mp && len > 0; mp = mp->b_cont) {
+    for (; mp && len > 0; mp = mp->b_cont) {
        if (mp->b_datap->db_type != M_DATA) {
            return -1;
        }
        n = MIN(len, (mp->b_wptr - mp->b_rptr));
-       bcopy((char *)mp->b_rptr, cp, n);
+       memcpy(cp, (char *)mp->b_rptr, n);
        cp += n;
        len -= n;
        mp->b_rptr += n;
@@ -977,12 +1519,11 @@ static int cpytoc(mp, off, len, cp)
  * but it doesn't really.  
  * This sucks, anyway, do it like m_cpy.... below 
  */
-static int cpytoiovec(mp, off, len, iovs, niovs)
-    mblk_t *mp;
-    int off, len, niovs;
-    register struct iovec *iovs;
+static int
+cpytoiovec(mblk_t * mp, int off, int len, register struct iovec *iovs,
+          int niovs)
 {
-    register int m,n,o,t,i;
+    register int m, n, o, t, i;
 
     for (i = -1, t = 0; i < niovs && mp && len > 0; mp = mp->b_cont) {
        if (mp->b_datap->db_type != M_DATA) {
@@ -991,115 +1532,127 @@ static int cpytoiovec(mp, off, len, iovs, niovs)
        n = MIN(len, (mp->b_wptr - mp->b_rptr));
        len -= n;
        while (n) {
-         if (!t) {
-           o=0;
-           i++;
-           t = iovs[i].iov_len;
-         }
-         m = MIN(n,t);
-         bcopy((char *)mp->b_rptr, iovs[i].iov_base + o, m);
-         mp->b_rptr += m;
-         o += m;
-         t -= m;
-         n -= m;
+           if (!t) {
+               o = 0;
+               i++;
+               t = iovs[i].iov_len;
+           }
+           m = MIN(n, t);
+           memcpy(iovs[i].iov_base + o, (char *)mp->b_rptr, m);
+           mp->b_rptr += m;
+           o += m;
+           t -= m;
+           n -= m;
        }
     }
     return (len);
 }
+
 #define m_cpytoc(a, b, c, d)  cpytoc(a, b, c, d)
 #define m_cpytoiovec(a, b, c, d, e) cpytoiovec(a, b, c, d, e)
 #else
-#if !defined(AFS_LINUX20_ENV)
-static int m_cpytoiovec(m, off, len, iovs, niovs)
-     struct mbuf *m;
-     int off, len, niovs;
-     struct iovec iovs[];
+#if !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN80_ENV)
+static int
+m_cpytoiovec(struct mbuf *m, int off, int len, struct iovec iovs[], int niovs)
 {
-  caddr_t p1, p2;
-  unsigned int l1, l2, i, t;
-  
-  if (m == NULL || off < 0 || len < 0 || iovs == NULL)
-    osi_Panic("m_cpytoiovec");  /* MTUXXX probably don't need this check */
-  
-  while (off && m)
-    if (m->m_len <= off) {
-      off -= m->m_len;
-      m = m->m_next;
-      continue;
-    } else
-      break;
-  
-  if (m == NULL)
-    return len;
-  
-  p1 = mtod(m, caddr_t)+off;
-  l1 = m->m_len - off;
-  i = 0;
-  p2 = iovs[0].iov_base;
-  l2 = iovs[0].iov_len;
-  
-  while (len) {
-    t = MIN(l1, MIN(l2, (unsigned int)len));
-    bcopy (p1, p2, t);
-    p1 += t;    p2 += t;
-    l1 -= t;    l2 -= t;
-    len -= t;
-    if (!l1) {
-      m = m->m_next; 
-      if (!m)
-       break;
-      p1 = mtod(m, caddr_t);
-      l1 = m->m_len;
-    }
-    if (!l2) {
-      if (++i >= niovs)
-       break;
-      p2 = iovs[i].iov_base;
-      l2 = iovs[i].iov_len;
+    caddr_t p1, p2;
+    unsigned int l1, l2, i, t;
+
+    if (m == NULL || off < 0 || len < 0 || iovs == NULL)
+       osi_Panic("m_cpytoiovec");      /* MTUXXX probably don't need this check */
+
+    while (off && m)
+       if (m->m_len <= off) {
+           off -= m->m_len;
+           m = m->m_next;
+           continue;
+       } else
+           break;
+
+    if (m == NULL)
+       return len;
+
+    p1 = mtod(m, caddr_t) + off;
+    l1 = m->m_len - off;
+    i = 0;
+    p2 = iovs[0].iov_base;
+    l2 = iovs[0].iov_len;
+
+    while (len) {
+       t = MIN(l1, MIN(l2, (unsigned int)len));
+       memcpy(p2, p1, t);
+       p1 += t;
+       p2 += t;
+       l1 -= t;
+       l2 -= t;
+       len -= t;
+       if (!l1) {
+           m = m->m_next;
+           if (!m)
+               break;
+           p1 = mtod(m, caddr_t);
+           l1 = m->m_len;
+       }
+       if (!l2) {
+           if (++i >= niovs)
+               break;
+           p2 = iovs[i].iov_base;
+           l2 = iovs[i].iov_len;
+       }
+
     }
-    
-  }
 
-return len;  
+    return len;
 }
 #endif /* LINUX */
 #endif /* AFS_SUN5_ENV */
 
-#if !defined(AFS_LINUX20_ENV)
-int rx_mb_to_packet(amb, free, hdr_len, data_len, phandle)
-#ifdef AFS_SUN5_ENV
-mblk_t *amb;
+#if !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN80_ENV)
+int
+rx_mb_to_packet(amb, free, hdr_len, data_len, phandle)
+#if defined(AFS_SUN5_ENV) || defined(AFS_HPUX110_ENV)
+     mblk_t *amb;
 #else
-struct mbuf *amb;
+     struct mbuf *amb;
 #endif
-void (*free)();
-struct rx_packet *phandle;
-int hdr_len, data_len;
+     void (*free) ();
+     struct rx_packet *phandle;
+     int hdr_len, data_len;
 {
-  register int code;
+    register int code;
 
-  code = m_cpytoiovec(amb, hdr_len, data_len, phandle->wirevec, phandle->niovecs); 
-  (*free)(amb);
+    code =
+       m_cpytoiovec(amb, hdr_len, data_len, phandle->wirevec,
+                    phandle->niovecs);
+    (*free) (amb);
 
-  return code;
+    return code;
 }
 #endif /* LINUX */
-#endif /*KERNEL && !UKERNEL*/
+#endif /*KERNEL && !UKERNEL */
 
 
 /* send a response to a debug packet */
 
-struct rx_packet *rxi_ReceiveDebugPacket(ap, asocket, ahost, aport, istack)
-  osi_socket asocket;
-  afs_int32 ahost;
-  short aport;
-  register struct rx_packet *ap;
-  int istack;
+struct rx_packet *
+rxi_ReceiveDebugPacket(register struct rx_packet *ap, osi_socket asocket,
+                      afs_int32 ahost, short aport, int istack)
 {
     struct rx_debugIn tin;
     afs_int32 tl;
     struct rx_serverQueueEntry *np, *nqe;
 
+    /*
+     * Only respond to client-initiated Rx debug packets,
+     * and clear the client flag in the response.
+     */
+    if (ap->header.flags & RX_CLIENT_INITIATED) {
+       ap->header.flags = ap->header.flags & ~RX_CLIENT_INITIATED;
+       rxi_EncodePacketHeader(ap);
+    } else {
+       return ap;
+    }
+
     rx_packetread(ap, 0, sizeof(struct rx_debugIn), (char *)&tin);
     /* all done with packet, now set length to the truth, so we can 
      * reuse this packet */
@@ -1107,39 +1660,43 @@ struct rx_packet *rxi_ReceiveDebugPacket(ap, asocket, ahost, aport, istack)
 
     tin.type = ntohl(tin.type);
     tin.index = ntohl(tin.index);
-    switch(tin.type) {
-       case RX_DEBUGI_GETSTATS: {
+    switch (tin.type) {
+    case RX_DEBUGI_GETSTATS:{
            struct rx_debugStats tstat;
 
            /* get basic stats */
-           bzero ((char *)&tstat, sizeof(tstat)); /* make sure spares are zero */
+           memset((char *)&tstat, 0, sizeof(tstat));   /* make sure spares are zero */
            tstat.version = RX_DEBUGI_VERSION;
 #ifndef        RX_ENABLE_LOCKS
            tstat.waitingForPackets = rx_waitingForPackets;
 #endif
+           MUTEX_ENTER(&rx_serverPool_lock);
            tstat.nFreePackets = htonl(rx_nFreePackets);
            tstat.callsExecuted = htonl(rxi_nCalls);
            tstat.packetReclaims = htonl(rx_packetReclaims);
            tstat.usedFDs = CountFDs(64);
            tstat.nWaiting = htonl(rx_nWaiting);
-           queue_Count( &rx_idleServerQueue, np, nqe, 
-                               rx_serverQueueEntry, tstat.idleThreads); 
+           tstat.nWaited = htonl(rx_nWaited);
+           queue_Count(&rx_idleServerQueue, np, nqe, rx_serverQueueEntry,
+                       tstat.idleThreads);
+           MUTEX_EXIT(&rx_serverPool_lock);
            tstat.idleThreads = htonl(tstat.idleThreads);
            tl = sizeof(struct rx_debugStats) - ap->length;
            if (tl > 0)
-             tl = rxi_AllocDataBuf(ap, tl, RX_PACKET_CLASS_SEND_CBUF);
+               tl = rxi_AllocDataBuf(ap, tl, RX_PACKET_CLASS_SEND_CBUF);
 
            if (tl <= 0) {
-             rx_packetwrite(ap, 0, sizeof(struct rx_debugStats), (char *)&tstat);
-             ap->length = sizeof(struct rx_debugStats);
-             rxi_SendDebugPacket(ap, asocket, ahost, aport, istack);
-             rx_computelen(ap, ap->length);
+               rx_packetwrite(ap, 0, sizeof(struct rx_debugStats),
+                              (char *)&tstat);
+               ap->length = sizeof(struct rx_debugStats);
+               rxi_SendDebugPacket(ap, asocket, ahost, aport, istack);
+               rx_computelen(ap, ap->length);
            }
            break;
        }
 
-       case RX_DEBUGI_GETALLCONN:
-       case RX_DEBUGI_GETCONN: {
+    case RX_DEBUGI_GETALLCONN:
+    case RX_DEBUGI_GETCONN:{
            int i, j;
            register struct rx_connection *tc;
            struct rx_call *tcall;
@@ -1149,13 +1706,13 @@ struct rx_packet *rxi_ReceiveDebugPacket(ap, asocket, ahost, aport, istack)
 
            tl = sizeof(struct rx_debugConn) - ap->length;
            if (tl > 0)
-             tl = rxi_AllocDataBuf(ap, tl, RX_PACKET_CLASS_SEND_CBUF);
+               tl = rxi_AllocDataBuf(ap, tl, RX_PACKET_CLASS_SEND_CBUF);
            if (tl > 0)
-             return ap;
+               return ap;
 
-           bzero ((char *)&tconn, sizeof(tconn)); /* make sure spares are zero */
+           memset((char *)&tconn, 0, sizeof(tconn));   /* make sure spares are zero */
            /* get N'th (maybe) "interesting" connection info */
-           for(i=0;i<rx_hashTableSize;i++) {
+           for (i = 0; i < rx_hashTableSize; i++) {
 #if !defined(KERNEL)
                /* the time complexity of the algorithm used here
                 * exponentially increses with the number of connections.
@@ -1163,23 +1720,24 @@ struct rx_packet *rxi_ReceiveDebugPacket(ap, asocket, ahost, aport, istack)
 #ifdef AFS_PTHREAD_ENV
                pthread_yield();
 #else
-               (void) IOMGR_Poll();
+               (void)IOMGR_Poll();
 #endif
 #endif
                MUTEX_ENTER(&rx_connHashTable_lock);
                /* We might be slightly out of step since we are not 
                 * locking each call, but this is only debugging output.
                 */
-               for(tc=rx_connHashTable[i]; tc; tc=tc->next) {
-                   if ((all || rxi_IsConnInteresting(tc)) && tin.index-- <= 0) {
+               for (tc = rx_connHashTable[i]; tc; tc = tc->next) {
+                   if ((all || rxi_IsConnInteresting(tc))
+                       && tin.index-- <= 0) {
                        tconn.host = tc->peer->host;
                        tconn.port = tc->peer->port;
                        tconn.cid = htonl(tc->cid);
                        tconn.epoch = htonl(tc->epoch);
                        tconn.serial = htonl(tc->serial);
-                       for(j=0;j<RX_MAXCALLS;j++) {
+                       for (j = 0; j < RX_MAXCALLS; j++) {
                            tconn.callNumber[j] = htonl(tc->callNumber[j]);
-                           if (tcall=tc->call[j]) {
+                           if ((tcall = tc->call[j])) {
                                tconn.callState[j] = tcall->state;
                                tconn.callMode[j] = tcall->mode;
                                tconn.callFlags[j] = tcall->flags;
@@ -1187,8 +1745,8 @@ struct rx_packet *rxi_ReceiveDebugPacket(ap, asocket, ahost, aport, istack)
                                    tconn.callOther[j] |= RX_OTHER_IN;
                                if (queue_IsNotEmpty(&tcall->tq))
                                    tconn.callOther[j] |= RX_OTHER_OUT;
-                           }
-                           else tconn.callState[j] = RX_STATE_NOTINIT;
+                           } else
+                               tconn.callState[j] = RX_STATE_NOTINIT;
                        }
 
                        tconn.natMTU = htonl(tc->peer->natMTU);
@@ -1197,8 +1755,8 @@ struct rx_packet *rxi_ReceiveDebugPacket(ap, asocket, ahost, aport, istack)
                        tconn.type = tc->type;
                        tconn.securityIndex = tc->securityIndex;
                        if (tc->securityObject) {
-                           RXS_GetStats (tc->securityObject, tc,
-                                         &tconn.secStats);
+                           RXS_GetStats(tc->securityObject, tc,
+                                        &tconn.secStats);
 #define DOHTONL(a) (tconn.secStats.a = htonl(tconn.secStats.a))
 #define DOHTONS(a) (tconn.secStats.a = htons(tconn.secStats.a))
                            DOHTONL(flags);
@@ -1207,21 +1765,25 @@ struct rx_packet *rxi_ReceiveDebugPacket(ap, asocket, ahost, aport, istack)
                            DOHTONL(packetsSent);
                            DOHTONL(bytesReceived);
                            DOHTONL(bytesSent);
-                           for (i=0;
-                                i<sizeof(tconn.secStats.spares)/sizeof(short);
-                                i++)
+                           for (i = 0;
+                                i <
+                                sizeof(tconn.secStats.spares) /
+                                sizeof(short); i++)
                                DOHTONS(spares[i]);
-                           for (i=0;
-                                i<sizeof(tconn.secStats.sparel)/sizeof(afs_int32);
-                                i++)
+                           for (i = 0;
+                                i <
+                                sizeof(tconn.secStats.sparel) /
+                                sizeof(afs_int32); i++)
                                DOHTONL(sparel[i]);
                        }
 
                        MUTEX_EXIT(&rx_connHashTable_lock);
-                       rx_packetwrite(ap, 0, sizeof(struct rx_debugConn), (char*)&tconn);
+                       rx_packetwrite(ap, 0, sizeof(struct rx_debugConn),
+                                      (char *)&tconn);
                        tl = ap->length;
                        ap->length = sizeof(struct rx_debugConn);
-                       rxi_SendDebugPacket(ap, asocket, ahost, aport, istack);
+                       rxi_SendDebugPacket(ap, asocket, ahost, aport,
+                                           istack);
                        ap->length = tl;
                        return ap;
                    }
@@ -1229,8 +1791,9 @@ struct rx_packet *rxi_ReceiveDebugPacket(ap, asocket, ahost, aport, istack)
                MUTEX_EXIT(&rx_connHashTable_lock);
            }
            /* if we make it here, there are no interesting packets */
-           tconn.cid = htonl(0xffffffff); /* means end */
-           rx_packetwrite(ap, 0, sizeof(struct rx_debugConn), (char *)&tconn);
+           tconn.cid = htonl(0xffffffff);      /* means end */
+           rx_packetwrite(ap, 0, sizeof(struct rx_debugConn),
+                          (char *)&tconn);
            tl = ap->length;
            ap->length = sizeof(struct rx_debugConn);
            rxi_SendDebugPacket(ap, asocket, ahost, aport, istack);
@@ -1242,20 +1805,20 @@ struct rx_packet *rxi_ReceiveDebugPacket(ap, asocket, ahost, aport, istack)
         * Pass back all the peer structures we have available
         */
 
-       case RX_DEBUGI_GETPEER: {
-           int i, j;
+    case RX_DEBUGI_GETPEER:{
+           int i;
            register struct rx_peer *tp;
            struct rx_debugPeer tpeer;
 
 
            tl = sizeof(struct rx_debugPeer) - ap->length;
            if (tl > 0)
-             tl = rxi_AllocDataBuf(ap, tl, RX_PACKET_CLASS_SEND_CBUF);
+               tl = rxi_AllocDataBuf(ap, tl, RX_PACKET_CLASS_SEND_CBUF);
            if (tl > 0)
-             return ap;
+               return ap;
 
-           bzero ((char *)&tpeer, sizeof(tpeer));
-           for(i=0;i<rx_hashTableSize;i++) {
+           memset((char *)&tpeer, 0, sizeof(tpeer));
+           for (i = 0; i < rx_hashTableSize; i++) {
 #if !defined(KERNEL)
                /* the time complexity of the algorithm used here
                 * exponentially increses with the number of peers.
@@ -1269,11 +1832,11 @@ struct rx_packet *rxi_ReceiveDebugPacket(ap, asocket, ahost, aport, istack)
 #ifdef AFS_PTHREAD_ENV
                pthread_yield();
 #else
-               (void) IOMGR_Poll();
+               (void)IOMGR_Poll();
 #endif
 #endif
                MUTEX_ENTER(&rx_peerHashTable_lock);
-               for(tp=rx_peerHashTable[i]; tp; tp=tp->next) {
+               for (tp = rx_peerHashTable[i]; tp; tp = tp->next) {
                    if (tin.index-- <= 0) {
                        tpeer.host = tp->host;
                        tpeer.port = tp->port;
@@ -1303,14 +1866,18 @@ struct rx_packet *rxi_ReceiveDebugPacket(ap, asocket, ahost, aport, istack)
                        tpeer.congestSeq = htons(tp->congestSeq);
                        tpeer.bytesSent.high = htonl(tp->bytesSent.high);
                        tpeer.bytesSent.low = htonl(tp->bytesSent.low);
-                       tpeer.bytesReceived.high = htonl(tp->bytesReceived.high);
-                       tpeer.bytesReceived.low = htonl(tp->bytesReceived.low);
+                       tpeer.bytesReceived.high =
+                           htonl(tp->bytesReceived.high);
+                       tpeer.bytesReceived.low =
+                           htonl(tp->bytesReceived.low);
 
                        MUTEX_EXIT(&rx_peerHashTable_lock);
-                       rx_packetwrite(ap, 0, sizeof(struct rx_debugPeer), (char*)&tpeer);
+                       rx_packetwrite(ap, 0, sizeof(struct rx_debugPeer),
+                                      (char *)&tpeer);
                        tl = ap->length;
                        ap->length = sizeof(struct rx_debugPeer);
-                       rxi_SendDebugPacket(ap, asocket, ahost, aport, istack);
+                       rxi_SendDebugPacket(ap, asocket, ahost, aport,
+                                           istack);
                        ap->length = tl;
                        return ap;
                    }
@@ -1318,8 +1885,9 @@ struct rx_packet *rxi_ReceiveDebugPacket(ap, asocket, ahost, aport, istack)
                MUTEX_EXIT(&rx_peerHashTable_lock);
            }
            /* if we make it here, there are no interesting packets */
-           tpeer.host = htonl(0xffffffff); /* means end */
-           rx_packetwrite(ap, 0, sizeof(struct rx_debugPeer), (char *)&tpeer);
+           tpeer.host = htonl(0xffffffff);     /* means end */
+           rx_packetwrite(ap, 0, sizeof(struct rx_debugPeer),
+                          (char *)&tpeer);
            tl = ap->length;
            ap->length = sizeof(struct rx_debugPeer);
            rxi_SendDebugPacket(ap, asocket, ahost, aport, istack);
@@ -1327,21 +1895,21 @@ struct rx_packet *rxi_ReceiveDebugPacket(ap, asocket, ahost, aport, istack)
            break;
        }
 
-       case RX_DEBUGI_RXSTATS: {
+    case RX_DEBUGI_RXSTATS:{
            int i;
            afs_int32 *s;
 
            tl = sizeof(rx_stats) - ap->length;
            if (tl > 0)
-             tl = rxi_AllocDataBuf(ap, tl, RX_PACKET_CLASS_SEND_CBUF);
+               tl = rxi_AllocDataBuf(ap, tl, RX_PACKET_CLASS_SEND_CBUF);
            if (tl > 0)
-             return ap;
+               return ap;
 
            /* Since its all int32s convert to network order with a loop. */
            MUTEX_ENTER(&rx_stats_mutex);
-           s = (afs_int32 *)&rx_stats;
-           for (i=0; i<sizeof(rx_stats)/sizeof(afs_int32); i++,s++)
-               rx_PutInt32(ap, i*sizeof(afs_int32), htonl(*s));
+           s = (afs_int32 *) & rx_stats;
+           for (i = 0; i < sizeof(rx_stats) / sizeof(afs_int32); i++, s++)
+               rx_PutInt32(ap, i * sizeof(afs_int32), htonl(*s));
 
            tl = ap->length;
            ap->length = sizeof(rx_stats);
@@ -1351,46 +1919,58 @@ struct rx_packet *rxi_ReceiveDebugPacket(ap, asocket, ahost, aport, istack)
            break;
        }
 
-       default:
-           /* error response packet */
-           tin.type = htonl(RX_DEBUGI_BADTYPE);
-           tin.index = tin.type;
-           rx_packetwrite(ap, 0, sizeof(struct rx_debugIn), (char *)&tin);
-           tl = ap->length;
-           ap->length = sizeof(struct rx_debugIn);
-           rxi_SendDebugPacket(ap, asocket, ahost, aport, istack);
-           ap->length = tl;
-           break;
+    default:
+       /* error response packet */
+       tin.type = htonl(RX_DEBUGI_BADTYPE);
+       tin.index = tin.type;
+       rx_packetwrite(ap, 0, sizeof(struct rx_debugIn), (char *)&tin);
+       tl = ap->length;
+       ap->length = sizeof(struct rx_debugIn);
+       rxi_SendDebugPacket(ap, asocket, ahost, aport, istack);
+       ap->length = tl;
+       break;
     }
     return ap;
 }
 
-struct rx_packet *rxi_ReceiveVersionPacket(ap, asocket, ahost, aport, istack)
-  osi_socket asocket;
-  afs_int32 ahost;
-  short aport;
-  register struct rx_packet *ap;
-  int istack;
+struct rx_packet *
+rxi_ReceiveVersionPacket(register struct rx_packet *ap, osi_socket asocket,
+                        afs_int32 ahost, short aport, int istack)
 {
-  afs_int32 tl;
-       rx_packetwrite(ap, 0, 65, cml_version_number+4);
-        tl = ap->length;
+    afs_int32 tl;
+
+    /*
+     * Only respond to client-initiated version requests, and
+     * clear that flag in the response.
+     */
+    if (ap->header.flags & RX_CLIENT_INITIATED) {
+       char buf[66];
+
+       ap->header.flags = ap->header.flags & ~RX_CLIENT_INITIATED;
+       rxi_EncodePacketHeader(ap);
+       memset(buf, 0, sizeof(buf));
+       strncpy(buf, cml_version_number + 4, sizeof(buf) - 1);
+       rx_packetwrite(ap, 0, 65, buf);
+       tl = ap->length;
        ap->length = 65;
        rxi_SendDebugPacket(ap, asocket, ahost, aport, istack);
-        ap->length = tl;
-       return ap;
+       ap->length = tl;
+    }
+
+    return ap;
 }
 
 
 /* send a debug packet back to the sender */
-static void rxi_SendDebugPacket(struct rx_packet *apacket, osi_socket asocket,
-                              afs_int32 ahost, short aport, afs_int32 istack)
+static void
+rxi_SendDebugPacket(struct rx_packet *apacket, osi_socket asocket,
+                   afs_int32 ahost, short aport, afs_int32 istack)
 {
     struct sockaddr_in taddr;
     int i;
     int nbytes;
     int saven = 0;
-    size_t savelen;
+    size_t savelen = 0;
 #ifdef KERNEL
     int waslocked = ISAFS_GLOCK();
 #endif
@@ -1398,44 +1978,70 @@ static void rxi_SendDebugPacket(struct rx_packet *apacket, osi_socket asocket,
     taddr.sin_family = AF_INET;
     taddr.sin_port = aport;
     taddr.sin_addr.s_addr = ahost;
-
+#ifdef STRUCT_SOCKADDR_HAS_SA_LEN
+    taddr.sin_len = sizeof(struct sockaddr_in);
+#endif
 
     /* We need to trim the niovecs. */
     nbytes = apacket->length;
-    for (i=1; i < apacket->niovecs; i++) {
-      if (nbytes <= apacket->wirevec[i].iov_len) {
-       savelen = apacket->wirevec[i].iov_len;
-       saven = apacket->niovecs;
-       apacket->wirevec[i].iov_len = nbytes;
-       apacket->niovecs = i+1;   /* so condition fails because i == niovecs */
-      }
-      else nbytes -= apacket->wirevec[i].iov_len;
-    }
-    AFS_RXGUNLOCK();
+    for (i = 1; i < apacket->niovecs; i++) {
+       if (nbytes <= apacket->wirevec[i].iov_len) {
+           savelen = apacket->wirevec[i].iov_len;
+           saven = apacket->niovecs;
+           apacket->wirevec[i].iov_len = nbytes;
+           apacket->niovecs = i + 1;   /* so condition fails because i == niovecs */
+       } else
+           nbytes -= apacket->wirevec[i].iov_len;
+    }
 #ifdef KERNEL
-    if (waslocked) AFS_GUNLOCK();
+#ifdef RX_KERNEL_TRACE
+    if (ICL_SETACTIVE(afs_iclSetp)) {
+       if (!waslocked)
+           AFS_GLOCK();
+       afs_Trace1(afs_iclSetp, CM_TRACE_TIMESTAMP, ICL_TYPE_STRING,
+                  "before osi_NetSend()");
+       AFS_GUNLOCK();
+    } else
+#else
+    if (waslocked)
+       AFS_GUNLOCK();
+#endif
 #endif
     /* debug packets are not reliably delivered, hence the cast below. */
-    (void) osi_NetSend(asocket, &taddr, apacket->wirevec, apacket->niovecs,
-                      apacket->length+RX_HEADER_SIZE, istack);
+    (void)osi_NetSend(asocket, &taddr, apacket->wirevec, apacket->niovecs,
+                     apacket->length + RX_HEADER_SIZE, istack);
 #ifdef KERNEL
-    if (waslocked) AFS_GLOCK();
+#ifdef RX_KERNEL_TRACE
+    if (ICL_SETACTIVE(afs_iclSetp)) {
+       AFS_GLOCK();
+       afs_Trace1(afs_iclSetp, CM_TRACE_TIMESTAMP, ICL_TYPE_STRING,
+                  "after osi_NetSend()");
+       if (!waslocked)
+           AFS_GUNLOCK();
+    } else
+#else
+    if (waslocked)
+       AFS_GLOCK();
 #endif
-    AFS_RXGLOCK();
-    if (saven) {  /* means we truncated the packet above. */
-      apacket->wirevec[i-1].iov_len = savelen;
-      apacket->niovecs = saven;
+#endif
+    if (saven) {               /* means we truncated the packet above. */
+       apacket->wirevec[i - 1].iov_len = savelen;
+       apacket->niovecs = saven;
     }
 
 }
 
 /* Send the packet to appropriate destination for the specified
- * connection.  The header is first encoded and placed in the packet.
+ * call.  The header is first encoded and placed in the packet.
  */
-void rxi_SendPacket(struct rx_connection * conn, struct rx_packet *p,
-                   int istack)
+void
+rxi_SendPacket(struct rx_call *call, struct rx_connection *conn,
+              struct rx_packet *p, int istack)
 {
+#if defined(KERNEL)
     int waslocked;
+#endif
+    int code;
     struct sockaddr_in addr;
     register struct rx_peer *peer = conn->peer;
     osi_socket socket;
@@ -1443,6 +2049,7 @@ void rxi_SendPacket(struct rx_connection * conn, struct rx_packet *p,
     char deliveryType = 'S';
 #endif
     /* The address we're sending the packet to */
+    memset(&addr, 0, sizeof(addr));
     addr.sin_family = AF_INET;
     addr.sin_port = peer->port;
     addr.sin_addr.s_addr = peer->host;
@@ -1459,22 +2066,22 @@ void rxi_SendPacket(struct rx_connection * conn, struct rx_packet *p,
     /* Pre-increment, to guarantee no zero serial number; a zero
      * serial number means the packet was never sent. */
     MUTEX_ENTER(&conn->conn_data_lock);
-    p->header.serial = ++conn->serial; 
+    p->header.serial = ++conn->serial;
     MUTEX_EXIT(&conn->conn_data_lock);
     /* This is so we can adjust retransmit time-outs better in the face of 
      * rapidly changing round-trip times.  RTO estimation is not a la Karn.
      */
     if (p->firstSerial == 0) {
-       p->firstSerial = p->header.serial;
-     }
-
+       p->firstSerial = p->header.serial;
+    }
 #ifdef RXDEBUG
     /* If an output tracer function is defined, call it with the packet and
      * network address.  Note this function may modify its arguments. */
     if (rx_almostSent) {
        int drop = (*rx_almostSent) (p, &addr);
        /* drop packet if return value is non-zero? */
-       if (drop) deliveryType = 'D';   /* Drop the packet */
+       if (drop)
+           deliveryType = 'D'; /* Drop the packet */
     }
 #endif
 
@@ -1484,52 +2091,89 @@ void rxi_SendPacket(struct rx_connection * conn, struct rx_packet *p,
 
     /* Send the packet out on the same socket that related packets are being
      * received on */
-    socket = (conn->type == RX_CLIENT_CONNECTION
-             ? rx_socket : conn->service->socket);
+    socket =
+       (conn->type ==
+        RX_CLIENT_CONNECTION ? rx_socket : conn->service->socket);
 
 #ifdef RXDEBUG
     /* Possibly drop this packet,  for testing purposes */
-    if ((deliveryType == 'D') ||
-       ((rx_intentionallyDroppedPacketsPer100 > 0) &&
-        (random() % 100 < rx_intentionallyDroppedPacketsPer100))) {
-       deliveryType = 'D';             /* Drop the packet */
-    }
-    else {
-       deliveryType = 'S';             /* Send the packet */
+    if ((deliveryType == 'D')
+       || ((rx_intentionallyDroppedPacketsPer100 > 0)
+           && (random() % 100 < rx_intentionallyDroppedPacketsPer100))) {
+       deliveryType = 'D';     /* Drop the packet */
+    } else {
+       deliveryType = 'S';     /* Send the packet */
 #endif /* RXDEBUG */
 
        /* Loop until the packet is sent.  We'd prefer just to use a
-         * blocking socket, but unfortunately the interface doesn't
-         * allow us to have the socket block in send mode, and not
-         * block in receive mode */
-       AFS_RXGUNLOCK();
+        * blocking socket, but unfortunately the interface doesn't
+        * allow us to have the socket block in send mode, and not
+        * block in receive mode */
 #ifdef KERNEL
        waslocked = ISAFS_GLOCK();
-       if (waslocked) AFS_GUNLOCK();
+#ifdef RX_KERNEL_TRACE
+       if (ICL_SETACTIVE(afs_iclSetp)) {
+           if (!waslocked)
+               AFS_GLOCK();
+           afs_Trace1(afs_iclSetp, CM_TRACE_TIMESTAMP, ICL_TYPE_STRING,
+                      "before osi_NetSend()");
+           AFS_GUNLOCK();
+       } else
+#else
+       if (waslocked)
+           AFS_GUNLOCK();
+#endif
+#endif
+       if ((code =
+            osi_NetSend(socket, &addr, p->wirevec, p->niovecs,
+                        p->length + RX_HEADER_SIZE, istack)) != 0) {
+           /* send failed, so let's hurry up the resend, eh? */
+           MUTEX_ENTER(&rx_stats_mutex);
+           rx_stats.netSendFailures++;
+           MUTEX_EXIT(&rx_stats_mutex);
+           p->retryTime = p->timeSent; /* resend it very soon */
+           clock_Addmsec(&(p->retryTime),
+                         10 + (((afs_uint32) p->backoff) << 8));
+
+#ifdef AFS_NT40_ENV
+           /* Windows is nice -- it can tell us right away that we cannot
+            * reach this recipient by returning an WSAEHOSTUNREACH error
+            * code.  So, when this happens let's "down" the host NOW so
+            * we don't sit around waiting for this host to timeout later.
+            */
+               if (call && code == -1 && errno == WSAEHOSTUNREACH)
+                       call->lastReceiveTime = 0;
+#endif
+#if defined(KERNEL) && defined(AFS_LINUX20_ENV)
+           /* Linux is nice -- it can tell us right away that we cannot
+            * reach this recipient by returning an ENETUNREACH error
+            * code.  So, when this happens let's "down" the host NOW so
+            * we don't sit around waiting for this host to timeout later.
+            */
+           if (call && code == -ENETUNREACH)
+               call->lastReceiveTime = 0;
 #endif
-       if (osi_NetSend(socket, &addr, p->wirevec, p->niovecs, 
-                       p->length+RX_HEADER_SIZE, istack)){
-         /* send failed, so let's hurry up the resend, eh? */
-         MUTEX_ENTER(&rx_stats_mutex);
-         rx_stats.netSendFailures++;      
-         MUTEX_EXIT(&rx_stats_mutex);
-         p->retryTime = p->timeSent;  /* resend it very soon */
-         clock_Addmsec(&(p->retryTime), 10 + (((afs_uint32) p->backoff) << 8));
        }
 #ifdef KERNEL
-       if (waslocked) AFS_GLOCK();
+#ifdef RX_KERNEL_TRACE
+       if (ICL_SETACTIVE(afs_iclSetp)) {
+           AFS_GLOCK();
+           afs_Trace1(afs_iclSetp, CM_TRACE_TIMESTAMP, ICL_TYPE_STRING,
+                      "after osi_NetSend()");
+           if (!waslocked)
+               AFS_GUNLOCK();
+       } else
+#else
+       if (waslocked)
+           AFS_GLOCK();
 #endif
-       AFS_RXGLOCK();
-#ifdef RXDEBUG    
-    }
-    dpf(("%c %d %s: %x.%u.%u.%u.%u.%u.%u flags %d, packet %x resend %d.%0.3d len %d",
-        deliveryType, p->header.serial, rx_packetTypes[p->header.type-1],
-        peer->host, peer->port, p->header.serial, p->header.epoch,
-        p->header.cid, p->header.callNumber, p->header.seq, p->header.flags,
-        p, p->retryTime.sec, p->retryTime.usec/1000, p->length));
+#endif
+#ifdef RXDEBUG
+    }
+    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], peer->host, 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));
 #endif
     MUTEX_ENTER(&rx_stats_mutex);
-    rx_stats.packetsSent[p->header.type-1]++;
+    rx_stats.packetsSent[p->header.type - 1]++;
     MUTEX_EXIT(&rx_stats_mutex);
     MUTEX_ENTER(&peer->peer_lock);
     hadd32(peer->bytesSent, p->length);
@@ -1539,18 +2183,19 @@ void rxi_SendPacket(struct rx_connection * conn, struct rx_packet *p,
 /* Send a list of packets to appropriate destination for the specified
  * connection.  The headers are first encoded and placed in the packets.
  */
-void rxi_SendPacketList(struct rx_connection * conn,
-                       struct rx_packet **list,
-                       int len,
-                       int istack)
+void
+rxi_SendPacketList(struct rx_call *call, struct rx_connection *conn,
+                  struct rx_packet **list, int len, int istack)
 {
+#if     defined(AFS_SUN5_ENV) && defined(KERNEL)
     int waslocked;
+#endif
     struct sockaddr_in addr;
     register struct rx_peer *peer = conn->peer;
     osi_socket socket;
-    struct rx_packet *p;
+    struct rx_packet *p = NULL;
     struct iovec wirevec[RX_MAXIOVECS];
-    int i, length;
+    int i, length, code;
     afs_uint32 serial;
     afs_uint32 temp;
     struct rx_jumboHeader *jp;
@@ -1562,7 +2207,7 @@ void rxi_SendPacketList(struct rx_connection * conn,
     addr.sin_port = peer->port;
     addr.sin_addr.s_addr = peer->host;
 
-    if (len+1 > RX_MAXIOVECS) {
+    if (len + 1 > RX_MAXIOVECS) {
        osi_Panic("rxi_SendPacketList, len > RX_MAXIOVECS\n");
     }
 
@@ -1570,7 +2215,7 @@ void rxi_SendPacketList(struct rx_connection * conn,
      * Stamp the packets in this jumbogram with consecutive serial numbers
      */
     MUTEX_ENTER(&conn->conn_data_lock);
-    serial = conn->serial; 
+    serial = conn->serial;
     conn->serial += len;
     MUTEX_EXIT(&conn->conn_data_lock);
 
@@ -1583,120 +2228,133 @@ void rxi_SendPacketList(struct rx_connection * conn,
     length = RX_HEADER_SIZE;
     wirevec[0].iov_base = (char *)(&list[0]->wirehead[0]);
     wirevec[0].iov_len = RX_HEADER_SIZE;
-    for (i = 0 ; i < len ; i++) {
-        p = list[i];
+    for (i = 0; i < len; i++) {
+       p = list[i];
 
        /* The whole 3.5 jumbogram scheme relies on packets fitting
-         * in a single packet buffer. */
+        * in a single packet buffer. */
        if (p->niovecs > 2) {
            osi_Panic("rxi_SendPacketList, niovecs > 2\n");
        }
 
        /* Set the RX_JUMBO_PACKET flags in all but the last packets
         * in this chunk.  */
-       if (i < len-1) {
+       if (i < len - 1) {
            if (p->length != RX_JUMBOBUFFERSIZE) {
                osi_Panic("rxi_SendPacketList, length != jumbo size\n");
            }
            p->header.flags |= RX_JUMBO_PACKET;
            length += RX_JUMBOBUFFERSIZE + RX_JUMBOHEADERSIZE;
-           wirevec[i+1].iov_len = RX_JUMBOBUFFERSIZE + RX_JUMBOHEADERSIZE;
+           wirevec[i + 1].iov_len = RX_JUMBOBUFFERSIZE + RX_JUMBOHEADERSIZE;
        } else {
-           wirevec[i+1].iov_len = p->length;
+           wirevec[i + 1].iov_len = p->length;
            length += p->length;
        }
-       wirevec[i+1].iov_base = (char *)(&p->localdata[0]);
+       wirevec[i + 1].iov_base = (char *)(&p->localdata[0]);
        if (jp != NULL) {
            /* Convert jumbo packet header to network byte order */
-           temp = (afs_uint32)(p->header.flags) << 24;
-           temp |= (afs_uint32)(p->header.spare);
-           *(afs_uint32 *)jp = htonl(temp);
+           temp = (afs_uint32) (p->header.flags) << 24;
+           temp |= (afs_uint32) (p->header.spare);
+           *(afs_uint32 *) jp = htonl(temp);
        }
        jp = (struct rx_jumboHeader *)
-            ((char *)(&p->localdata[0]) + RX_JUMBOBUFFERSIZE);
-
-        /* Stamp each packet with a unique serial number.  The serial
-         * number is maintained on a connection basis because some types
-         * of security may be based on the serial number of the packet,
-         * and security is handled on a per authenticated-connection
-         * basis. */
-        /* Pre-increment, to guarantee no zero serial number; a zero
-         * serial number means the packet was never sent. */
-        p->header.serial = ++serial; 
-        /* This is so we can adjust retransmit time-outs better in the face of 
-         * rapidly changing round-trip times.  RTO estimation is not a la Karn.
-         */
-        if (p->firstSerial == 0) {
-           p->firstSerial = p->header.serial;
-        }
-
+           ((char *)(&p->localdata[0]) + RX_JUMBOBUFFERSIZE);
+
+       /* Stamp each packet with a unique serial number.  The serial
+        * number is maintained on a connection basis because some types
+        * of security may be based on the serial number of the packet,
+        * and security is handled on a per authenticated-connection
+        * basis. */
+       /* Pre-increment, to guarantee no zero serial number; a zero
+        * serial number means the packet was never sent. */
+       p->header.serial = ++serial;
+       /* This is so we can adjust retransmit time-outs better in the face of 
+        * rapidly changing round-trip times.  RTO estimation is not a la Karn.
+        */
+       if (p->firstSerial == 0) {
+           p->firstSerial = p->header.serial;
+       }
 #ifdef RXDEBUG
-        /* If an output tracer function is defined, call it with the packet and
-         * network address.  Note this function may modify its arguments. */
-        if (rx_almostSent) {
+       /* If an output tracer function is defined, call it with the packet and
+        * network address.  Note this function may modify its arguments. */
+       if (rx_almostSent) {
            int drop = (*rx_almostSent) (p, &addr);
            /* drop packet if return value is non-zero? */
-           if (drop) deliveryType = 'D';       /* Drop the packet */
-        }
+           if (drop)
+               deliveryType = 'D';     /* Drop the packet */
+       }
 #endif
 
-        /* Get network byte order header */
-        rxi_EncodePacketHeader(p);     /* XXX in the event of rexmit, etc, don't need to 
-                                    * touch ALL the fields */
+       /* Get network byte order header */
+       rxi_EncodePacketHeader(p);      /* XXX in the event of rexmit, etc, don't need to 
+                                        * touch ALL the fields */
     }
 
     /* Send the packet out on the same socket that related packets are being
      * received on */
-    socket = (conn->type == RX_CLIENT_CONNECTION
-             ? rx_socket : conn->service->socket);
+    socket =
+       (conn->type ==
+        RX_CLIENT_CONNECTION ? rx_socket : conn->service->socket);
 
 #ifdef RXDEBUG
     /* Possibly drop this packet,  for testing purposes */
-    if ((deliveryType == 'D') ||
-       ((rx_intentionallyDroppedPacketsPer100 > 0) &&
-        (random() % 100 < rx_intentionallyDroppedPacketsPer100))) {
-       deliveryType = 'D';             /* Drop the packet */
-    }
-    else {
-       deliveryType = 'S';             /* Send the packet */
+    if ((deliveryType == 'D')
+       || ((rx_intentionallyDroppedPacketsPer100 > 0)
+           && (random() % 100 < rx_intentionallyDroppedPacketsPer100))) {
+       deliveryType = 'D';     /* Drop the packet */
+    } else {
+       deliveryType = 'S';     /* Send the packet */
 #endif /* RXDEBUG */
 
        /* Loop until the packet is sent.  We'd prefer just to use a
-         * blocking socket, but unfortunately the interface doesn't
-         * allow us to have the socket block in send mode, and not
-         * block in receive mode */
-       AFS_RXGUNLOCK();
+        * blocking socket, but unfortunately the interface doesn't
+        * allow us to have the socket block in send mode, and not
+        * block in receive mode */
 #if    defined(AFS_SUN5_ENV) && defined(KERNEL)
        waslocked = ISAFS_GLOCK();
-       if (!istack && waslocked) AFS_GUNLOCK();
+       if (!istack && waslocked)
+           AFS_GUNLOCK();
+#endif
+       if ((code =
+            osi_NetSend(socket, &addr, &wirevec[0], len + 1, length,
+                        istack)) != 0) {
+           /* send failed, so let's hurry up the resend, eh? */
+           MUTEX_ENTER(&rx_stats_mutex);
+           rx_stats.netSendFailures++;
+           MUTEX_EXIT(&rx_stats_mutex);
+           for (i = 0; i < len; i++) {
+               p = list[i];
+               p->retryTime = p->timeSent;     /* resend it very soon */
+               clock_Addmsec(&(p->retryTime),
+                             10 + (((afs_uint32) p->backoff) << 8));
+           }
+#if defined(KERNEL) && defined(AFS_LINUX20_ENV)
+           /* Linux is nice -- it can tell us right away that we cannot
+            * reach this recipient by returning an ENETUNREACH error
+            * code.  So, when this happens let's "down" the host NOW so
+            * we don't sit around waiting for this host to timeout later.
+            */
+           if (call && code == -ENETUNREACH)
+               call->lastReceiveTime = 0;
 #endif
-       if (osi_NetSend(socket, &addr, &wirevec[0], len+1, length, istack)){
-         /* send failed, so let's hurry up the resend, eh? */
-         MUTEX_ENTER(&rx_stats_mutex);
-         rx_stats.netSendFailures++;      
-         MUTEX_EXIT(&rx_stats_mutex);
-         for (i = 0 ; i < len ; i++) {
-           p = list[i];
-           p->retryTime = p->timeSent;  /* resend it very soon */
-           clock_Addmsec(&(p->retryTime), 10 + (((afs_uint32) p->backoff) << 8));
-         }
        }
 #if    defined(AFS_SUN5_ENV) && defined(KERNEL)
-       if (!istack && waslocked) AFS_GLOCK();
+       if (!istack && waslocked)
+           AFS_GLOCK();
 #endif
-       AFS_RXGLOCK();
-#ifdef RXDEBUG    
-    }
-    dpf(("%c %d %s: %x.%u.%u.%u.%u.%u.%u flags %d, packet %x resend %d.%0.3d len %d",
-        deliveryType, p->header.serial, rx_packetTypes[p->header.type-1],
-        peer->host, peer->port, p->header.serial, p->header.epoch,
-        p->header.cid, p->header.callNumber, p->header.seq, p->header.flags,
-        p, p->retryTime.sec, p->retryTime.usec/1000, p->length));
+#ifdef RXDEBUG
+    }
+
+    assert(p != NULL);
+
+    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], peer->host, 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));
+
 #endif
     MUTEX_ENTER(&rx_stats_mutex);
-    rx_stats.packetsSent[p->header.type-1]++;
+    rx_stats.packetsSent[p->header.type - 1]++;
     MUTEX_EXIT(&rx_stats_mutex);
     MUTEX_ENTER(&peer->peer_lock);
+
     hadd32(peer->bytesSent, p->length);
     MUTEX_EXIT(&peer->peer_lock);
 }
@@ -1712,19 +2370,16 @@ void rxi_SendPacketList(struct rx_connection * conn,
  * in rx.h.  Bug: there's a lot of duplication between this and other
  * routines.  This needs to be cleaned up. */
 struct rx_packet *
-rxi_SendSpecial(call, conn, optionalPacket, type, data, nbytes, istack)
-    register struct rx_call *call;
-    register struct rx_connection *conn;
-    struct rx_packet *optionalPacket;
-    int type;
-    char *data;
-    int nbytes, istack;
+rxi_SendSpecial(register struct rx_call *call,
+               register struct rx_connection *conn,
+               struct rx_packet *optionalPacket, int type, char *data,
+               int nbytes, int istack)
 {
     /* Some of the following stuff should be common code for all
      * packet sends (it's repeated elsewhere) */
     register struct rx_packet *p;
     unsigned int i = 0;
-    int savelen, saven = 0;
+    int savelen = 0, saven = 0;
     int channel, callNumber;
     if (call) {
        channel = call->channel;
@@ -1740,13 +2395,14 @@ rxi_SendSpecial(call, conn, optionalPacket, type, data, nbytes, istack)
     p = optionalPacket;
     if (!p) {
        p = rxi_AllocPacket(RX_PACKET_CLASS_SPECIAL);
-       if (!p) osi_Panic("rxi_SendSpecial failure");
+       if (!p)
+           osi_Panic("rxi_SendSpecial failure");
     }
 
-    if (nbytes != -1) 
-      p->length = nbytes;
+    if (nbytes != -1)
+       p->length = nbytes;
     else
-      nbytes = p->length;
+       nbytes = p->length;
     p->header.serviceId = conn->serviceId;
     p->header.securityIndex = conn->securityIndex;
     p->header.cid = (conn->cid | channel);
@@ -1755,30 +2411,33 @@ rxi_SendSpecial(call, conn, optionalPacket, type, data, nbytes, istack)
     p->header.epoch = conn->epoch;
     p->header.type = type;
     p->header.flags = 0;
-    if (conn->type == RX_CLIENT_CONNECTION) 
-       p->header.flags |= RX_CLIENT_INITIATED;
-    if (data) 
-      rx_packetwrite(p, 0, nbytes, data);
-
-    for (i=1; i < p->niovecs; i++) {
-      if (nbytes <= p->wirevec[i].iov_len) {
-       savelen = p->wirevec[i].iov_len;
-       saven = p->niovecs;
-       p->wirevec[i].iov_len = nbytes;
-       p->niovecs = i+1;   /* so condition fails because i == niovecs */
-      }
-      else nbytes -= p->wirevec[i].iov_len;
-    }
-
-    if (call) rxi_Send(call, p, istack);
-    else rxi_SendPacket(conn, p, istack);
-    if (saven) {  /* means we truncated the packet above.  We probably don't  */
-      /* really need to do this, but it seems safer this way, given that  */
-      /* sneaky optionalPacket... */
-      p->wirevec[i-1].iov_len = savelen;
-      p->niovecs = saven;
-    }
-    if (!optionalPacket) rxi_FreePacket(p);
+    if (conn->type == RX_CLIENT_CONNECTION)
+       p->header.flags |= RX_CLIENT_INITIATED;
+    if (data)
+       rx_packetwrite(p, 0, nbytes, data);
+
+    for (i = 1; i < p->niovecs; i++) {
+       if (nbytes <= p->wirevec[i].iov_len) {
+           savelen = p->wirevec[i].iov_len;
+           saven = p->niovecs;
+           p->wirevec[i].iov_len = nbytes;
+           p->niovecs = i + 1; /* so condition fails because i == niovecs */
+       } else
+           nbytes -= p->wirevec[i].iov_len;
+    }
+
+    if (call)
+       rxi_Send(call, p, istack);
+    else
+       rxi_SendPacket((struct rx_call *)0, conn, p, istack);
+    if (saven) {               /* means we truncated the packet above.  We probably don't  */
+       /* really need to do this, but it seems safer this way, given that  */
+       /* sneaky optionalPacket... */
+       p->wirevec[i - 1].iov_len = savelen;
+       p->niovecs = saven;
+    }
+    if (!optionalPacket)
+       rxi_FreePacket(p);
     return optionalPacket;
 }
 
@@ -1786,95 +2445,117 @@ rxi_SendSpecial(call, conn, optionalPacket, type, data, nbytes, istack)
 /* Encode the packet's header (from the struct header in the packet to
  * the net byte order representation in the wire representation of the
  * packet, which is what is actually sent out on the wire) */
-void rxi_EncodePacketHeader(p)
-register struct rx_packet *p;
+void
+rxi_EncodePacketHeader(register struct rx_packet *p)
 {
-    register afs_uint32 *buf = (afs_uint32 *)(p->wirevec[0].iov_base);      /* MTUXXX */
+    register afs_uint32 *buf = (afs_uint32 *) (p->wirevec[0].iov_base);        /* MTUXXX */
 
-    bzero((char *)buf, RX_HEADER_SIZE);
+    memset((char *)buf, 0, RX_HEADER_SIZE);
     *buf++ = htonl(p->header.epoch);
     *buf++ = htonl(p->header.cid);
     *buf++ = htonl(p->header.callNumber);
     *buf++ = htonl(p->header.seq);
     *buf++ = htonl(p->header.serial);
-    *buf++ = htonl(  (((afs_uint32)p->header.type)<<24) 
-                  | (((afs_uint32)p->header.flags)<<16) 
-                  | (p->header.userStatus<<8) | p->header.securityIndex);
+    *buf++ = htonl((((afs_uint32) p->header.type) << 24)
+                  | (((afs_uint32) p->header.flags) << 16)
+                  | (p->header.userStatus << 8) | p->header.securityIndex);
     /* Note: top 16 bits of this next word were reserved */
-    *buf++ = htonl((p->header.spare << 16) | (p->header.serviceId&0xffff));
+    *buf++ = htonl((p->header.spare << 16) | (p->header.serviceId & 0xffff));
 }
 
 /* Decode the packet's header (from net byte order to a struct header) */
-void rxi_DecodePacketHeader(p)
-register struct rx_packet *p;
+void
+rxi_DecodePacketHeader(register struct rx_packet *p)
 {
-    register afs_uint32 *buf = (afs_uint32*)(p->wirevec[0].iov_base);      /* MTUXXX */
+    register afs_uint32 *buf = (afs_uint32 *) (p->wirevec[0].iov_base);        /* MTUXXX */
     afs_uint32 temp;
 
-    p->header.epoch = ntohl(*buf++);
-    p->header.cid = ntohl(*buf++);
-    p->header.callNumber = ntohl(*buf++);
-    p->header.seq = ntohl(*buf++);
-    p->header.serial = ntohl(*buf++);
-    temp = ntohl(*buf++);
+    p->header.epoch = ntohl(*buf);
+    buf++;
+    p->header.cid = ntohl(*buf);
+    buf++;
+    p->header.callNumber = ntohl(*buf);
+    buf++;
+    p->header.seq = ntohl(*buf);
+    buf++;
+    p->header.serial = ntohl(*buf);
+    buf++;
+
+    temp = ntohl(*buf);
+    buf++;
+
     /* C will truncate byte fields to bytes for me */
-    p->header.type = temp>>24;
-    p->header.flags = temp>>16;
-    p->header.userStatus = temp>>8;
-    p->header.securityIndex = temp>>0;
-    temp = ntohl(*buf++);
-    p->header.serviceId = (temp&0xffff);
-    p->header.spare = temp>>16;
+    p->header.type = temp >> 24;
+    p->header.flags = temp >> 16;
+    p->header.userStatus = temp >> 8;
+    p->header.securityIndex = temp >> 0;
+
+    temp = ntohl(*buf);
+    buf++;
+
+    p->header.serviceId = (temp & 0xffff);
+    p->header.spare = temp >> 16;
     /* Note: top 16 bits of this last word are the security checksum */
 }
 
-void rxi_PrepareSendPacket(call, p, last)
-    register struct rx_call *call;
-    register struct rx_packet *p;
-    register int last;
+void
+rxi_PrepareSendPacket(register struct rx_call *call,
+                     register struct rx_packet *p, register int last)
 {
     register struct rx_connection *conn = call->conn;
     int i, j;
-    ssize_t len;       /* len must be a signed type; it can go negative */
+    ssize_t len;               /* len must be a signed type; it can go negative */
 
-    p->acked = 0;
+    p->flags &= ~RX_PKTFLAG_ACKED;
     p->header.cid = (conn->cid | call->channel);
     p->header.serviceId = conn->serviceId;
     p->header.securityIndex = conn->securityIndex;
+
+    /* No data packets on call 0. Where do these come from? */
+    if (*call->callNumber == 0)
+       *call->callNumber = 1;
+
     p->header.callNumber = *call->callNumber;
     p->header.seq = call->tnext++;
     p->header.epoch = conn->epoch;
     p->header.type = RX_PACKET_TYPE_DATA;
     p->header.flags = 0;
     p->header.spare = 0;
-    if (conn->type == RX_CLIENT_CONNECTION) 
-      p->header.flags |= RX_CLIENT_INITIATED;
+    if (conn->type == RX_CLIENT_CONNECTION)
+       p->header.flags |= RX_CLIENT_INITIATED;
 
     if (last)
-      p->header.flags |= RX_LAST_PACKET;
+       p->header.flags |= RX_LAST_PACKET;
 
-    clock_Zero(&p->retryTime); /* Never yet transmitted */
-    clock_Zero(&p->firstSent); /* Never yet transmitted */
-    p->header.serial = 0;      /* Another way of saying never transmitted... */
+    clock_Zero(&p->retryTime); /* Never yet transmitted */
+    clock_Zero(&p->firstSent); /* Never yet transmitted */
+    p->header.serial = 0;      /* Another way of saying never transmitted... */
     p->backoff = 0;
 
     /* Now that we're sure this is the last data on the call, make sure
      * that the "length" and the sum of the iov_lens matches. */
     len = p->length + call->conn->securityHeaderSize;
 
-    for (i=1; i < p->niovecs && len > 0; i++) {
-      len -=  p->wirevec[i].iov_len;
+    for (i = 1; i < p->niovecs && len > 0; i++) {
+       len -= p->wirevec[i].iov_len;
     }
     if (len > 0) {
-      osi_Panic("PrepareSendPacket 1\n"); /* MTUXXX */
-    }
-    else {
-      /* Free any extra elements in the wirevec */
-      for (j = MAX(2,i) ; j < p->niovecs ; j++) {
-       rxi_freeCBuf(RX_CBUF_TO_PACKET(p->wirevec[j].iov_base, p));
-      }
-      p->niovecs = i;
-      p->wirevec[i-1].iov_len += len;
+       osi_Panic("PrepareSendPacket 1\n");     /* MTUXXX */
+    } else {
+        struct rx_queue q;
+       int nb;
+
+       queue_Init(&q);
+
+       /* Free any extra elements in the wirevec */
+       for (j = MAX(2, i), nb = p->niovecs - j; j < p->niovecs; j++) {
+           queue_Append(&q,RX_CBUF_TO_PACKET(p->wirevec[j].iov_base, p));
+       }
+       if (nb)
+           rxi_FreePackets(nb, &q);
+
+       p->niovecs = i;
+       p->wirevec[i - 1].iov_len += len;
     }
     RXS_PreparePacket(conn->securityObject, call, p);
 }
@@ -1882,7 +2563,8 @@ void rxi_PrepareSendPacket(call, p, last)
 /* Given an interface MTU size, calculate an adjusted MTU size that
  * will make efficient use of the RX buffers when the peer is sending
  * either AFS 3.4a jumbograms or AFS 3.5 jumbograms.  */
-int rxi_AdjustIfMTU(int mtu)
+int
+rxi_AdjustIfMTU(int mtu)
 {
     int adjMTU;
     int frags;
@@ -1902,7 +2584,8 @@ int rxi_AdjustIfMTU(int mtu)
 /* Given an interface MTU size, and the peer's advertised max receive
  * size, calculate an adjisted maxMTU size that makes efficient use
  * of our packet buffers when we are sending AFS 3.4a jumbograms. */
-int rxi_AdjustMaxMTU(int mtu, int peerMaxMTU)
+int
+rxi_AdjustMaxMTU(int mtu, int peerMaxMTU)
 {
     int maxMTU = mtu * rxi_nSendFrags;
     maxMTU = MIN(maxMTU, peerMaxMTU);
@@ -1913,7 +2596,8 @@ int rxi_AdjustMaxMTU(int mtu, int peerMaxMTU)
  * The first buffer always contains RX_HEADER_SIZE+RX_JUMBOBUFFERSIZE+
  * RX_JUMBOHEADERSIZE, the middle buffers contain RX_JUMBOBUFFERSIZE+
  * RX_JUMBOHEADERSIZE, and the last buffer contains RX_JUMBOBUFFERSIZE */
-int rxi_AdjustDgramPackets(int frags, int mtu)
+int
+rxi_AdjustDgramPackets(int frags, int mtu)
 {
     int maxMTU;
     if (mtu + IPv6_FRAG_HDR_SIZE < RX_JUMBOBUFFERSIZE + RX_HEADER_SIZE) {