60f08523e59df78aa5317dae28e76e38fa2b53d3
[openafs.git] / src / rx / rx_rdwr.c
1  /*
2   * Copyright 2000, International Business Machines Corporation and others.
3   * All Rights Reserved.
4   *
5   * This software has been released under the terms of the IBM Public
6   * License.  For details, see the LICENSE file in the top-level source
7   * directory or online at http://www.openafs.org/dl/license10.html
8   */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12
13 #ifdef KERNEL
14 # ifndef UKERNEL
15 #  ifdef RX_KERNEL_TRACE
16 #   include "rx_kcommon.h"
17 #  endif
18 #  if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
19 #   include "afs/sysincludes.h"
20 #  else
21 #   include "h/types.h"
22 #   include "h/time.h"
23 #   include "h/stat.h"
24 #   if defined(AFS_AIX_ENV) || defined(AFS_AUX_ENV) || defined(AFS_SUN5_ENV)
25 #    include "h/systm.h"
26 #   endif
27 #   ifdef       AFS_OSF_ENV
28 #    include <net/net_globals.h>
29 #   endif /* AFS_OSF_ENV */
30 #   ifdef AFS_LINUX20_ENV
31 #    include "h/socket.h"
32 #   endif
33 #   include "netinet/in.h"
34 #   if defined(AFS_SGI_ENV)
35 #    include "afs/sysincludes.h"
36 #   endif
37 #  endif
38 #  include "afs/afs_args.h"
39 #  if   (defined(AFS_AUX_ENV) || defined(AFS_AIX_ENV))
40 #   include "h/systm.h"
41 #  endif
42 # else /* !UKERNEL */
43 #  include "afs/sysincludes.h"
44 # endif /* !UKERNEL */
45
46 # ifdef RXDEBUG
47 #  undef RXDEBUG                        /* turn off debugging */
48 # endif /* RXDEBUG */
49
50 # include "afs/afs_osi.h"
51 # include "rx_kmutex.h"
52 # include "rx/rx_kernel.h"
53 # include "afs/lock.h"
54 #else /* KERNEL */
55 # include <roken.h>
56 #endif /* KERNEL */
57
58 #include "rx.h"
59 #include "rx_clock.h"
60 #include "rx_queue.h"
61 #include "rx_globals.h"
62
63 #include "rx_conn.h"
64 #include "rx_call.h"
65 #include "rx_packet.h"
66
67 #ifdef RX_LOCKS_DB
68 /* rxdb_fileID is used to identify the lock location, along with line#. */
69 static int rxdb_fileID = RXDB_FILE_RX_RDWR;
70 #endif /* RX_LOCKS_DB */
71 /* rxi_ReadProc -- internal version.
72  *
73  * LOCKS USED -- called at netpri
74  */
75 int
76 rxi_ReadProc(struct rx_call *call, char *buf,
77              int nbytes)
78 {
79     struct rx_packet *cp = call->currentPacket;
80     struct rx_packet *rp;
81     int requestCount;
82     unsigned int t;
83
84 /* XXXX took out clock_NewTime from here.  Was it needed? */
85     requestCount = nbytes;
86
87     /* Free any packets from the last call to ReadvProc/WritevProc */
88     if (queue_IsNotEmpty(&call->iovq)) {
89 #ifdef RXDEBUG_PACKET
90         call->iovqc -=
91 #endif /* RXDEBUG_PACKET */
92             rxi_FreePackets(0, &call->iovq);
93     }
94
95     do {
96         if (call->nLeft == 0) {
97             /* Get next packet */
98             MUTEX_ENTER(&call->lock);
99             for (;;) {
100                 if (call->error || (call->mode != RX_MODE_RECEIVING)) {
101                     if (call->error) {
102                         call->mode = RX_MODE_ERROR;
103                         MUTEX_EXIT(&call->lock);
104                         return 0;
105                     }
106                     if (call->mode == RX_MODE_SENDING) {
107                         MUTEX_EXIT(&call->lock);
108                         rxi_FlushWrite(call);
109                         MUTEX_ENTER(&call->lock);
110                         continue;
111                     }
112                 }
113                 if (queue_IsNotEmpty(&call->rq)) {
114                     /* Check that next packet available is next in sequence */
115                     rp = queue_First(&call->rq, rx_packet);
116                     if (rp->header.seq == call->rnext) {
117                         afs_int32 error;
118                         struct rx_connection *conn = call->conn;
119                         queue_Remove(rp);
120 #ifdef RX_TRACK_PACKETS
121                         rp->flags &= ~RX_PKTFLAG_RQ;
122 #endif
123 #ifdef RXDEBUG_PACKET
124                         call->rqc--;
125 #endif /* RXDEBUG_PACKET */
126
127                         /* RXS_CheckPacket called to undo RXS_PreparePacket's
128                          * work.  It may reduce the length of the packet by up
129                          * to conn->maxTrailerSize, to reflect the length of the
130                          * data + the header. */
131                         if ((error =
132                              RXS_CheckPacket(conn->securityObject, call,
133                                              rp))) {
134                             /* Used to merely shut down the call, but now we
135                              * shut down the whole connection since this may
136                              * indicate an attempt to hijack it */
137
138                             MUTEX_EXIT(&call->lock);
139                             rxi_ConnectionError(conn, error);
140                             MUTEX_ENTER(&conn->conn_data_lock);
141                             rp = rxi_SendConnectionAbort(conn, rp, 0, 0);
142                             MUTEX_EXIT(&conn->conn_data_lock);
143                             rxi_FreePacket(rp);
144
145                             return 0;
146                         }
147                         call->rnext++;
148                         cp = call->currentPacket = rp;
149 #ifdef RX_TRACK_PACKETS
150                         call->currentPacket->flags |= RX_PKTFLAG_CP;
151 #endif
152                         call->curvec = 1;       /* 0th vec is always header */
153                         /* begin at the beginning [ more or less ], continue
154                          * on until the end, then stop. */
155                         call->curpos =
156                             (char *)cp->wirevec[1].iov_base +
157                             call->conn->securityHeaderSize;
158                         call->curlen =
159                             cp->wirevec[1].iov_len -
160                             call->conn->securityHeaderSize;
161
162                         /* Notice that this code works correctly if the data
163                          * size is 0 (which it may be--no reply arguments from
164                          * server, for example).  This relies heavily on the
165                          * fact that the code below immediately frees the packet
166                          * (no yields, etc.).  If it didn't, this would be a
167                          * problem because a value of zero for call->nLeft
168                          * normally means that there is no read packet */
169                         call->nLeft = cp->length;
170                         hadd32(call->bytesRcvd, cp->length);
171
172                         /* Send a hard ack for every rxi_HardAckRate+1 packets
173                          * consumed. Otherwise schedule an event to send
174                          * the hard ack later on.
175                          */
176                         call->nHardAcks++;
177                         if (!(call->flags & RX_CALL_RECEIVE_DONE)) {
178                             if (call->nHardAcks > (u_short) rxi_HardAckRate) {
179                                 rxevent_Cancel(&call->delayedAckEvent, call,
180                                                RX_CALL_REFCOUNT_DELAY);
181                                 rxi_SendAck(call, 0, 0, RX_ACK_DELAY, 0);
182                             } else {
183                                 /* Delay to consolidate ack packets */
184                                 rxi_PostDelayedAckEvent(call,
185                                                         &rx_hardAckDelay);
186                             }
187                         }
188                         break;
189                     }
190                 }
191
192                 /*
193                  * If we reach this point either we have no packets in the
194                  * receive queue or the next packet in the queue is not the
195                  * one we are looking for.  There is nothing else for us to
196                  * do but wait for another packet to arrive.
197                  */
198
199                 /* Are there ever going to be any more packets? */
200                 if (call->flags & RX_CALL_RECEIVE_DONE) {
201                     MUTEX_EXIT(&call->lock);
202                     return requestCount - nbytes;
203                 }
204                 /* Wait for in-sequence packet */
205                 call->flags |= RX_CALL_READER_WAIT;
206                 clock_NewTime();
207                 call->startWait = clock_Sec();
208                 while (call->flags & RX_CALL_READER_WAIT) {
209 #ifdef  RX_ENABLE_LOCKS
210                     CV_WAIT(&call->cv_rq, &call->lock);
211 #else
212                     osi_rxSleep(&call->rq);
213 #endif
214                 }
215                 cp = call->currentPacket;
216
217                 call->startWait = 0;
218 #ifdef RX_ENABLE_LOCKS
219                 if (call->error) {
220                     MUTEX_EXIT(&call->lock);
221                     return 0;
222                 }
223 #endif /* RX_ENABLE_LOCKS */
224             }
225             MUTEX_EXIT(&call->lock);
226         } else
227             /* osi_Assert(cp); */
228             /* MTUXXX  this should be replaced by some error-recovery code before shipping */
229             /* yes, the following block is allowed to be the ELSE clause (or not) */
230             /* It's possible for call->nLeft to be smaller than any particular
231              * iov_len.  Usually, recvmsg doesn't change the iov_len, since it
232              * reflects the size of the buffer.  We have to keep track of the
233              * number of bytes read in the length field of the packet struct.  On
234              * the final portion of a received packet, it's almost certain that
235              * call->nLeft will be smaller than the final buffer. */
236             while (nbytes && cp) {
237                 t = MIN((int)call->curlen, nbytes);
238                 t = MIN(t, (int)call->nLeft);
239                 memcpy(buf, call->curpos, t);
240                 buf += t;
241                 nbytes -= t;
242                 call->curpos += t;
243                 call->curlen -= t;
244                 call->nLeft -= t;
245
246                 if (!call->nLeft) {
247                     /* out of packet.  Get another one. */
248 #ifdef RX_TRACK_PACKETS
249                     call->currentPacket->flags &= ~RX_PKTFLAG_CP;
250 #endif
251                     rxi_FreePacket(cp);
252                     cp = call->currentPacket = (struct rx_packet *)0;
253                 } else if (!call->curlen) {
254                     /* need to get another struct iov */
255                     if (++call->curvec >= cp->niovecs) {
256                         /* current packet is exhausted, get ready for another */
257                         /* don't worry about curvec and stuff, they get set somewhere else */
258 #ifdef RX_TRACK_PACKETS
259                         call->currentPacket->flags &= ~RX_PKTFLAG_CP;
260 #endif
261                         rxi_FreePacket(cp);
262                         cp = call->currentPacket = (struct rx_packet *)0;
263                         call->nLeft = 0;
264                     } else {
265                         call->curpos =
266                             (char *)cp->wirevec[call->curvec].iov_base;
267                         call->curlen = cp->wirevec[call->curvec].iov_len;
268                     }
269                 }
270             }
271         if (!nbytes) {
272             /* user buffer is full, return */
273             return requestCount;
274         }
275
276     } while (nbytes);
277
278     return requestCount;
279 }
280
281 int
282 rx_ReadProc(struct rx_call *call, char *buf, int nbytes)
283 {
284     int bytes;
285     SPLVAR;
286
287     /* Free any packets from the last call to ReadvProc/WritevProc */
288     if (!queue_IsEmpty(&call->iovq)) {
289 #ifdef RXDEBUG_PACKET
290         call->iovqc -=
291 #endif /* RXDEBUG_PACKET */
292             rxi_FreePackets(0, &call->iovq);
293     }
294
295     /*
296      * Most common case, all of the data is in the current iovec.
297      * We are relying on nLeft being zero unless the call is in receive mode.
298      */
299     if (!call->error && call->curlen > nbytes && call->nLeft > nbytes) {
300         memcpy(buf, call->curpos, nbytes);
301
302         call->curpos += nbytes;
303         call->curlen -= nbytes;
304         call->nLeft  -= nbytes;
305
306         if (!call->nLeft && call->currentPacket != NULL) {
307             /* out of packet.  Get another one. */
308             rxi_FreePacket(call->currentPacket);
309             call->currentPacket = (struct rx_packet *)0;
310         }
311         return nbytes;
312     }
313
314     NETPRI;
315     bytes = rxi_ReadProc(call, buf, nbytes);
316     USERPRI;
317     return bytes;
318 }
319
320 /* Optimization for unmarshalling 32 bit integers */
321 int
322 rx_ReadProc32(struct rx_call *call, afs_int32 * value)
323 {
324     int bytes;
325     SPLVAR;
326
327     /* Free any packets from the last call to ReadvProc/WritevProc */
328     if (!queue_IsEmpty(&call->iovq)) {
329 #ifdef RXDEBUG_PACKET
330         call->iovqc -=
331 #endif /* RXDEBUG_PACKET */
332             rxi_FreePackets(0, &call->iovq);
333     }
334
335     /*
336      * Most common case, all of the data is in the current iovec.
337      * We are relying on nLeft being zero unless the call is in receive mode.
338      */
339     if (!call->error && call->curlen >= sizeof(afs_int32)
340         && call->nLeft >= sizeof(afs_int32)) {
341
342         memcpy((char *)value, call->curpos, sizeof(afs_int32));
343
344         call->curpos += sizeof(afs_int32);
345         call->curlen -= sizeof(afs_int32);
346         call->nLeft  -= sizeof(afs_int32);
347
348         if (!call->nLeft && call->currentPacket != NULL) {
349             /* out of packet.  Get another one. */
350             rxi_FreePacket(call->currentPacket);
351             call->currentPacket = (struct rx_packet *)0;
352         }
353         return sizeof(afs_int32);
354     }
355
356     NETPRI;
357     bytes = rxi_ReadProc(call, (char *)value, sizeof(afs_int32));
358     USERPRI;
359
360     return bytes;
361 }
362
363 /* rxi_FillReadVec
364  *
365  * Uses packets in the receive queue to fill in as much of the
366  * current iovec as possible. Does not block if it runs out
367  * of packets to complete the iovec. Return true if an ack packet
368  * was sent, otherwise return false */
369 int
370 rxi_FillReadVec(struct rx_call *call, afs_uint32 serial)
371 {
372     int didConsume = 0;
373     int didHardAck = 0;
374     unsigned int t;
375     struct rx_packet *rp;
376     struct rx_packet *curp;
377     struct iovec *call_iov;
378     struct iovec *cur_iov = NULL;
379
380     curp = call->currentPacket;
381     if (curp) {
382         cur_iov = &curp->wirevec[call->curvec];
383     }
384     call_iov = &call->iov[call->iovNext];
385
386     while (!call->error && call->iovNBytes && call->iovNext < call->iovMax) {
387         if (call->nLeft == 0) {
388             /* Get next packet */
389             if (queue_IsNotEmpty(&call->rq)) {
390                 /* Check that next packet available is next in sequence */
391                 rp = queue_First(&call->rq, rx_packet);
392                 if (rp->header.seq == call->rnext) {
393                     afs_int32 error;
394                     struct rx_connection *conn = call->conn;
395                     queue_Remove(rp);
396 #ifdef RX_TRACK_PACKETS
397                     rp->flags &= ~RX_PKTFLAG_RQ;
398 #endif
399 #ifdef RXDEBUG_PACKET
400                     call->rqc--;
401 #endif /* RXDEBUG_PACKET */
402
403                     /* RXS_CheckPacket called to undo RXS_PreparePacket's
404                      * work.  It may reduce the length of the packet by up
405                      * to conn->maxTrailerSize, to reflect the length of the
406                      * data + the header. */
407                     if ((error =
408                          RXS_CheckPacket(conn->securityObject, call, rp))) {
409                         /* Used to merely shut down the call, but now we
410                          * shut down the whole connection since this may
411                          * indicate an attempt to hijack it */
412
413                         MUTEX_EXIT(&call->lock);
414                         rxi_ConnectionError(conn, error);
415                         MUTEX_ENTER(&conn->conn_data_lock);
416                         rp = rxi_SendConnectionAbort(conn, rp, 0, 0);
417                         MUTEX_EXIT(&conn->conn_data_lock);
418                         rxi_FreePacket(rp);
419                         MUTEX_ENTER(&call->lock);
420
421                         return 1;
422                     }
423                     call->rnext++;
424                     curp = call->currentPacket = rp;
425 #ifdef RX_TRACK_PACKETS
426                     call->currentPacket->flags |= RX_PKTFLAG_CP;
427 #endif
428                     call->curvec = 1;   /* 0th vec is always header */
429                     cur_iov = &curp->wirevec[1];
430                     /* begin at the beginning [ more or less ], continue
431                      * on until the end, then stop. */
432                     call->curpos =
433                         (char *)curp->wirevec[1].iov_base +
434                         call->conn->securityHeaderSize;
435                     call->curlen =
436                         curp->wirevec[1].iov_len -
437                         call->conn->securityHeaderSize;
438
439                     /* Notice that this code works correctly if the data
440                      * size is 0 (which it may be--no reply arguments from
441                      * server, for example).  This relies heavily on the
442                      * fact that the code below immediately frees the packet
443                      * (no yields, etc.).  If it didn't, this would be a
444                      * problem because a value of zero for call->nLeft
445                      * normally means that there is no read packet */
446                     call->nLeft = curp->length;
447                     hadd32(call->bytesRcvd, curp->length);
448
449                     /* Send a hard ack for every rxi_HardAckRate+1 packets
450                      * consumed. Otherwise schedule an event to send
451                      * the hard ack later on.
452                      */
453                     call->nHardAcks++;
454                     didConsume = 1;
455                     continue;
456                 }
457             }
458             break;
459         }
460
461         /* It's possible for call->nLeft to be smaller than any particular
462          * iov_len.  Usually, recvmsg doesn't change the iov_len, since it
463          * reflects the size of the buffer.  We have to keep track of the
464          * number of bytes read in the length field of the packet struct.  On
465          * the final portion of a received packet, it's almost certain that
466          * call->nLeft will be smaller than the final buffer. */
467         while (call->iovNBytes && call->iovNext < call->iovMax && curp) {
468
469             t = MIN((int)call->curlen, call->iovNBytes);
470             t = MIN(t, (int)call->nLeft);
471             call_iov->iov_base = call->curpos;
472             call_iov->iov_len = t;
473             call_iov++;
474             call->iovNext++;
475             call->iovNBytes -= t;
476             call->curpos += t;
477             call->curlen -= t;
478             call->nLeft -= t;
479
480             if (!call->nLeft) {
481                 /* out of packet.  Get another one. */
482 #ifdef RX_TRACK_PACKETS
483                 curp->flags &= ~RX_PKTFLAG_CP;
484                 curp->flags |= RX_PKTFLAG_IOVQ;
485 #endif
486                 queue_Append(&call->iovq, curp);
487 #ifdef RXDEBUG_PACKET
488                 call->iovqc++;
489 #endif /* RXDEBUG_PACKET */
490                 curp = call->currentPacket = (struct rx_packet *)0;
491             } else if (!call->curlen) {
492                 /* need to get another struct iov */
493                 if (++call->curvec >= curp->niovecs) {
494                     /* current packet is exhausted, get ready for another */
495                     /* don't worry about curvec and stuff, they get set somewhere else */
496 #ifdef RX_TRACK_PACKETS
497                     curp->flags &= ~RX_PKTFLAG_CP;
498                     curp->flags |= RX_PKTFLAG_IOVQ;
499 #endif
500                     queue_Append(&call->iovq, curp);
501 #ifdef RXDEBUG_PACKET
502                     call->iovqc++;
503 #endif /* RXDEBUG_PACKET */
504                     curp = call->currentPacket = (struct rx_packet *)0;
505                     call->nLeft = 0;
506                 } else {
507                     cur_iov++;
508                     call->curpos = (char *)cur_iov->iov_base;
509                     call->curlen = cur_iov->iov_len;
510                 }
511             }
512         }
513     }
514
515     /* If we consumed any packets then check whether we need to
516      * send a hard ack. */
517     if (didConsume && (!(call->flags & RX_CALL_RECEIVE_DONE))) {
518         if (call->nHardAcks > (u_short) rxi_HardAckRate) {
519             rxevent_Cancel(&call->delayedAckEvent, call,
520                            RX_CALL_REFCOUNT_DELAY);
521             rxi_SendAck(call, 0, serial, RX_ACK_DELAY, 0);
522             didHardAck = 1;
523         } else {
524             /* Delay to consolidate ack packets */
525             rxi_PostDelayedAckEvent(call, &rx_hardAckDelay);
526         }
527     }
528     return didHardAck;
529 }
530
531
532 /* rxi_ReadvProc -- internal version.
533  *
534  * Fills in an iovec with pointers to the packet buffers. All packets
535  * except the last packet (new current packet) are moved to the iovq
536  * while the application is processing the data.
537  *
538  * LOCKS USED -- called at netpri.
539  */
540 int
541 rxi_ReadvProc(struct rx_call *call, struct iovec *iov, int *nio, int maxio,
542               int nbytes)
543 {
544     int bytes;
545
546     /* Free any packets from the last call to ReadvProc/WritevProc */
547     if (queue_IsNotEmpty(&call->iovq)) {
548 #ifdef RXDEBUG_PACKET
549         call->iovqc -=
550 #endif /* RXDEBUG_PACKET */
551             rxi_FreePackets(0, &call->iovq);
552     }
553
554     if (call->mode == RX_MODE_SENDING) {
555         rxi_FlushWrite(call);
556     }
557
558     MUTEX_ENTER(&call->lock);
559     if (call->error)
560         goto error;
561
562     /* Get whatever data is currently available in the receive queue.
563      * If rxi_FillReadVec sends an ack packet then it is possible
564      * that we will receive more data while we drop the call lock
565      * to send the packet. Set the RX_CALL_IOVEC_WAIT flag
566      * here to avoid a race with the receive thread if we send
567      * hard acks in rxi_FillReadVec. */
568     call->flags |= RX_CALL_IOVEC_WAIT;
569     call->iovNBytes = nbytes;
570     call->iovMax = maxio;
571     call->iovNext = 0;
572     call->iov = iov;
573     rxi_FillReadVec(call, 0);
574
575     /* if we need more data then sleep until the receive thread has
576      * filled in the rest. */
577     if (!call->error && call->iovNBytes && call->iovNext < call->iovMax
578         && !(call->flags & RX_CALL_RECEIVE_DONE)) {
579         call->flags |= RX_CALL_READER_WAIT;
580         clock_NewTime();
581         call->startWait = clock_Sec();
582         while (call->flags & RX_CALL_READER_WAIT) {
583 #ifdef  RX_ENABLE_LOCKS
584             CV_WAIT(&call->cv_rq, &call->lock);
585 #else
586             osi_rxSleep(&call->rq);
587 #endif
588         }
589         call->startWait = 0;
590     }
591     call->flags &= ~RX_CALL_IOVEC_WAIT;
592
593     if (call->error)
594         goto error;
595
596     call->iov = NULL;
597     *nio = call->iovNext;
598     bytes = nbytes - call->iovNBytes;
599     MUTEX_EXIT(&call->lock);
600     return bytes;
601
602   error:
603     MUTEX_EXIT(&call->lock);
604     call->mode = RX_MODE_ERROR;
605     return 0;
606 }
607
608 int
609 rx_ReadvProc(struct rx_call *call, struct iovec *iov, int *nio, int maxio,
610              int nbytes)
611 {
612     int bytes;
613     SPLVAR;
614
615     NETPRI;
616     bytes = rxi_ReadvProc(call, iov, nio, maxio, nbytes);
617     USERPRI;
618     return bytes;
619 }
620
621 /* rxi_WriteProc -- internal version.
622  *
623  * LOCKS USED -- called at netpri
624  */
625
626 int
627 rxi_WriteProc(struct rx_call *call, char *buf,
628               int nbytes)
629 {
630     struct rx_connection *conn = call->conn;
631     struct rx_packet *cp = call->currentPacket;
632     unsigned int t;
633     int requestCount = nbytes;
634
635     /* Free any packets from the last call to ReadvProc/WritevProc */
636     if (queue_IsNotEmpty(&call->iovq)) {
637 #ifdef RXDEBUG_PACKET
638         call->iovqc -=
639 #endif /* RXDEBUG_PACKET */
640             rxi_FreePackets(0, &call->iovq);
641     }
642
643     if (call->mode != RX_MODE_SENDING) {
644         if ((conn->type == RX_SERVER_CONNECTION)
645             && (call->mode == RX_MODE_RECEIVING)) {
646             call->mode = RX_MODE_SENDING;
647             if (cp) {
648 #ifdef RX_TRACK_PACKETS
649                 cp->flags &= ~RX_PKTFLAG_CP;
650 #endif
651                 rxi_FreePacket(cp);
652                 cp = call->currentPacket = (struct rx_packet *)0;
653                 call->nLeft = 0;
654                 call->nFree = 0;
655             }
656         } else {
657             return 0;
658         }
659     }
660
661     /* Loop condition is checked at end, so that a write of 0 bytes
662      * will force a packet to be created--specially for the case where
663      * there are 0 bytes on the stream, but we must send a packet
664      * anyway. */
665     do {
666         if (call->nFree == 0) {
667             MUTEX_ENTER(&call->lock);
668             cp = call->currentPacket;
669             if (call->error)
670                 call->mode = RX_MODE_ERROR;
671             if (!call->error && cp) {
672                 /* Clear the current packet now so that if
673                  * we are forced to wait and drop the lock
674                  * the packet we are planning on using
675                  * cannot be freed.
676                  */
677 #ifdef RX_TRACK_PACKETS
678                 cp->flags &= ~RX_PKTFLAG_CP;
679 #endif
680                 call->currentPacket = (struct rx_packet *)0;
681                 clock_NewTime();        /* Bogus:  need new time package */
682                 /* The 0, below, specifies that it is not the last packet:
683                  * there will be others. PrepareSendPacket may
684                  * alter the packet length by up to
685                  * conn->securityMaxTrailerSize */
686                 hadd32(call->bytesSent, cp->length);
687                 rxi_PrepareSendPacket(call, cp, 0);
688 #ifdef  AFS_GLOBAL_RXLOCK_KERNEL
689                 /* PrepareSendPacket drops the call lock */
690                 rxi_WaitforTQBusy(call);
691 #endif /* AFS_GLOBAL_RXLOCK_KERNEL */
692 #ifdef RX_TRACK_PACKETS
693                 cp->flags |= RX_PKTFLAG_TQ;
694 #endif
695                 queue_Append(&call->tq, cp);
696 #ifdef RXDEBUG_PACKET
697                 call->tqc++;
698 #endif /* RXDEBUG_PACKET */
699                 cp = (struct rx_packet *)0;
700                 /* If the call is in recovery, let it exhaust its current
701                  * retransmit queue before forcing it to send new packets
702                  */
703                 if (!(call->flags & (RX_CALL_FAST_RECOVER))) {
704                     rxi_Start(call, 0);
705                 }
706             } else if (cp) {
707 #ifdef RX_TRACK_PACKETS
708                 cp->flags &= ~RX_PKTFLAG_CP;
709 #endif
710                 rxi_FreePacket(cp);
711                 cp = call->currentPacket = (struct rx_packet *)0;
712             }
713             /* Wait for transmit window to open up */
714             while (!call->error
715                    && call->tnext + 1 > call->tfirst + (2 * call->twind)) {
716                 clock_NewTime();
717                 call->startWait = clock_Sec();
718
719 #ifdef  RX_ENABLE_LOCKS
720                 CV_WAIT(&call->cv_twind, &call->lock);
721 #else
722                 call->flags |= RX_CALL_WAIT_WINDOW_ALLOC;
723                 osi_rxSleep(&call->twind);
724 #endif
725
726                 call->startWait = 0;
727 #ifdef RX_ENABLE_LOCKS
728                 if (call->error) {
729                     call->mode = RX_MODE_ERROR;
730                     MUTEX_EXIT(&call->lock);
731                     return 0;
732                 }
733 #endif /* RX_ENABLE_LOCKS */
734             }
735             if ((cp = rxi_AllocSendPacket(call, nbytes))) {
736 #ifdef RX_TRACK_PACKETS
737                 cp->flags |= RX_PKTFLAG_CP;
738 #endif
739                 call->currentPacket = cp;
740                 call->nFree = cp->length;
741                 call->curvec = 1;       /* 0th vec is always header */
742                 /* begin at the beginning [ more or less ], continue
743                  * on until the end, then stop. */
744                 call->curpos =
745                     (char *)cp->wirevec[1].iov_base +
746                     call->conn->securityHeaderSize;
747                 call->curlen =
748                     cp->wirevec[1].iov_len - call->conn->securityHeaderSize;
749             }
750             if (call->error) {
751                 call->mode = RX_MODE_ERROR;
752                 if (cp) {
753 #ifdef RX_TRACK_PACKETS
754                     cp->flags &= ~RX_PKTFLAG_CP;
755 #endif
756                     rxi_FreePacket(cp);
757                     call->currentPacket = NULL;
758                 }
759                 MUTEX_EXIT(&call->lock);
760                 return 0;
761             }
762             MUTEX_EXIT(&call->lock);
763         }
764
765         if (cp && (int)call->nFree < nbytes) {
766             /* Try to extend the current buffer */
767             int len, mud;
768             len = cp->length;
769             mud = rx_MaxUserDataSize(call);
770             if (mud > len) {
771                 int want;
772                 want = MIN(nbytes - (int)call->nFree, mud - len);
773                 rxi_AllocDataBuf(cp, want, RX_PACKET_CLASS_SEND_CBUF);
774                 if (cp->length > (unsigned)mud)
775                     cp->length = mud;
776                 call->nFree += (cp->length - len);
777             }
778         }
779
780         /* If the remaining bytes fit in the buffer, then store them
781          * and return.  Don't ship a buffer that's full immediately to
782          * the peer--we don't know if it's the last buffer yet */
783
784         if (!cp) {
785             call->nFree = 0;
786         }
787
788         while (nbytes && call->nFree) {
789
790             t = MIN((int)call->curlen, nbytes);
791             t = MIN((int)call->nFree, t);
792             memcpy(call->curpos, buf, t);
793             buf += t;
794             nbytes -= t;
795             call->curpos += t;
796             call->curlen -= (u_short)t;
797             call->nFree -= (u_short)t;
798
799             if (!call->curlen) {
800                 /* need to get another struct iov */
801                 if (++call->curvec >= cp->niovecs) {
802                     /* current packet is full, extend or send it */
803                     call->nFree = 0;
804                 } else {
805                     call->curpos = (char *)cp->wirevec[call->curvec].iov_base;
806                     call->curlen = cp->wirevec[call->curvec].iov_len;
807                 }
808             }
809         }                       /* while bytes to send and room to send them */
810
811         /* might be out of space now */
812         if (!nbytes) {
813             return requestCount;
814         } else;                 /* more data to send, so get another packet and keep going */
815     } while (nbytes);
816
817     return requestCount - nbytes;
818 }
819
820 int
821 rx_WriteProc(struct rx_call *call, char *buf, int nbytes)
822 {
823     int bytes;
824     int tcurlen;
825     int tnFree;
826     char *tcurpos;
827     SPLVAR;
828
829     /* Free any packets from the last call to ReadvProc/WritevProc */
830     if (queue_IsNotEmpty(&call->iovq)) {
831 #ifdef RXDEBUG_PACKET
832         call->iovqc -=
833 #endif /* RXDEBUG_PACKET */
834             rxi_FreePackets(0, &call->iovq);
835     }
836
837     /*
838      * Most common case: all of the data fits in the current iovec.
839      * We are relying on nFree being zero unless the call is in send mode.
840      */
841     tcurlen = (int)call->curlen;
842     tnFree = (int)call->nFree;
843     if (!call->error && tcurlen >= nbytes && tnFree >= nbytes) {
844         tcurpos = call->curpos;
845
846         memcpy(tcurpos, buf, nbytes);
847         call->curpos = tcurpos + nbytes;
848         call->curlen = (u_short)(tcurlen - nbytes);
849         call->nFree = (u_short)(tnFree - nbytes);
850         return nbytes;
851     }
852
853     NETPRI;
854     bytes = rxi_WriteProc(call, buf, nbytes);
855     USERPRI;
856     return bytes;
857 }
858
859 /* Optimization for marshalling 32 bit arguments */
860 int
861 rx_WriteProc32(struct rx_call *call, afs_int32 * value)
862 {
863     int bytes;
864     int tcurlen;
865     int tnFree;
866     char *tcurpos;
867     SPLVAR;
868
869     if (queue_IsNotEmpty(&call->iovq)) {
870 #ifdef RXDEBUG_PACKET
871         call->iovqc -=
872 #endif /* RXDEBUG_PACKET */
873             rxi_FreePackets(0, &call->iovq);
874     }
875
876     /*
877      * Most common case: all of the data fits in the current iovec.
878      * We are relying on nFree being zero unless the call is in send mode.
879      */
880     tcurlen = call->curlen;
881     tnFree = call->nFree;
882     if (!call->error && tcurlen >= sizeof(afs_int32)
883         && tnFree >= sizeof(afs_int32)) {
884         tcurpos = call->curpos;
885
886         if (!((size_t)tcurpos & (sizeof(afs_int32) - 1))) {
887             *((afs_int32 *) (tcurpos)) = *value;
888         } else {
889             memcpy(tcurpos, (char *)value, sizeof(afs_int32));
890         }
891         call->curpos = tcurpos + sizeof(afs_int32);
892         call->curlen = (u_short)(tcurlen - sizeof(afs_int32));
893         call->nFree = (u_short)(tnFree - sizeof(afs_int32));
894         return sizeof(afs_int32);
895     }
896
897     NETPRI;
898     bytes = rxi_WriteProc(call, (char *)value, sizeof(afs_int32));
899     USERPRI;
900     return bytes;
901 }
902
903 /* rxi_WritevAlloc -- internal version.
904  *
905  * Fill in an iovec to point to data in packet buffers. The application
906  * calls rxi_WritevProc when the buffers are full.
907  *
908  * LOCKS USED -- called at netpri.
909  */
910
911 static int
912 rxi_WritevAlloc(struct rx_call *call, struct iovec *iov, int *nio, int maxio,
913                 int nbytes)
914 {
915     struct rx_connection *conn = call->conn;
916     struct rx_packet *cp = call->currentPacket;
917     int requestCount;
918     int nextio;
919     /* Temporary values, real work is done in rxi_WritevProc */
920     int tnFree;
921     unsigned int tcurvec;
922     char *tcurpos;
923     int tcurlen;
924
925     requestCount = nbytes;
926     nextio = 0;
927
928     /* Free any packets from the last call to ReadvProc/WritevProc */
929     if (queue_IsNotEmpty(&call->iovq)) {
930 #ifdef RXDEBUG_PACKET
931         call->iovqc -=
932 #endif /* RXDEBUG_PACKET */
933             rxi_FreePackets(0, &call->iovq);
934     }
935
936     if (call->mode != RX_MODE_SENDING) {
937         if ((conn->type == RX_SERVER_CONNECTION)
938             && (call->mode == RX_MODE_RECEIVING)) {
939             call->mode = RX_MODE_SENDING;
940             if (cp) {
941 #ifdef RX_TRACK_PACKETS
942                 cp->flags &= ~RX_PKTFLAG_CP;
943 #endif
944                 rxi_FreePacket(cp);
945                 cp = call->currentPacket = (struct rx_packet *)0;
946                 call->nLeft = 0;
947                 call->nFree = 0;
948             }
949         } else {
950             return 0;
951         }
952     }
953
954     /* Set up the iovec to point to data in packet buffers. */
955     tnFree = call->nFree;
956     tcurvec = call->curvec;
957     tcurpos = call->curpos;
958     tcurlen = call->curlen;
959     do {
960         int t;
961
962         if (tnFree == 0) {
963             /* current packet is full, allocate a new one */
964             MUTEX_ENTER(&call->lock);
965             cp = rxi_AllocSendPacket(call, nbytes);
966             MUTEX_EXIT(&call->lock);
967             if (cp == NULL) {
968                 /* out of space, return what we have */
969                 *nio = nextio;
970                 return requestCount - nbytes;
971             }
972 #ifdef RX_TRACK_PACKETS
973             cp->flags |= RX_PKTFLAG_IOVQ;
974 #endif
975             queue_Append(&call->iovq, cp);
976 #ifdef RXDEBUG_PACKET
977             call->iovqc++;
978 #endif /* RXDEBUG_PACKET */
979             tnFree = cp->length;
980             tcurvec = 1;
981             tcurpos =
982                 (char *)cp->wirevec[1].iov_base +
983                 call->conn->securityHeaderSize;
984             tcurlen = cp->wirevec[1].iov_len - call->conn->securityHeaderSize;
985         }
986
987         if (tnFree < nbytes) {
988             /* try to extend the current packet */
989             int len, mud;
990             len = cp->length;
991             mud = rx_MaxUserDataSize(call);
992             if (mud > len) {
993                 int want;
994                 want = MIN(nbytes - tnFree, mud - len);
995                 rxi_AllocDataBuf(cp, want, RX_PACKET_CLASS_SEND_CBUF);
996                 if (cp->length > (unsigned)mud)
997                     cp->length = mud;
998                 tnFree += (cp->length - len);
999                 if (cp == call->currentPacket) {
1000                     call->nFree += (cp->length - len);
1001                 }
1002             }
1003         }
1004
1005         /* fill in the next entry in the iovec */
1006         t = MIN(tcurlen, nbytes);
1007         t = MIN(tnFree, t);
1008         iov[nextio].iov_base = tcurpos;
1009         iov[nextio].iov_len = t;
1010         nbytes -= t;
1011         tcurpos += t;
1012         tcurlen -= t;
1013         tnFree -= t;
1014         nextio++;
1015
1016         if (!tcurlen) {
1017             /* need to get another struct iov */
1018             if (++tcurvec >= cp->niovecs) {
1019                 /* current packet is full, extend it or move on to next packet */
1020                 tnFree = 0;
1021             } else {
1022                 tcurpos = (char *)cp->wirevec[tcurvec].iov_base;
1023                 tcurlen = cp->wirevec[tcurvec].iov_len;
1024             }
1025         }
1026     } while (nbytes && nextio < maxio);
1027     *nio = nextio;
1028     return requestCount - nbytes;
1029 }
1030
1031 int
1032 rx_WritevAlloc(struct rx_call *call, struct iovec *iov, int *nio, int maxio,
1033                int nbytes)
1034 {
1035     int bytes;
1036     SPLVAR;
1037
1038     NETPRI;
1039     bytes = rxi_WritevAlloc(call, iov, nio, maxio, nbytes);
1040     USERPRI;
1041     return bytes;
1042 }
1043
1044 /* rxi_WritevProc -- internal version.
1045  *
1046  * Send buffers allocated in rxi_WritevAlloc.
1047  *
1048  * LOCKS USED -- called at netpri.
1049  */
1050 int
1051 rxi_WritevProc(struct rx_call *call, struct iovec *iov, int nio, int nbytes)
1052 {
1053     struct rx_packet *cp = NULL;
1054 #ifdef RX_TRACK_PACKETS
1055     struct rx_packet *p, *np;
1056 #endif
1057     int nextio;
1058     int requestCount;
1059     struct rx_queue tmpq;
1060 #ifdef RXDEBUG_PACKET
1061     u_short tmpqc;
1062 #endif
1063
1064     requestCount = nbytes;
1065     nextio = 0;
1066
1067     MUTEX_ENTER(&call->lock);
1068     if (call->error) {
1069         call->mode = RX_MODE_ERROR;
1070     } else if (call->mode != RX_MODE_SENDING) {
1071         call->error = RX_PROTOCOL_ERROR;
1072     }
1073 #ifdef AFS_GLOBAL_RXLOCK_KERNEL
1074     rxi_WaitforTQBusy(call);
1075 #endif /* AFS_GLOBAL_RXLOCK_KERNEL */
1076     cp = call->currentPacket;
1077
1078     if (call->error) {
1079         call->mode = RX_MODE_ERROR;
1080         MUTEX_EXIT(&call->lock);
1081         if (cp) {
1082 #ifdef RX_TRACK_PACKETS
1083             cp->flags &= ~RX_PKTFLAG_CP;
1084             cp->flags |= RX_PKTFLAG_IOVQ;
1085 #endif
1086             queue_Prepend(&call->iovq, cp);
1087 #ifdef RXDEBUG_PACKET
1088             call->iovqc++;
1089 #endif /* RXDEBUG_PACKET */
1090             call->currentPacket = (struct rx_packet *)0;
1091         }
1092 #ifdef RXDEBUG_PACKET
1093         call->iovqc -=
1094 #endif /* RXDEBUG_PACKET */
1095             rxi_FreePackets(0, &call->iovq);
1096         return 0;
1097     }
1098
1099     /* Loop through the I/O vector adjusting packet pointers.
1100      * Place full packets back onto the iovq once they are ready
1101      * to send. Set RX_PROTOCOL_ERROR if any problems are found in
1102      * the iovec. We put the loop condition at the end to ensure that
1103      * a zero length write will push a short packet. */
1104     nextio = 0;
1105     queue_Init(&tmpq);
1106 #ifdef RXDEBUG_PACKET
1107     tmpqc = 0;
1108 #endif /* RXDEBUG_PACKET */
1109     do {
1110         if (call->nFree == 0 && cp) {
1111             clock_NewTime();    /* Bogus:  need new time package */
1112             /* The 0, below, specifies that it is not the last packet:
1113              * there will be others. PrepareSendPacket may
1114              * alter the packet length by up to
1115              * conn->securityMaxTrailerSize */
1116             hadd32(call->bytesSent, cp->length);
1117             rxi_PrepareSendPacket(call, cp, 0);
1118 #ifdef  AFS_GLOBAL_RXLOCK_KERNEL
1119             /* PrepareSendPacket drops the call lock */
1120             rxi_WaitforTQBusy(call);
1121 #endif /* AFS_GLOBAL_RXLOCK_KERNEL */
1122             queue_Append(&tmpq, cp);
1123 #ifdef RXDEBUG_PACKET
1124             tmpqc++;
1125 #endif /* RXDEBUG_PACKET */
1126             cp = call->currentPacket = (struct rx_packet *)0;
1127
1128             /* The head of the iovq is now the current packet */
1129             if (nbytes) {
1130                 if (queue_IsEmpty(&call->iovq)) {
1131                     MUTEX_EXIT(&call->lock);
1132                     call->error = RX_PROTOCOL_ERROR;
1133 #ifdef RXDEBUG_PACKET
1134                     tmpqc -=
1135 #endif /* RXDEBUG_PACKET */
1136                         rxi_FreePackets(0, &tmpq);
1137                     return 0;
1138                 }
1139                 cp = queue_First(&call->iovq, rx_packet);
1140                 queue_Remove(cp);
1141 #ifdef RX_TRACK_PACKETS
1142                 cp->flags &= ~RX_PKTFLAG_IOVQ;
1143 #endif
1144 #ifdef RXDEBUG_PACKET
1145                 call->iovqc--;
1146 #endif /* RXDEBUG_PACKET */
1147 #ifdef RX_TRACK_PACKETS
1148                 cp->flags |= RX_PKTFLAG_CP;
1149 #endif
1150                 call->currentPacket = cp;
1151                 call->nFree = cp->length;
1152                 call->curvec = 1;
1153                 call->curpos =
1154                     (char *)cp->wirevec[1].iov_base +
1155                     call->conn->securityHeaderSize;
1156                 call->curlen =
1157                     cp->wirevec[1].iov_len - call->conn->securityHeaderSize;
1158             }
1159         }
1160
1161         if (nbytes) {
1162             /* The next iovec should point to the current position */
1163             if (iov[nextio].iov_base != call->curpos
1164                 || iov[nextio].iov_len > (int)call->curlen) {
1165                 call->error = RX_PROTOCOL_ERROR;
1166                 MUTEX_EXIT(&call->lock);
1167                 if (cp) {
1168 #ifdef RX_TRACK_PACKETS
1169                     cp->flags &= ~RX_PKTFLAG_CP;
1170 #endif
1171                     queue_Prepend(&tmpq, cp);
1172 #ifdef RXDEBUG_PACKET
1173                     tmpqc++;
1174 #endif /* RXDEBUG_PACKET */
1175                     cp = call->currentPacket = (struct rx_packet *)0;
1176                 }
1177 #ifdef RXDEBUG_PACKET
1178                 tmpqc -=
1179 #endif /* RXDEBUG_PACKET */
1180                     rxi_FreePackets(0, &tmpq);
1181                 return 0;
1182             }
1183             nbytes -= iov[nextio].iov_len;
1184             call->curpos += iov[nextio].iov_len;
1185             call->curlen -= iov[nextio].iov_len;
1186             call->nFree -= iov[nextio].iov_len;
1187             nextio++;
1188             if (call->curlen == 0) {
1189                 if (++call->curvec > cp->niovecs) {
1190                     call->nFree = 0;
1191                 } else {
1192                     call->curpos = (char *)cp->wirevec[call->curvec].iov_base;
1193                     call->curlen = cp->wirevec[call->curvec].iov_len;
1194                 }
1195             }
1196         }
1197     } while (nbytes && nextio < nio);
1198
1199     /* Move the packets from the temporary queue onto the transmit queue.
1200      * We may end up with more than call->twind packets on the queue. */
1201
1202 #ifdef RX_TRACK_PACKETS
1203     for (queue_Scan(&tmpq, p, np, rx_packet))
1204     {
1205         p->flags |= RX_PKTFLAG_TQ;
1206     }
1207 #endif
1208
1209     if (call->error)
1210         call->mode = RX_MODE_ERROR;
1211
1212     queue_SpliceAppend(&call->tq, &tmpq);
1213
1214     /* If the call is in recovery, let it exhaust its current retransmit
1215      * queue before forcing it to send new packets
1216      */
1217     if (!(call->flags & RX_CALL_FAST_RECOVER)) {
1218         rxi_Start(call, 0);
1219     }
1220
1221     /* Wait for the length of the transmit queue to fall below call->twind */
1222     while (!call->error && call->tnext + 1 > call->tfirst + (2 * call->twind)) {
1223         clock_NewTime();
1224         call->startWait = clock_Sec();
1225 #ifdef  RX_ENABLE_LOCKS
1226         CV_WAIT(&call->cv_twind, &call->lock);
1227 #else
1228         call->flags |= RX_CALL_WAIT_WINDOW_ALLOC;
1229         osi_rxSleep(&call->twind);
1230 #endif
1231         call->startWait = 0;
1232     }
1233
1234     /* cp is no longer valid since we may have given up the lock */
1235     cp = call->currentPacket;
1236
1237     if (call->error) {
1238         call->mode = RX_MODE_ERROR;
1239         call->currentPacket = NULL;
1240         MUTEX_EXIT(&call->lock);
1241         if (cp) {
1242 #ifdef RX_TRACK_PACKETS
1243             cp->flags &= ~RX_PKTFLAG_CP;
1244 #endif
1245             rxi_FreePacket(cp);
1246         }
1247         return 0;
1248     }
1249     MUTEX_EXIT(&call->lock);
1250
1251     return requestCount - nbytes;
1252 }
1253
1254 int
1255 rx_WritevProc(struct rx_call *call, struct iovec *iov, int nio, int nbytes)
1256 {
1257     int bytes;
1258     SPLVAR;
1259
1260     NETPRI;
1261     bytes = rxi_WritevProc(call, iov, nio, nbytes);
1262     USERPRI;
1263     return bytes;
1264 }
1265
1266 /* Flush any buffered data to the stream, switch to read mode
1267  * (clients) or to EOF mode (servers)
1268  *
1269  * LOCKS HELD: called at netpri.
1270  */
1271 void
1272 rxi_FlushWrite(struct rx_call *call)
1273 {
1274     struct rx_packet *cp = NULL;
1275
1276     /* Free any packets from the last call to ReadvProc/WritevProc */
1277     if (queue_IsNotEmpty(&call->iovq)) {
1278 #ifdef RXDEBUG_PACKET
1279         call->iovqc -=
1280 #endif /* RXDEBUG_PACKET */
1281             rxi_FreePackets(0, &call->iovq);
1282     }
1283
1284     if (call->mode == RX_MODE_SENDING) {
1285
1286         call->mode =
1287             (call->conn->type ==
1288              RX_CLIENT_CONNECTION ? RX_MODE_RECEIVING : RX_MODE_EOF);
1289
1290 #ifdef RX_KERNEL_TRACE
1291         {
1292             int glockOwner = ISAFS_GLOCK();
1293             if (!glockOwner)
1294                 AFS_GLOCK();
1295             afs_Trace3(afs_iclSetp, CM_TRACE_WASHERE, ICL_TYPE_STRING,
1296                        __FILE__, ICL_TYPE_INT32, __LINE__, ICL_TYPE_POINTER,
1297                        call);
1298             if (!glockOwner)
1299                 AFS_GUNLOCK();
1300         }
1301 #endif
1302
1303         MUTEX_ENTER(&call->lock);
1304         if (call->error)
1305             call->mode = RX_MODE_ERROR;
1306
1307         cp = call->currentPacket;
1308
1309         if (cp) {
1310             /* cp->length is only supposed to be the user's data */
1311             /* cp->length was already set to (then-current)
1312              * MaxUserDataSize or less. */
1313 #ifdef RX_TRACK_PACKETS
1314             cp->flags &= ~RX_PKTFLAG_CP;
1315 #endif
1316             cp->length -= call->nFree;
1317             call->currentPacket = (struct rx_packet *)0;
1318             call->nFree = 0;
1319         } else {
1320             cp = rxi_AllocSendPacket(call, 0);
1321             if (!cp) {
1322                 /* Mode can no longer be MODE_SENDING */
1323                 return;
1324             }
1325             cp->length = 0;
1326             cp->niovecs = 2;    /* header + space for rxkad stuff */
1327             call->nFree = 0;
1328         }
1329
1330         /* The 1 specifies that this is the last packet */
1331         hadd32(call->bytesSent, cp->length);
1332         rxi_PrepareSendPacket(call, cp, 1);
1333 #ifdef  AFS_GLOBAL_RXLOCK_KERNEL
1334         /* PrepareSendPacket drops the call lock */
1335         rxi_WaitforTQBusy(call);
1336 #endif /* AFS_GLOBAL_RXLOCK_KERNEL */
1337 #ifdef RX_TRACK_PACKETS
1338         cp->flags |= RX_PKTFLAG_TQ;
1339 #endif
1340         queue_Append(&call->tq, cp);
1341 #ifdef RXDEBUG_PACKET
1342         call->tqc++;
1343 #endif /* RXDEBUG_PACKET */
1344
1345         /* If the call is in recovery, let it exhaust its current retransmit
1346          * queue before forcing it to send new packets
1347          */
1348         if (!(call->flags & RX_CALL_FAST_RECOVER)) {
1349             rxi_Start(call, 0);
1350         }
1351         MUTEX_EXIT(&call->lock);
1352     }
1353 }
1354
1355 /* Flush any buffered data to the stream, switch to read mode
1356  * (clients) or to EOF mode (servers) */
1357 void
1358 rx_FlushWrite(struct rx_call *call)
1359 {
1360     SPLVAR;
1361     NETPRI;
1362     rxi_FlushWrite(call);
1363     USERPRI;
1364 }