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