rx: Hide the rx_packet.h
[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     int tcurlen;
286     int tnLeft;
287     char *tcurpos;
288     SPLVAR;
289
290     /* Free any packets from the last call to ReadvProc/WritevProc */
291     if (!queue_IsEmpty(&call->iovq)) {
292 #ifdef RXDEBUG_PACKET
293         call->iovqc -=
294 #endif /* RXDEBUG_PACKET */
295             rxi_FreePackets(0, &call->iovq);
296     }
297
298     /*
299      * Most common case, all of the data is in the current iovec.
300      * We are relying on nLeft being zero unless the call is in receive mode.
301      */
302     tcurlen = call->curlen;
303     tnLeft = call->nLeft;
304     if (!call->error && tcurlen > nbytes && tnLeft > nbytes) {
305         tcurpos = call->curpos;
306         memcpy(buf, tcurpos, nbytes);
307
308         call->curpos = tcurpos + nbytes;
309         call->curlen = tcurlen - nbytes;
310         call->nLeft = tnLeft - nbytes;
311
312         if (!call->nLeft && call->currentPacket != NULL) {
313             /* out of packet.  Get another one. */
314             rxi_FreePacket(call->currentPacket);
315             call->currentPacket = (struct rx_packet *)0;
316         }
317         return nbytes;
318     }
319
320     NETPRI;
321     bytes = rxi_ReadProc(call, buf, nbytes);
322     USERPRI;
323     return bytes;
324 }
325
326 /* Optimization for unmarshalling 32 bit integers */
327 int
328 rx_ReadProc32(struct rx_call *call, afs_int32 * value)
329 {
330     int bytes;
331     int tcurlen;
332     int tnLeft;
333     char *tcurpos;
334     SPLVAR;
335
336     /* Free any packets from the last call to ReadvProc/WritevProc */
337     if (!queue_IsEmpty(&call->iovq)) {
338 #ifdef RXDEBUG_PACKET
339         call->iovqc -=
340 #endif /* RXDEBUG_PACKET */
341             rxi_FreePackets(0, &call->iovq);
342     }
343
344     /*
345      * Most common case, all of the data is in the current iovec.
346      * We are relying on nLeft being zero unless the call is in receive mode.
347      */
348     tcurlen = call->curlen;
349     tnLeft = call->nLeft;
350     if (!call->error && tcurlen >= sizeof(afs_int32)
351         && tnLeft >= sizeof(afs_int32)) {
352         tcurpos = call->curpos;
353
354         memcpy((char *)value, tcurpos, sizeof(afs_int32));
355
356         call->curpos = tcurpos + sizeof(afs_int32);
357         call->curlen = (u_short)(tcurlen - sizeof(afs_int32));
358         call->nLeft = (u_short)(tnLeft - sizeof(afs_int32));
359         if (!call->nLeft && call->currentPacket != NULL) {
360             /* out of packet.  Get another one. */
361             rxi_FreePacket(call->currentPacket);
362             call->currentPacket = (struct rx_packet *)0;
363         }
364         return sizeof(afs_int32);
365     }
366
367     NETPRI;
368     bytes = rxi_ReadProc(call, (char *)value, sizeof(afs_int32));
369     USERPRI;
370
371     return bytes;
372 }
373
374 /* rxi_FillReadVec
375  *
376  * Uses packets in the receive queue to fill in as much of the
377  * current iovec as possible. Does not block if it runs out
378  * of packets to complete the iovec. Return true if an ack packet
379  * was sent, otherwise return false */
380 int
381 rxi_FillReadVec(struct rx_call *call, afs_uint32 serial)
382 {
383     int didConsume = 0;
384     int didHardAck = 0;
385     unsigned int t;
386     struct rx_packet *rp;
387     struct rx_packet *curp;
388     struct iovec *call_iov;
389     struct iovec *cur_iov = NULL;
390
391     curp = call->currentPacket;
392     if (curp) {
393         cur_iov = &curp->wirevec[call->curvec];
394     }
395     call_iov = &call->iov[call->iovNext];
396
397     while (!call->error && call->iovNBytes && call->iovNext < call->iovMax) {
398         if (call->nLeft == 0) {
399             /* Get next packet */
400             if (queue_IsNotEmpty(&call->rq)) {
401                 /* Check that next packet available is next in sequence */
402                 rp = queue_First(&call->rq, rx_packet);
403                 if (rp->header.seq == call->rnext) {
404                     afs_int32 error;
405                     struct rx_connection *conn = call->conn;
406                     queue_Remove(rp);
407 #ifdef RX_TRACK_PACKETS
408                     rp->flags &= ~RX_PKTFLAG_RQ;
409 #endif
410 #ifdef RXDEBUG_PACKET
411                     call->rqc--;
412 #endif /* RXDEBUG_PACKET */
413
414                     /* RXS_CheckPacket called to undo RXS_PreparePacket's
415                      * work.  It may reduce the length of the packet by up
416                      * to conn->maxTrailerSize, to reflect the length of the
417                      * data + the header. */
418                     if ((error =
419                          RXS_CheckPacket(conn->securityObject, call, rp))) {
420                         /* Used to merely shut down the call, but now we
421                          * shut down the whole connection since this may
422                          * indicate an attempt to hijack it */
423
424                         MUTEX_EXIT(&call->lock);
425                         rxi_ConnectionError(conn, error);
426                         MUTEX_ENTER(&conn->conn_data_lock);
427                         rp = rxi_SendConnectionAbort(conn, rp, 0, 0);
428                         MUTEX_EXIT(&conn->conn_data_lock);
429                         rxi_FreePacket(rp);
430                         MUTEX_ENTER(&call->lock);
431
432                         return 1;
433                     }
434                     call->rnext++;
435                     curp = call->currentPacket = rp;
436 #ifdef RX_TRACK_PACKETS
437                     call->currentPacket->flags |= RX_PKTFLAG_CP;
438 #endif
439                     call->curvec = 1;   /* 0th vec is always header */
440                     cur_iov = &curp->wirevec[1];
441                     /* begin at the beginning [ more or less ], continue
442                      * on until the end, then stop. */
443                     call->curpos =
444                         (char *)curp->wirevec[1].iov_base +
445                         call->conn->securityHeaderSize;
446                     call->curlen =
447                         curp->wirevec[1].iov_len -
448                         call->conn->securityHeaderSize;
449
450                     /* Notice that this code works correctly if the data
451                      * size is 0 (which it may be--no reply arguments from
452                      * server, for example).  This relies heavily on the
453                      * fact that the code below immediately frees the packet
454                      * (no yields, etc.).  If it didn't, this would be a
455                      * problem because a value of zero for call->nLeft
456                      * normally means that there is no read packet */
457                     call->nLeft = curp->length;
458                     hadd32(call->bytesRcvd, curp->length);
459
460                     /* Send a hard ack for every rxi_HardAckRate+1 packets
461                      * consumed. Otherwise schedule an event to send
462                      * the hard ack later on.
463                      */
464                     call->nHardAcks++;
465                     didConsume = 1;
466                     continue;
467                 }
468             }
469             break;
470         }
471
472         /* It's possible for call->nLeft to be smaller than any particular
473          * iov_len.  Usually, recvmsg doesn't change the iov_len, since it
474          * reflects the size of the buffer.  We have to keep track of the
475          * number of bytes read in the length field of the packet struct.  On
476          * the final portion of a received packet, it's almost certain that
477          * call->nLeft will be smaller than the final buffer. */
478         while (call->iovNBytes && call->iovNext < call->iovMax && curp) {
479
480             t = MIN((int)call->curlen, call->iovNBytes);
481             t = MIN(t, (int)call->nLeft);
482             call_iov->iov_base = call->curpos;
483             call_iov->iov_len = t;
484             call_iov++;
485             call->iovNext++;
486             call->iovNBytes -= t;
487             call->curpos += t;
488             call->curlen -= t;
489             call->nLeft -= t;
490
491             if (!call->nLeft) {
492                 /* out of packet.  Get another one. */
493 #ifdef RX_TRACK_PACKETS
494                 curp->flags &= ~RX_PKTFLAG_CP;
495                 curp->flags |= RX_PKTFLAG_IOVQ;
496 #endif
497                 queue_Append(&call->iovq, curp);
498 #ifdef RXDEBUG_PACKET
499                 call->iovqc++;
500 #endif /* RXDEBUG_PACKET */
501                 curp = call->currentPacket = (struct rx_packet *)0;
502             } else if (!call->curlen) {
503                 /* need to get another struct iov */
504                 if (++call->curvec >= curp->niovecs) {
505                     /* current packet is exhausted, get ready for another */
506                     /* don't worry about curvec and stuff, they get set somewhere else */
507 #ifdef RX_TRACK_PACKETS
508                     curp->flags &= ~RX_PKTFLAG_CP;
509                     curp->flags |= RX_PKTFLAG_IOVQ;
510 #endif
511                     queue_Append(&call->iovq, curp);
512 #ifdef RXDEBUG_PACKET
513                     call->iovqc++;
514 #endif /* RXDEBUG_PACKET */
515                     curp = call->currentPacket = (struct rx_packet *)0;
516                     call->nLeft = 0;
517                 } else {
518                     cur_iov++;
519                     call->curpos = (char *)cur_iov->iov_base;
520                     call->curlen = cur_iov->iov_len;
521                 }
522             }
523         }
524     }
525
526     /* If we consumed any packets then check whether we need to
527      * send a hard ack. */
528     if (didConsume && (!(call->flags & RX_CALL_RECEIVE_DONE))) {
529         if (call->nHardAcks > (u_short) rxi_HardAckRate) {
530             rxevent_Cancel(&call->delayedAckEvent, call,
531                            RX_CALL_REFCOUNT_DELAY);
532             rxi_SendAck(call, 0, serial, RX_ACK_DELAY, 0);
533             didHardAck = 1;
534         } else {
535             /* Delay to consolidate ack packets */
536             rxi_PostDelayedAckEvent(call, &rx_hardAckDelay);
537         }
538     }
539     return didHardAck;
540 }
541
542
543 /* rxi_ReadvProc -- internal version.
544  *
545  * Fills in an iovec with pointers to the packet buffers. All packets
546  * except the last packet (new current packet) are moved to the iovq
547  * while the application is processing the data.
548  *
549  * LOCKS USED -- called at netpri.
550  */
551 int
552 rxi_ReadvProc(struct rx_call *call, struct iovec *iov, int *nio, int maxio,
553               int nbytes)
554 {
555     int bytes;
556
557     /* Free any packets from the last call to ReadvProc/WritevProc */
558     if (queue_IsNotEmpty(&call->iovq)) {
559 #ifdef RXDEBUG_PACKET
560         call->iovqc -=
561 #endif /* RXDEBUG_PACKET */
562             rxi_FreePackets(0, &call->iovq);
563     }
564
565     if (call->mode == RX_MODE_SENDING) {
566         rxi_FlushWrite(call);
567     }
568
569     MUTEX_ENTER(&call->lock);
570     if (call->error)
571         goto error;
572
573     /* Get whatever data is currently available in the receive queue.
574      * If rxi_FillReadVec sends an ack packet then it is possible
575      * that we will receive more data while we drop the call lock
576      * to send the packet. Set the RX_CALL_IOVEC_WAIT flag
577      * here to avoid a race with the receive thread if we send
578      * hard acks in rxi_FillReadVec. */
579     call->flags |= RX_CALL_IOVEC_WAIT;
580     call->iovNBytes = nbytes;
581     call->iovMax = maxio;
582     call->iovNext = 0;
583     call->iov = iov;
584     rxi_FillReadVec(call, 0);
585
586     /* if we need more data then sleep until the receive thread has
587      * filled in the rest. */
588     if (!call->error && call->iovNBytes && call->iovNext < call->iovMax
589         && !(call->flags & RX_CALL_RECEIVE_DONE)) {
590         call->flags |= RX_CALL_READER_WAIT;
591         clock_NewTime();
592         call->startWait = clock_Sec();
593         while (call->flags & RX_CALL_READER_WAIT) {
594 #ifdef  RX_ENABLE_LOCKS
595             CV_WAIT(&call->cv_rq, &call->lock);
596 #else
597             osi_rxSleep(&call->rq);
598 #endif
599         }
600         call->startWait = 0;
601     }
602     call->flags &= ~RX_CALL_IOVEC_WAIT;
603
604     if (call->error)
605         goto error;
606
607     call->iov = NULL;
608     *nio = call->iovNext;
609     bytes = nbytes - call->iovNBytes;
610     MUTEX_EXIT(&call->lock);
611     return bytes;
612
613   error:
614     MUTEX_EXIT(&call->lock);
615     call->mode = RX_MODE_ERROR;
616     return 0;
617 }
618
619 int
620 rx_ReadvProc(struct rx_call *call, struct iovec *iov, int *nio, int maxio,
621              int nbytes)
622 {
623     int bytes;
624     SPLVAR;
625
626     NETPRI;
627     bytes = rxi_ReadvProc(call, iov, nio, maxio, nbytes);
628     USERPRI;
629     return bytes;
630 }
631
632 /* rxi_WriteProc -- internal version.
633  *
634  * LOCKS USED -- called at netpri
635  */
636
637 int
638 rxi_WriteProc(struct rx_call *call, char *buf,
639               int nbytes)
640 {
641     struct rx_connection *conn = call->conn;
642     struct rx_packet *cp = call->currentPacket;
643     unsigned int t;
644     int requestCount = nbytes;
645
646     /* Free any packets from the last call to ReadvProc/WritevProc */
647     if (queue_IsNotEmpty(&call->iovq)) {
648 #ifdef RXDEBUG_PACKET
649         call->iovqc -=
650 #endif /* RXDEBUG_PACKET */
651             rxi_FreePackets(0, &call->iovq);
652     }
653
654     if (call->mode != RX_MODE_SENDING) {
655         if ((conn->type == RX_SERVER_CONNECTION)
656             && (call->mode == RX_MODE_RECEIVING)) {
657             call->mode = RX_MODE_SENDING;
658             if (cp) {
659 #ifdef RX_TRACK_PACKETS
660                 cp->flags &= ~RX_PKTFLAG_CP;
661 #endif
662                 rxi_FreePacket(cp);
663                 cp = call->currentPacket = (struct rx_packet *)0;
664                 call->nLeft = 0;
665                 call->nFree = 0;
666             }
667         } else {
668             return 0;
669         }
670     }
671
672     /* Loop condition is checked at end, so that a write of 0 bytes
673      * will force a packet to be created--specially for the case where
674      * there are 0 bytes on the stream, but we must send a packet
675      * anyway. */
676     do {
677         if (call->nFree == 0) {
678             MUTEX_ENTER(&call->lock);
679             cp = call->currentPacket;
680             if (call->error)
681                 call->mode = RX_MODE_ERROR;
682             if (!call->error && cp) {
683                 /* Clear the current packet now so that if
684                  * we are forced to wait and drop the lock
685                  * the packet we are planning on using
686                  * cannot be freed.
687                  */
688 #ifdef RX_TRACK_PACKETS
689                 cp->flags &= ~RX_PKTFLAG_CP;
690 #endif
691                 call->currentPacket = (struct rx_packet *)0;
692                 clock_NewTime();        /* Bogus:  need new time package */
693                 /* The 0, below, specifies that it is not the last packet:
694                  * there will be others. PrepareSendPacket may
695                  * alter the packet length by up to
696                  * conn->securityMaxTrailerSize */
697                 hadd32(call->bytesSent, cp->length);
698                 rxi_PrepareSendPacket(call, cp, 0);
699 #ifdef  AFS_GLOBAL_RXLOCK_KERNEL
700                 /* PrepareSendPacket drops the call lock */
701                 rxi_WaitforTQBusy(call);
702 #endif /* AFS_GLOBAL_RXLOCK_KERNEL */
703 #ifdef RX_TRACK_PACKETS
704                 cp->flags |= RX_PKTFLAG_TQ;
705 #endif
706                 queue_Append(&call->tq, cp);
707 #ifdef RXDEBUG_PACKET
708                 call->tqc++;
709 #endif /* RXDEBUG_PACKET */
710                 cp = (struct rx_packet *)0;
711                 /* If the call is in recovery, let it exhaust its current
712                  * retransmit queue before forcing it to send new packets
713                  */
714                 if (!(call->flags & (RX_CALL_FAST_RECOVER))) {
715                     rxi_Start(call, 0);
716                 }
717             } else if (cp) {
718 #ifdef RX_TRACK_PACKETS
719                 cp->flags &= ~RX_PKTFLAG_CP;
720 #endif
721                 rxi_FreePacket(cp);
722                 cp = call->currentPacket = (struct rx_packet *)0;
723             }
724             /* Wait for transmit window to open up */
725             while (!call->error
726                    && call->tnext + 1 > call->tfirst + (2 * call->twind)) {
727                 clock_NewTime();
728                 call->startWait = clock_Sec();
729
730 #ifdef  RX_ENABLE_LOCKS
731                 CV_WAIT(&call->cv_twind, &call->lock);
732 #else
733                 call->flags |= RX_CALL_WAIT_WINDOW_ALLOC;
734                 osi_rxSleep(&call->twind);
735 #endif
736
737                 call->startWait = 0;
738 #ifdef RX_ENABLE_LOCKS
739                 if (call->error) {
740                     call->mode = RX_MODE_ERROR;
741                     MUTEX_EXIT(&call->lock);
742                     return 0;
743                 }
744 #endif /* RX_ENABLE_LOCKS */
745             }
746             if ((cp = rxi_AllocSendPacket(call, nbytes))) {
747 #ifdef RX_TRACK_PACKETS
748                 cp->flags |= RX_PKTFLAG_CP;
749 #endif
750                 call->currentPacket = cp;
751                 call->nFree = cp->length;
752                 call->curvec = 1;       /* 0th vec is always header */
753                 /* begin at the beginning [ more or less ], continue
754                  * on until the end, then stop. */
755                 call->curpos =
756                     (char *)cp->wirevec[1].iov_base +
757                     call->conn->securityHeaderSize;
758                 call->curlen =
759                     cp->wirevec[1].iov_len - call->conn->securityHeaderSize;
760             }
761             if (call->error) {
762                 call->mode = RX_MODE_ERROR;
763                 if (cp) {
764 #ifdef RX_TRACK_PACKETS
765                     cp->flags &= ~RX_PKTFLAG_CP;
766 #endif
767                     rxi_FreePacket(cp);
768                     call->currentPacket = NULL;
769                 }
770                 MUTEX_EXIT(&call->lock);
771                 return 0;
772             }
773             MUTEX_EXIT(&call->lock);
774         }
775
776         if (cp && (int)call->nFree < nbytes) {
777             /* Try to extend the current buffer */
778             int len, mud;
779             len = cp->length;
780             mud = rx_MaxUserDataSize(call);
781             if (mud > len) {
782                 int want;
783                 want = MIN(nbytes - (int)call->nFree, mud - len);
784                 rxi_AllocDataBuf(cp, want, RX_PACKET_CLASS_SEND_CBUF);
785                 if (cp->length > (unsigned)mud)
786                     cp->length = mud;
787                 call->nFree += (cp->length - len);
788             }
789         }
790
791         /* If the remaining bytes fit in the buffer, then store them
792          * and return.  Don't ship a buffer that's full immediately to
793          * the peer--we don't know if it's the last buffer yet */
794
795         if (!cp) {
796             call->nFree = 0;
797         }
798
799         while (nbytes && call->nFree) {
800
801             t = MIN((int)call->curlen, nbytes);
802             t = MIN((int)call->nFree, t);
803             memcpy(call->curpos, buf, t);
804             buf += t;
805             nbytes -= t;
806             call->curpos += t;
807             call->curlen -= (u_short)t;
808             call->nFree -= (u_short)t;
809
810             if (!call->curlen) {
811                 /* need to get another struct iov */
812                 if (++call->curvec >= cp->niovecs) {
813                     /* current packet is full, extend or send it */
814                     call->nFree = 0;
815                 } else {
816                     call->curpos = (char *)cp->wirevec[call->curvec].iov_base;
817                     call->curlen = cp->wirevec[call->curvec].iov_len;
818                 }
819             }
820         }                       /* while bytes to send and room to send them */
821
822         /* might be out of space now */
823         if (!nbytes) {
824             return requestCount;
825         } else;                 /* more data to send, so get another packet and keep going */
826     } while (nbytes);
827
828     return requestCount - nbytes;
829 }
830
831 int
832 rx_WriteProc(struct rx_call *call, char *buf, int nbytes)
833 {
834     int bytes;
835     int tcurlen;
836     int tnFree;
837     char *tcurpos;
838     SPLVAR;
839
840     /* Free any packets from the last call to ReadvProc/WritevProc */
841     if (queue_IsNotEmpty(&call->iovq)) {
842 #ifdef RXDEBUG_PACKET
843         call->iovqc -=
844 #endif /* RXDEBUG_PACKET */
845             rxi_FreePackets(0, &call->iovq);
846     }
847
848     /*
849      * Most common case: all of the data fits in the current iovec.
850      * We are relying on nFree being zero unless the call is in send mode.
851      */
852     tcurlen = (int)call->curlen;
853     tnFree = (int)call->nFree;
854     if (!call->error && tcurlen >= nbytes && tnFree >= nbytes) {
855         tcurpos = call->curpos;
856
857         memcpy(tcurpos, buf, nbytes);
858         call->curpos = tcurpos + nbytes;
859         call->curlen = (u_short)(tcurlen - nbytes);
860         call->nFree = (u_short)(tnFree - nbytes);
861         return nbytes;
862     }
863
864     NETPRI;
865     bytes = rxi_WriteProc(call, buf, nbytes);
866     USERPRI;
867     return bytes;
868 }
869
870 /* Optimization for marshalling 32 bit arguments */
871 int
872 rx_WriteProc32(struct rx_call *call, afs_int32 * value)
873 {
874     int bytes;
875     int tcurlen;
876     int tnFree;
877     char *tcurpos;
878     SPLVAR;
879
880     if (queue_IsNotEmpty(&call->iovq)) {
881 #ifdef RXDEBUG_PACKET
882         call->iovqc -=
883 #endif /* RXDEBUG_PACKET */
884             rxi_FreePackets(0, &call->iovq);
885     }
886
887     /*
888      * Most common case: all of the data fits in the current iovec.
889      * We are relying on nFree being zero unless the call is in send mode.
890      */
891     tcurlen = call->curlen;
892     tnFree = call->nFree;
893     if (!call->error && tcurlen >= sizeof(afs_int32)
894         && tnFree >= sizeof(afs_int32)) {
895         tcurpos = call->curpos;
896
897         if (!((size_t)tcurpos & (sizeof(afs_int32) - 1))) {
898             *((afs_int32 *) (tcurpos)) = *value;
899         } else {
900             memcpy(tcurpos, (char *)value, sizeof(afs_int32));
901         }
902         call->curpos = tcurpos + sizeof(afs_int32);
903         call->curlen = (u_short)(tcurlen - sizeof(afs_int32));
904         call->nFree = (u_short)(tnFree - sizeof(afs_int32));
905         return sizeof(afs_int32);
906     }
907
908     NETPRI;
909     bytes = rxi_WriteProc(call, (char *)value, sizeof(afs_int32));
910     USERPRI;
911     return bytes;
912 }
913
914 /* rxi_WritevAlloc -- internal version.
915  *
916  * Fill in an iovec to point to data in packet buffers. The application
917  * calls rxi_WritevProc when the buffers are full.
918  *
919  * LOCKS USED -- called at netpri.
920  */
921
922 static int
923 rxi_WritevAlloc(struct rx_call *call, struct iovec *iov, int *nio, int maxio,
924                 int nbytes)
925 {
926     struct rx_connection *conn = call->conn;
927     struct rx_packet *cp = call->currentPacket;
928     int requestCount;
929     int nextio;
930     /* Temporary values, real work is done in rxi_WritevProc */
931     int tnFree;
932     unsigned int tcurvec;
933     char *tcurpos;
934     int tcurlen;
935
936     requestCount = nbytes;
937     nextio = 0;
938
939     /* Free any packets from the last call to ReadvProc/WritevProc */
940     if (queue_IsNotEmpty(&call->iovq)) {
941 #ifdef RXDEBUG_PACKET
942         call->iovqc -=
943 #endif /* RXDEBUG_PACKET */
944             rxi_FreePackets(0, &call->iovq);
945     }
946
947     if (call->mode != RX_MODE_SENDING) {
948         if ((conn->type == RX_SERVER_CONNECTION)
949             && (call->mode == RX_MODE_RECEIVING)) {
950             call->mode = RX_MODE_SENDING;
951             if (cp) {
952 #ifdef RX_TRACK_PACKETS
953                 cp->flags &= ~RX_PKTFLAG_CP;
954 #endif
955                 rxi_FreePacket(cp);
956                 cp = call->currentPacket = (struct rx_packet *)0;
957                 call->nLeft = 0;
958                 call->nFree = 0;
959             }
960         } else {
961             return 0;
962         }
963     }
964
965     /* Set up the iovec to point to data in packet buffers. */
966     tnFree = call->nFree;
967     tcurvec = call->curvec;
968     tcurpos = call->curpos;
969     tcurlen = call->curlen;
970     do {
971         int t;
972
973         if (tnFree == 0) {
974             /* current packet is full, allocate a new one */
975             MUTEX_ENTER(&call->lock);
976             cp = rxi_AllocSendPacket(call, nbytes);
977             MUTEX_EXIT(&call->lock);
978             if (cp == NULL) {
979                 /* out of space, return what we have */
980                 *nio = nextio;
981                 return requestCount - nbytes;
982             }
983 #ifdef RX_TRACK_PACKETS
984             cp->flags |= RX_PKTFLAG_IOVQ;
985 #endif
986             queue_Append(&call->iovq, cp);
987 #ifdef RXDEBUG_PACKET
988             call->iovqc++;
989 #endif /* RXDEBUG_PACKET */
990             tnFree = cp->length;
991             tcurvec = 1;
992             tcurpos =
993                 (char *)cp->wirevec[1].iov_base +
994                 call->conn->securityHeaderSize;
995             tcurlen = cp->wirevec[1].iov_len - call->conn->securityHeaderSize;
996         }
997
998         if (tnFree < nbytes) {
999             /* try to extend the current packet */
1000             int len, mud;
1001             len = cp->length;
1002             mud = rx_MaxUserDataSize(call);
1003             if (mud > len) {
1004                 int want;
1005                 want = MIN(nbytes - tnFree, mud - len);
1006                 rxi_AllocDataBuf(cp, want, RX_PACKET_CLASS_SEND_CBUF);
1007                 if (cp->length > (unsigned)mud)
1008                     cp->length = mud;
1009                 tnFree += (cp->length - len);
1010                 if (cp == call->currentPacket) {
1011                     call->nFree += (cp->length - len);
1012                 }
1013             }
1014         }
1015
1016         /* fill in the next entry in the iovec */
1017         t = MIN(tcurlen, nbytes);
1018         t = MIN(tnFree, t);
1019         iov[nextio].iov_base = tcurpos;
1020         iov[nextio].iov_len = t;
1021         nbytes -= t;
1022         tcurpos += t;
1023         tcurlen -= t;
1024         tnFree -= t;
1025         nextio++;
1026
1027         if (!tcurlen) {
1028             /* need to get another struct iov */
1029             if (++tcurvec >= cp->niovecs) {
1030                 /* current packet is full, extend it or move on to next packet */
1031                 tnFree = 0;
1032             } else {
1033                 tcurpos = (char *)cp->wirevec[tcurvec].iov_base;
1034                 tcurlen = cp->wirevec[tcurvec].iov_len;
1035             }
1036         }
1037     } while (nbytes && nextio < maxio);
1038     *nio = nextio;
1039     return requestCount - nbytes;
1040 }
1041
1042 int
1043 rx_WritevAlloc(struct rx_call *call, struct iovec *iov, int *nio, int maxio,
1044                int nbytes)
1045 {
1046     int bytes;
1047     SPLVAR;
1048
1049     NETPRI;
1050     bytes = rxi_WritevAlloc(call, iov, nio, maxio, nbytes);
1051     USERPRI;
1052     return bytes;
1053 }
1054
1055 /* rxi_WritevProc -- internal version.
1056  *
1057  * Send buffers allocated in rxi_WritevAlloc.
1058  *
1059  * LOCKS USED -- called at netpri.
1060  */
1061 int
1062 rxi_WritevProc(struct rx_call *call, struct iovec *iov, int nio, int nbytes)
1063 {
1064     struct rx_packet *cp = NULL;
1065 #ifdef RX_TRACK_PACKETS
1066     struct rx_packet *p, *np;
1067 #endif
1068     int nextio;
1069     int requestCount;
1070     struct rx_queue tmpq;
1071 #ifdef RXDEBUG_PACKET
1072     u_short tmpqc;
1073 #endif
1074
1075     requestCount = nbytes;
1076     nextio = 0;
1077
1078     MUTEX_ENTER(&call->lock);
1079     if (call->error) {
1080         call->mode = RX_MODE_ERROR;
1081     } else if (call->mode != RX_MODE_SENDING) {
1082         call->error = RX_PROTOCOL_ERROR;
1083     }
1084 #ifdef AFS_GLOBAL_RXLOCK_KERNEL
1085     rxi_WaitforTQBusy(call);
1086 #endif /* AFS_GLOBAL_RXLOCK_KERNEL */
1087     cp = call->currentPacket;
1088
1089     if (call->error) {
1090         call->mode = RX_MODE_ERROR;
1091         MUTEX_EXIT(&call->lock);
1092         if (cp) {
1093 #ifdef RX_TRACK_PACKETS
1094             cp->flags &= ~RX_PKTFLAG_CP;
1095             cp->flags |= RX_PKTFLAG_IOVQ;
1096 #endif
1097             queue_Prepend(&call->iovq, cp);
1098 #ifdef RXDEBUG_PACKET
1099             call->iovqc++;
1100 #endif /* RXDEBUG_PACKET */
1101             call->currentPacket = (struct rx_packet *)0;
1102         }
1103 #ifdef RXDEBUG_PACKET
1104         call->iovqc -=
1105 #endif /* RXDEBUG_PACKET */
1106             rxi_FreePackets(0, &call->iovq);
1107         return 0;
1108     }
1109
1110     /* Loop through the I/O vector adjusting packet pointers.
1111      * Place full packets back onto the iovq once they are ready
1112      * to send. Set RX_PROTOCOL_ERROR if any problems are found in
1113      * the iovec. We put the loop condition at the end to ensure that
1114      * a zero length write will push a short packet. */
1115     nextio = 0;
1116     queue_Init(&tmpq);
1117 #ifdef RXDEBUG_PACKET
1118     tmpqc = 0;
1119 #endif /* RXDEBUG_PACKET */
1120     do {
1121         if (call->nFree == 0 && cp) {
1122             clock_NewTime();    /* Bogus:  need new time package */
1123             /* The 0, below, specifies that it is not the last packet:
1124              * there will be others. PrepareSendPacket may
1125              * alter the packet length by up to
1126              * conn->securityMaxTrailerSize */
1127             hadd32(call->bytesSent, cp->length);
1128             rxi_PrepareSendPacket(call, cp, 0);
1129 #ifdef  AFS_GLOBAL_RXLOCK_KERNEL
1130             /* PrepareSendPacket drops the call lock */
1131             rxi_WaitforTQBusy(call);
1132 #endif /* AFS_GLOBAL_RXLOCK_KERNEL */
1133             queue_Append(&tmpq, cp);
1134 #ifdef RXDEBUG_PACKET
1135             tmpqc++;
1136 #endif /* RXDEBUG_PACKET */
1137             cp = call->currentPacket = (struct rx_packet *)0;
1138
1139             /* The head of the iovq is now the current packet */
1140             if (nbytes) {
1141                 if (queue_IsEmpty(&call->iovq)) {
1142                     MUTEX_EXIT(&call->lock);
1143                     call->error = RX_PROTOCOL_ERROR;
1144 #ifdef RXDEBUG_PACKET
1145                     tmpqc -=
1146 #endif /* RXDEBUG_PACKET */
1147                         rxi_FreePackets(0, &tmpq);
1148                     return 0;
1149                 }
1150                 cp = queue_First(&call->iovq, rx_packet);
1151                 queue_Remove(cp);
1152 #ifdef RX_TRACK_PACKETS
1153                 cp->flags &= ~RX_PKTFLAG_IOVQ;
1154 #endif
1155 #ifdef RXDEBUG_PACKET
1156                 call->iovqc--;
1157 #endif /* RXDEBUG_PACKET */
1158 #ifdef RX_TRACK_PACKETS
1159                 cp->flags |= RX_PKTFLAG_CP;
1160 #endif
1161                 call->currentPacket = cp;
1162                 call->nFree = cp->length;
1163                 call->curvec = 1;
1164                 call->curpos =
1165                     (char *)cp->wirevec[1].iov_base +
1166                     call->conn->securityHeaderSize;
1167                 call->curlen =
1168                     cp->wirevec[1].iov_len - call->conn->securityHeaderSize;
1169             }
1170         }
1171
1172         if (nbytes) {
1173             /* The next iovec should point to the current position */
1174             if (iov[nextio].iov_base != call->curpos
1175                 || iov[nextio].iov_len > (int)call->curlen) {
1176                 call->error = RX_PROTOCOL_ERROR;
1177                 MUTEX_EXIT(&call->lock);
1178                 if (cp) {
1179 #ifdef RX_TRACK_PACKETS
1180                     cp->flags &= ~RX_PKTFLAG_CP;
1181 #endif
1182                     queue_Prepend(&tmpq, cp);
1183 #ifdef RXDEBUG_PACKET
1184                     tmpqc++;
1185 #endif /* RXDEBUG_PACKET */
1186                     cp = call->currentPacket = (struct rx_packet *)0;
1187                 }
1188 #ifdef RXDEBUG_PACKET
1189                 tmpqc -=
1190 #endif /* RXDEBUG_PACKET */
1191                     rxi_FreePackets(0, &tmpq);
1192                 return 0;
1193             }
1194             nbytes -= iov[nextio].iov_len;
1195             call->curpos += iov[nextio].iov_len;
1196             call->curlen -= iov[nextio].iov_len;
1197             call->nFree -= iov[nextio].iov_len;
1198             nextio++;
1199             if (call->curlen == 0) {
1200                 if (++call->curvec > cp->niovecs) {
1201                     call->nFree = 0;
1202                 } else {
1203                     call->curpos = (char *)cp->wirevec[call->curvec].iov_base;
1204                     call->curlen = cp->wirevec[call->curvec].iov_len;
1205                 }
1206             }
1207         }
1208     } while (nbytes && nextio < nio);
1209
1210     /* Move the packets from the temporary queue onto the transmit queue.
1211      * We may end up with more than call->twind packets on the queue. */
1212
1213 #ifdef RX_TRACK_PACKETS
1214     for (queue_Scan(&tmpq, p, np, rx_packet))
1215     {
1216         p->flags |= RX_PKTFLAG_TQ;
1217     }
1218 #endif
1219
1220     if (call->error)
1221         call->mode = RX_MODE_ERROR;
1222
1223     queue_SpliceAppend(&call->tq, &tmpq);
1224
1225     /* If the call is in recovery, let it exhaust its current retransmit
1226      * queue before forcing it to send new packets
1227      */
1228     if (!(call->flags & RX_CALL_FAST_RECOVER)) {
1229         rxi_Start(call, 0);
1230     }
1231
1232     /* Wait for the length of the transmit queue to fall below call->twind */
1233     while (!call->error && call->tnext + 1 > call->tfirst + (2 * call->twind)) {
1234         clock_NewTime();
1235         call->startWait = clock_Sec();
1236 #ifdef  RX_ENABLE_LOCKS
1237         CV_WAIT(&call->cv_twind, &call->lock);
1238 #else
1239         call->flags |= RX_CALL_WAIT_WINDOW_ALLOC;
1240         osi_rxSleep(&call->twind);
1241 #endif
1242         call->startWait = 0;
1243     }
1244
1245     /* cp is no longer valid since we may have given up the lock */
1246     cp = call->currentPacket;
1247
1248     if (call->error) {
1249         call->mode = RX_MODE_ERROR;
1250         call->currentPacket = NULL;
1251         MUTEX_EXIT(&call->lock);
1252         if (cp) {
1253 #ifdef RX_TRACK_PACKETS
1254             cp->flags &= ~RX_PKTFLAG_CP;
1255 #endif
1256             rxi_FreePacket(cp);
1257         }
1258         return 0;
1259     }
1260     MUTEX_EXIT(&call->lock);
1261
1262     return requestCount - nbytes;
1263 }
1264
1265 int
1266 rx_WritevProc(struct rx_call *call, struct iovec *iov, int nio, int nbytes)
1267 {
1268     int bytes;
1269     SPLVAR;
1270
1271     NETPRI;
1272     bytes = rxi_WritevProc(call, iov, nio, nbytes);
1273     USERPRI;
1274     return bytes;
1275 }
1276
1277 /* Flush any buffered data to the stream, switch to read mode
1278  * (clients) or to EOF mode (servers)
1279  *
1280  * LOCKS HELD: called at netpri.
1281  */
1282 void
1283 rxi_FlushWrite(struct rx_call *call)
1284 {
1285     struct rx_packet *cp = NULL;
1286
1287     /* Free any packets from the last call to ReadvProc/WritevProc */
1288     if (queue_IsNotEmpty(&call->iovq)) {
1289 #ifdef RXDEBUG_PACKET
1290         call->iovqc -=
1291 #endif /* RXDEBUG_PACKET */
1292             rxi_FreePackets(0, &call->iovq);
1293     }
1294
1295     if (call->mode == RX_MODE_SENDING) {
1296
1297         call->mode =
1298             (call->conn->type ==
1299              RX_CLIENT_CONNECTION ? RX_MODE_RECEIVING : RX_MODE_EOF);
1300
1301 #ifdef RX_KERNEL_TRACE
1302         {
1303             int glockOwner = ISAFS_GLOCK();
1304             if (!glockOwner)
1305                 AFS_GLOCK();
1306             afs_Trace3(afs_iclSetp, CM_TRACE_WASHERE, ICL_TYPE_STRING,
1307                        __FILE__, ICL_TYPE_INT32, __LINE__, ICL_TYPE_POINTER,
1308                        call);
1309             if (!glockOwner)
1310                 AFS_GUNLOCK();
1311         }
1312 #endif
1313
1314         MUTEX_ENTER(&call->lock);
1315         if (call->error)
1316             call->mode = RX_MODE_ERROR;
1317
1318         cp = call->currentPacket;
1319
1320         if (cp) {
1321             /* cp->length is only supposed to be the user's data */
1322             /* cp->length was already set to (then-current)
1323              * MaxUserDataSize or less. */
1324 #ifdef RX_TRACK_PACKETS
1325             cp->flags &= ~RX_PKTFLAG_CP;
1326 #endif
1327             cp->length -= call->nFree;
1328             call->currentPacket = (struct rx_packet *)0;
1329             call->nFree = 0;
1330         } else {
1331             cp = rxi_AllocSendPacket(call, 0);
1332             if (!cp) {
1333                 /* Mode can no longer be MODE_SENDING */
1334                 return;
1335             }
1336             cp->length = 0;
1337             cp->niovecs = 2;    /* header + space for rxkad stuff */
1338             call->nFree = 0;
1339         }
1340
1341         /* The 1 specifies that this is the last packet */
1342         hadd32(call->bytesSent, cp->length);
1343         rxi_PrepareSendPacket(call, cp, 1);
1344 #ifdef  AFS_GLOBAL_RXLOCK_KERNEL
1345         /* PrepareSendPacket drops the call lock */
1346         rxi_WaitforTQBusy(call);
1347 #endif /* AFS_GLOBAL_RXLOCK_KERNEL */
1348 #ifdef RX_TRACK_PACKETS
1349         cp->flags |= RX_PKTFLAG_TQ;
1350 #endif
1351         queue_Append(&call->tq, cp);
1352 #ifdef RXDEBUG_PACKET
1353         call->tqc++;
1354 #endif /* RXDEBUG_PACKET */
1355
1356         /* If the call is in recovery, let it exhaust its current retransmit
1357          * queue before forcing it to send new packets
1358          */
1359         if (!(call->flags & RX_CALL_FAST_RECOVER)) {
1360             rxi_Start(call, 0);
1361         }
1362         MUTEX_EXIT(&call->lock);
1363     }
1364 }
1365
1366 /* Flush any buffered data to the stream, switch to read mode
1367  * (clients) or to EOF mode (servers) */
1368 void
1369 rx_FlushWrite(struct rx_call *call)
1370 {
1371     SPLVAR;
1372     NETPRI;
1373     rxi_FlushWrite(call);
1374     USERPRI;
1375 }