2 * Copyright 2000, International Business Machines Corporation and others.
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
10 #include <afsconfig.h>
12 #include "afs/param.h"
14 #include <afs/param.h>
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"
33 #ifndef AFS_LINUX20_ENV
36 #if defined(AFS_SGI_ENV) || defined(AFS_HPUX110_ENV)
37 #include "afs/sysincludes.h"
39 #if defined(AFS_OBSD_ENV)
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 */
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"
55 #include <sys/sysmacros.h>
57 #include "rx/rx_packet.h"
58 #endif /* defined(UKERNEL) */
59 #include "rx/rx_globals.h"
61 #include "sys/types.h"
64 #if defined(AFS_NT40_ENV) || defined(AFS_DJGPP_ENV)
68 #define EWOULDBLOCK WSAEWOULDBLOCK
71 #include <sys/socket.h>
72 #include <netinet/in.h>
73 #endif /* AFS_NT40_ENV */
74 #include "rx_xmit_nt.h"
77 #include <sys/socket.h>
78 #include <netinet/in.h>
84 #include <sys/sysmacros.h>
86 #include "rx_packet.h"
87 #include "rx_globals.h"
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;
108 extern char cml_version_number[];
109 extern int (*rx_almostSent) ();
111 static void rxi_SendDebugPacket(struct rx_packet *apacket, osi_socket asocket,
112 afs_int32 ahost, short aport,
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.
124 * all packet buffers (iov_base) are integral multiples of
126 * offset is an integral multiple of the word size.
129 rx_SlowGetInt32(struct rx_packet *packet, size_t offset)
133 for (l = 0, i = 1; i < packet->niovecs; i++) {
134 if (l + packet->wirevec[i].iov_len > offset) {
136 *((afs_int32 *) ((char *)(packet->wirevec[i].iov_base) +
139 l += packet->wirevec[i].iov_len;
146 * all packet buffers (iov_base) are integral multiples of the word size.
147 * offset is an integral multiple of the word size.
150 rx_SlowPutInt32(struct rx_packet * packet, size_t offset, afs_int32 data)
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;
160 l += packet->wirevec[i].iov_len;
167 * all packet buffers (iov_base) are integral multiples of the
169 * offset is an integral multiple of the word size.
171 * all buffers are contiguously arrayed in the iovec from 0..niovecs-1
174 rx_SlowReadPacket(struct rx_packet * packet, unsigned int offset, int resid,
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) {
182 l += packet->wirevec[i].iov_len;
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.
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);
196 l += packet->wirevec[i].iov_len;
201 return (resid ? (r - resid) : r);
206 * all packet buffers (iov_base) are integral multiples of the
208 * offset is an integral multiple of the word size.
211 rx_SlowWritePacket(struct rx_packet * packet, int offset, int resid, char *in)
216 for (l = 0, i = 1; i < packet->niovecs; i++) {
217 if (l + packet->wirevec[i].iov_len > offset) {
220 l += packet->wirevec[i].iov_len;
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.
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 */
234 b = (char *)(packet->wirevec[i].iov_base) + (offset - l);
235 j = MIN(resid, packet->wirevec[i].iov_len - (offset - l));
239 l += packet->wirevec[i].iov_len;
244 return (resid ? (r - resid) : r);
247 #ifdef RX_ENABLE_TSFPQ
248 static struct rx_packet *
252 register struct rx_ts_info_t * rx_ts_info;
255 RX_TS_INFO_GET(rx_ts_info);
257 if (queue_IsEmpty(&rx_ts_info->_FPQ)) {
259 MUTEX_ENTER(&rx_freePktQ_lock);
261 if (queue_IsEmpty(&rx_freePacketQueue)) {
262 rxi_MorePacketsNoLock(rx_initSendWindow);
265 RX_TS_FPQ_GTOL(rx_ts_info);
267 MUTEX_EXIT(&rx_freePktQ_lock);
271 RX_TS_FPQ_CHECKOUT(rx_ts_info, c);
275 #else /* RX_ENABLE_TSFPQ */
276 static struct rx_packet *
284 MUTEX_ENTER(&rx_freePktQ_lock);
287 if (rxi_OverQuota(class)) {
289 rxi_NeedMorePackets = TRUE;
290 MUTEX_ENTER(&rx_stats_mutex);
292 case RX_PACKET_CLASS_RECEIVE:
293 rx_stats.receivePktAllocFailures++;
295 case RX_PACKET_CLASS_SEND:
296 rx_stats.sendPktAllocFailures++;
298 case RX_PACKET_CLASS_SPECIAL:
299 rx_stats.specialPktAllocFailures++;
301 case RX_PACKET_CLASS_RECV_CBUF:
302 rx_stats.receiveCbufPktAllocFailures++;
304 case RX_PACKET_CLASS_SEND_CBUF:
305 rx_stats.sendCbufPktAllocFailures++;
308 MUTEX_EXIT(&rx_stats_mutex);
312 if (queue_IsEmpty(&rx_freePacketQueue)) {
314 rxi_NeedMorePackets = TRUE;
318 if (queue_IsEmpty(&rx_freePacketQueue)) {
319 rxi_MorePacketsNoLock(rx_initSendWindow);
324 c = queue_First(&rx_freePacketQueue, rx_packet);
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 */
334 MUTEX_EXIT(&rx_freePktQ_lock);
339 #endif /* RX_ENABLE_TSFPQ */
342 * Free a packet currently used as a continuation buffer
344 #ifdef RX_ENABLE_TSFPQ
346 rxi_freeCBuf(struct rx_packet *c)
348 register struct rx_ts_info_t * rx_ts_info;
352 RX_TS_INFO_GET(rx_ts_info);
353 RX_TS_FPQ_CHECKIN(rx_ts_info,c);
355 if (rx_ts_info->_FPQ.len > rx_TSFPQLocalMax) {
357 MUTEX_ENTER(&rx_freePktQ_lock);
359 RX_TS_FPQ_LTOG(rx_ts_info);
361 /* Wakeup anyone waiting for packets */
364 MUTEX_EXIT(&rx_freePktQ_lock);
368 #else /* RX_ENABLE_TSFPQ */
370 rxi_freeCBuf(struct rx_packet *c)
375 MUTEX_ENTER(&rx_freePktQ_lock);
377 rxi_FreePacketNoLock(c);
378 /* Wakeup anyone waiting for packets */
381 MUTEX_EXIT(&rx_freePktQ_lock);
384 #endif /* RX_ENABLE_TSFPQ */
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).
393 rxi_RoundUpPacket(struct rx_packet *p, unsigned int nb)
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;
403 if (p->wirevec[i].iov_len <= RX_CBUFFERSIZE - nb) {
404 p->wirevec[i].iov_len += nb;
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 */
420 rxi_AllocDataBuf(struct rx_packet *p, int nb, int class)
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;
439 /* Add more packet buffers */
440 #ifdef RX_ENABLE_TSFPQ
442 rxi_MorePackets(int apackets)
444 struct rx_packet *p, *e;
445 register struct rx_ts_info_t * rx_ts_info;
449 getme = apackets * sizeof(struct rx_packet);
450 p = rx_mallocedP = (struct rx_packet *)osi_Alloc(getme);
452 PIN(p, getme); /* XXXXX */
453 memset((char *)p, 0, getme);
454 RX_TS_INFO_GET(rx_ts_info);
456 for (e = p + apackets; p < e; p++) {
457 RX_PACKET_IOV_INIT(p);
460 RX_TS_FPQ_CHECKIN(rx_ts_info,p);
462 rx_ts_info->_FPQ.delta += apackets;
464 if (rx_ts_info->_FPQ.len > rx_TSFPQLocalMax) {
466 MUTEX_ENTER(&rx_freePktQ_lock);
468 RX_TS_FPQ_LTOG(rx_ts_info);
469 rxi_NeedMorePackets = FALSE;
472 MUTEX_EXIT(&rx_freePktQ_lock);
476 #else /* RX_ENABLE_TSFPQ */
478 rxi_MorePackets(int apackets)
480 struct rx_packet *p, *e;
484 getme = apackets * sizeof(struct rx_packet);
485 p = rx_mallocedP = (struct rx_packet *)osi_Alloc(getme);
487 PIN(p, getme); /* XXXXX */
488 memset((char *)p, 0, getme);
490 MUTEX_ENTER(&rx_freePktQ_lock);
492 for (e = p + apackets; p < e; p++) {
493 RX_PACKET_IOV_INIT(p);
494 p->flags |= RX_PKTFLAG_FREE;
497 queue_Append(&rx_freePacketQueue, p);
499 rx_nFreePackets += apackets;
500 rxi_NeedMorePackets = FALSE;
503 MUTEX_EXIT(&rx_freePktQ_lock);
506 #endif /* RX_ENABLE_TSFPQ */
508 #ifdef RX_ENABLE_TSFPQ
510 rxi_MorePacketsTSFPQ(int apackets, int flush_global, int num_keep_local)
512 struct rx_packet *p, *e;
513 register struct rx_ts_info_t * rx_ts_info;
517 getme = apackets * sizeof(struct rx_packet);
518 p = rx_mallocedP = (struct rx_packet *)osi_Alloc(getme);
520 PIN(p, getme); /* XXXXX */
521 memset((char *)p, 0, getme);
522 RX_TS_INFO_GET(rx_ts_info);
524 for (e = p + apackets; p < e; p++) {
525 RX_PACKET_IOV_INIT(p);
528 RX_TS_FPQ_CHECKIN(rx_ts_info,p);
530 rx_ts_info->_FPQ.delta += apackets;
533 (num_keep_local < apackets)) {
535 MUTEX_ENTER(&rx_freePktQ_lock);
537 RX_TS_FPQ_LTOG2(rx_ts_info, (apackets - num_keep_local));
538 rxi_NeedMorePackets = FALSE;
541 MUTEX_EXIT(&rx_freePktQ_lock);
545 #endif /* RX_ENABLE_TSFPQ */
548 /* Add more packet buffers */
550 rxi_MorePacketsNoLock(int apackets)
552 struct rx_packet *p, *e;
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);
562 memset((char *)p, 0, getme);
564 for (e = p + apackets; p < e; p++) {
565 RX_PACKET_IOV_INIT(p);
566 p->flags |= RX_PKTFLAG_FREE;
569 queue_Append(&rx_freePacketQueue, p);
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;
583 rxi_FreeAllPackets(void)
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));
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. */
596 rx_CheckPackets(void)
598 if (rxi_NeedMorePackets) {
599 rxi_MorePackets(rx_initSendWindow);
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
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.
616 /* Actually free the packet p. */
617 #ifdef RX_ENABLE_TSFPQ
619 rxi_FreePacketNoLock(struct rx_packet *p)
621 register struct rx_ts_info_t * rx_ts_info;
622 dpf(("Free %lx\n", (unsigned long)p));
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);
630 #else /* RX_ENABLE_TSFPQ */
632 rxi_FreePacketNoLock(struct rx_packet *p)
634 dpf(("Free %lx\n", (unsigned long)p));
638 queue_Append(&rx_freePacketQueue, p);
640 #endif /* RX_ENABLE_TSFPQ */
642 #ifdef RX_ENABLE_TSFPQ
644 rxi_FreePacketTSFPQ(struct rx_packet *p, int flush_global)
646 register struct rx_ts_info_t * rx_ts_info;
647 dpf(("Free %lx\n", (unsigned long)p));
649 RX_TS_INFO_GET(rx_ts_info);
650 RX_TS_FPQ_CHECKIN(rx_ts_info,p);
652 if (flush_global && (rx_ts_info->_FPQ.len > rx_TSFPQLocalMax)) {
654 MUTEX_ENTER(&rx_freePktQ_lock);
656 RX_TS_FPQ_LTOG(rx_ts_info);
658 /* Wakeup anyone waiting for packets */
661 MUTEX_EXIT(&rx_freePktQ_lock);
665 #endif /* RX_ENABLE_TSFPQ */
668 rxi_FreeDataBufsNoLock(struct rx_packet *p, int first)
670 struct iovec *iov, *end;
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++) {
680 osi_Panic("FreeDataBufs 3: vecs 2-niovecs must not be NULL");
681 rxi_FreePacketNoLock(RX_CBUF_TO_PACKET(iov->iov_base, p));
689 #ifdef RX_ENABLE_TSFPQ
691 rxi_FreeDataBufsTSFPQ(struct rx_packet *p, int first, int flush_global)
693 struct iovec *iov, *end;
694 register struct rx_ts_info_t * rx_ts_info;
696 RX_TS_INFO_GET(rx_ts_info);
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++) {
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));
712 if (flush_global && (rx_ts_info->_FPQ.len > rx_TSFPQLocalMax)) {
714 MUTEX_ENTER(&rx_freePktQ_lock);
716 RX_TS_FPQ_LTOG(rx_ts_info);
718 /* Wakeup anyone waiting for packets */
721 MUTEX_EXIT(&rx_freePktQ_lock);
726 #endif /* RX_ENABLE_TSFPQ */
728 int rxi_nBadIovecs = 0;
730 /* rxi_RestoreDataBufs
732 * Restore the correct sizes to the iovecs. Called when reusing a packet
733 * for reading off the wire.
736 rxi_RestoreDataBufs(struct rx_packet *p)
739 struct iovec *iov = &p->wirevec[2];
741 RX_PACKET_IOV_INIT(p);
743 for (i = 2, iov = &p->wirevec[2]; i < p->niovecs; i++, iov++) {
744 if (!iov->iov_base) {
749 iov->iov_len = RX_CBUFFERSIZE;
753 #ifdef RX_ENABLE_TSFPQ
755 rxi_TrimDataBufs(struct rx_packet *p, int first)
758 struct iovec *iov, *end;
759 register struct rx_ts_info_t * rx_ts_info;
763 osi_Panic("TrimDataBufs 1: first must be 1");
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++) {
771 osi_Panic("TrimDataBufs 3: vecs 1-niovecs must not be NULL");
772 length -= iov->iov_len;
775 /* iov now points to the first empty data buffer. */
779 RX_TS_INFO_GET(rx_ts_info);
780 for (; iov < end; iov++) {
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));
786 if (rx_ts_info->_FPQ.len > rx_TSFPQLocalMax) {
788 MUTEX_ENTER(&rx_freePktQ_lock);
790 RX_TS_FPQ_LTOG(rx_ts_info);
793 MUTEX_EXIT(&rx_freePktQ_lock);
799 #else /* RX_ENABLE_TSFPQ */
801 rxi_TrimDataBufs(struct rx_packet *p, int first)
804 struct iovec *iov, *end;
808 osi_Panic("TrimDataBufs 1: first must be 1");
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++) {
816 osi_Panic("TrimDataBufs 3: vecs 1-niovecs must not be NULL");
817 length -= iov->iov_len;
820 /* iov now points to the first empty data buffer. */
825 MUTEX_ENTER(&rx_freePktQ_lock);
827 for (; iov < end; iov++) {
829 osi_Panic("TrimDataBufs 4: vecs 2-niovecs must not be NULL");
830 rxi_FreePacketNoLock(RX_CBUF_TO_PACKET(iov->iov_base, p));
835 MUTEX_EXIT(&rx_freePktQ_lock);
840 #endif /* RX_ENABLE_TSFPQ */
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
846 rxi_FreePacket(struct rx_packet *p)
848 rxi_FreeDataBufsTSFPQ(p, 1, 0);
849 rxi_FreePacketTSFPQ(p, RX_TS_FPQ_FLUSH_GLOBAL);
851 #else /* RX_ENABLE_TSFPQ */
853 rxi_FreePacket(struct rx_packet *p)
858 MUTEX_ENTER(&rx_freePktQ_lock);
860 rxi_FreeDataBufsNoLock(p, 1);
861 rxi_FreePacketNoLock(p);
862 /* Wakeup anyone waiting for packets */
865 MUTEX_EXIT(&rx_freePktQ_lock);
868 #endif /* RX_ENABLE_TSFPQ */
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
876 rxi_AllocPacketNoLock(int class)
878 register struct rx_packet *p;
879 register struct rx_ts_info_t * rx_ts_info;
881 RX_TS_INFO_GET(rx_ts_info);
884 if (rxi_OverQuota(class)) {
885 rxi_NeedMorePackets = TRUE;
886 MUTEX_ENTER(&rx_stats_mutex);
888 case RX_PACKET_CLASS_RECEIVE:
889 rx_stats.receivePktAllocFailures++;
891 case RX_PACKET_CLASS_SEND:
892 rx_stats.sendPktAllocFailures++;
894 case RX_PACKET_CLASS_SPECIAL:
895 rx_stats.specialPktAllocFailures++;
897 case RX_PACKET_CLASS_RECV_CBUF:
898 rx_stats.receiveCbufPktAllocFailures++;
900 case RX_PACKET_CLASS_SEND_CBUF:
901 rx_stats.sendCbufPktAllocFailures++;
904 MUTEX_EXIT(&rx_stats_mutex);
905 return (struct rx_packet *)0;
909 MUTEX_ENTER(&rx_stats_mutex);
910 rx_stats.packetRequests++;
911 MUTEX_EXIT(&rx_stats_mutex);
913 if (queue_IsEmpty(&rx_ts_info->_FPQ)) {
916 if (queue_IsEmpty(&rx_freePacketQueue))
917 osi_Panic("rxi_AllocPacket error");
919 if (queue_IsEmpty(&rx_freePacketQueue))
920 rxi_MorePacketsNoLock(rx_initSendWindow);
924 RX_TS_FPQ_GTOL(rx_ts_info);
927 RX_TS_FPQ_CHECKOUT(rx_ts_info,p);
929 dpf(("Alloc %lx, class %d\n", (unsigned long)p, class));
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
936 RX_PACKET_IOV_FULLINIT(p);
939 #else /* RX_ENABLE_TSFPQ */
941 rxi_AllocPacketNoLock(int class)
943 register struct rx_packet *p;
946 if (rxi_OverQuota(class)) {
947 rxi_NeedMorePackets = TRUE;
948 MUTEX_ENTER(&rx_stats_mutex);
950 case RX_PACKET_CLASS_RECEIVE:
951 rx_stats.receivePktAllocFailures++;
953 case RX_PACKET_CLASS_SEND:
954 rx_stats.sendPktAllocFailures++;
956 case RX_PACKET_CLASS_SPECIAL:
957 rx_stats.specialPktAllocFailures++;
959 case RX_PACKET_CLASS_RECV_CBUF:
960 rx_stats.receiveCbufPktAllocFailures++;
962 case RX_PACKET_CLASS_SEND_CBUF:
963 rx_stats.sendCbufPktAllocFailures++;
966 MUTEX_EXIT(&rx_stats_mutex);
967 return (struct rx_packet *)0;
971 MUTEX_ENTER(&rx_stats_mutex);
972 rx_stats.packetRequests++;
973 MUTEX_EXIT(&rx_stats_mutex);
976 if (queue_IsEmpty(&rx_freePacketQueue))
977 osi_Panic("rxi_AllocPacket error");
979 if (queue_IsEmpty(&rx_freePacketQueue))
980 rxi_MorePacketsNoLock(rx_initSendWindow);
984 p = queue_First(&rx_freePacketQueue, rx_packet);
988 dpf(("Alloc %lx, class %d\n", (unsigned long)p, class));
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
995 RX_PACKET_IOV_FULLINIT(p);
998 #endif /* RX_ENABLE_TSFPQ */
1000 #ifdef RX_ENABLE_TSFPQ
1002 rxi_AllocPacketTSFPQ(int class, int pull_global)
1004 register struct rx_packet *p;
1005 register struct rx_ts_info_t * rx_ts_info;
1007 RX_TS_INFO_GET(rx_ts_info);
1009 MUTEX_ENTER(&rx_stats_mutex);
1010 rx_stats.packetRequests++;
1011 MUTEX_EXIT(&rx_stats_mutex);
1013 if (pull_global && queue_IsEmpty(&rx_ts_info->_FPQ)) {
1014 MUTEX_ENTER(&rx_freePktQ_lock);
1016 if (queue_IsEmpty(&rx_freePacketQueue))
1017 rxi_MorePacketsNoLock(rx_initSendWindow);
1019 RX_TS_FPQ_GTOL(rx_ts_info);
1021 MUTEX_EXIT(&rx_freePktQ_lock);
1022 } else if (queue_IsEmpty(&rx_ts_info->_FPQ)) {
1026 RX_TS_FPQ_CHECKOUT(rx_ts_info,p);
1028 dpf(("Alloc %lx, class %d\n", (unsigned long)p, class));
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
1034 RX_PACKET_IOV_FULLINIT(p);
1037 #endif /* RX_ENABLE_TSFPQ */
1039 #ifdef RX_ENABLE_TSFPQ
1041 rxi_AllocPacket(int class)
1043 register struct rx_packet *p;
1045 p = rxi_AllocPacketTSFPQ(class, RX_TS_FPQ_PULL_GLOBAL);
1048 #else /* RX_ENABLE_TSFPQ */
1050 rxi_AllocPacket(int class)
1052 register struct rx_packet *p;
1054 MUTEX_ENTER(&rx_freePktQ_lock);
1055 p = rxi_AllocPacketNoLock(class);
1056 MUTEX_EXIT(&rx_freePktQ_lock);
1059 #endif /* RX_ENABLE_TSFPQ */
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.
1067 rxi_AllocSendPacket(register struct rx_call *call, int want)
1069 register struct rx_packet *p = (struct rx_packet *)0;
1071 register unsigned delta;
1074 mud = call->MTU - RX_HEADER_SIZE;
1076 rx_GetSecurityHeaderSize(rx_ConnectionOf(call)) +
1077 rx_GetSecurityMaxTrailerSize(rx_ConnectionOf(call));
1079 #ifdef RX_ENABLE_TSFPQ
1080 if ((p = rxi_AllocPacketTSFPQ(RX_PACKET_CLASS_SEND, 0))) {
1082 want = MIN(want, mud);
1084 if ((unsigned)want > p->length)
1085 (void)rxi_AllocDataBuf(p, (want - p->length),
1086 RX_PACKET_CLASS_SEND_CBUF);
1088 if ((unsigned)p->length > mud)
1091 if (delta >= p->length) {
1099 #endif /* RX_ENABLE_TSFPQ */
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);
1108 want = MIN(want, mud);
1110 if ((unsigned)want > p->length)
1111 (void)rxi_AllocDataBuf(p, (want - p->length),
1112 RX_PACKET_CLASS_SEND_CBUF);
1114 if ((unsigned)p->length > mud)
1117 if (delta >= p->length) {
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
1131 call->flags |= RX_CALL_WAIT_PACKETS;
1132 CALL_HOLD(call, RX_CALL_REFCOUNT_PACKET);
1133 MUTEX_EXIT(&call->lock);
1134 rx_waitingForPackets = 1;
1136 #ifdef RX_ENABLE_LOCKS
1137 CV_WAIT(&rx_waitingForPackets_cv, &rx_freePktQ_lock);
1139 osi_rxSleep(&rx_waitingForPackets);
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;
1153 /* count the number of used FDs */
1155 CountFDs(register int amax)
1158 register int i, code;
1162 for (i = 0; i < amax; i++) {
1163 code = fstat(i, &tstat);
1172 #define CountFDs(amax) amax
1176 #if !defined(KERNEL) || defined(UKERNEL)
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. */
1184 rxi_ReadPacket(int socket, register struct rx_packet *p, afs_uint32 * host,
1187 struct sockaddr_in from;
1190 register afs_int32 tlen, savelen;
1192 rx_computelen(p, tlen);
1193 rx_SetDataSize(p, tlen); /* this is the size of the user data area */
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. */
1200 tlen = rxi_AllocDataBuf(p, tlen, RX_PACKET_CLASS_SEND_CBUF);
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
1213 savelen = p->wirevec[p->niovecs - 1].iov_len;
1214 p->wirevec[p->niovecs - 1].iov_len += RX_EXTRABUFFERSIZE;
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);
1223 /* restore the vec to its correct state */
1224 p->wirevec[p->niovecs - 1].iov_len = savelen;
1226 p->length = (nbytes - RX_HEADER_SIZE);
1227 if ((nbytes > tlen) || (p->length & 0x8000)) { /* Bogus packet */
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);
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));
1244 /* Extract packet header. */
1245 rxi_DecodePacketHeader(p);
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);
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.
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.
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
1270 if (peer && (peer->refCount > 0)) {
1271 MUTEX_ENTER(&peer->peer_lock);
1272 hadd32(peer->bytesReceived, p->length);
1273 MUTEX_EXIT(&peer->peer_lock);
1277 /* Free any empty packet buffers at the end of this packet */
1278 rxi_TrimDataBufs(p, 1);
1284 #endif /* !KERNEL || UKERNEL */
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. */
1295 rxi_SplitJumboPacket(register struct rx_packet *p, afs_int32 host, short port,
1298 struct rx_packet *np;
1299 struct rx_jumboHeader *jp;
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;
1311 if ((int)p->length < length) {
1312 dpf(("rxi_SplitJumboPacket: bogus length %d\n", p->length));
1315 niov = p->niovecs - 2;
1317 dpf(("rxi_SplitJumboPacket: bogus niovecs %d\n", p->niovecs));
1320 iov = &p->wirevec[2];
1321 np = RX_CBUF_TO_PACKET(iov->iov_base, p);
1323 /* Get a pointer to the abbreviated packet header */
1324 jp = (struct rx_jumboHeader *)
1325 ((char *)(p->wirevec[1].iov_base) + RX_JUMBOBUFFERSIZE);
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;
1336 np->length = p->length - length;
1337 p->length = RX_JUMBOBUFFERSIZE;
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);
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;
1356 /* Send a udp datagram */
1358 osi_NetSend(osi_socket socket, void *addr, struct iovec *dvec, int nvecs,
1359 int length, int istack)
1363 memset(&msg, 0, sizeof(msg));
1365 msg.msg_iovlen = nvecs;
1366 msg.msg_name = addr;
1367 msg.msg_namelen = sizeof(struct sockaddr_in);
1369 rxi_Sendmsg(socket, &msg, 0);
1373 #elif !defined(UKERNEL)
1375 * message receipt is done in rxk_input or rx_put.
1378 #if defined(AFS_SUN5_ENV) || defined(AFS_HPUX110_ENV)
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.
1387 cpytoc(mblk_t * mp, register int off, register int len, register char *cp)
1391 for (; mp && len > 0; mp = mp->b_cont) {
1392 if (mp->b_datap->db_type != M_DATA) {
1395 n = MIN(len, (mp->b_wptr - mp->b_rptr));
1396 memcpy(cp, (char *)mp->b_rptr, n);
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
1409 cpytoiovec(mblk_t * mp, int off, int len, register struct iovec *iovs,
1412 register int m, n, o, t, i;
1414 for (i = -1, t = 0; i < niovs && mp && len > 0; mp = mp->b_cont) {
1415 if (mp->b_datap->db_type != M_DATA) {
1418 n = MIN(len, (mp->b_wptr - mp->b_rptr));
1424 t = iovs[i].iov_len;
1427 memcpy(iovs[i].iov_base + o, (char *)mp->b_rptr, m);
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)
1440 #if !defined(AFS_LINUX20_ENV)
1442 m_cpytoiovec(struct mbuf *m, int off, int len, struct iovec iovs[], int niovs)
1445 unsigned int l1, l2, i, t;
1447 if (m == NULL || off < 0 || len < 0 || iovs == NULL)
1448 osi_Panic("m_cpytoiovec"); /* MTUXXX probably don't need this check */
1451 if (m->m_len <= off) {
1461 p1 = mtod(m, caddr_t) + off;
1462 l1 = m->m_len - off;
1464 p2 = iovs[0].iov_base;
1465 l2 = iovs[0].iov_len;
1468 t = MIN(l1, MIN(l2, (unsigned int)len));
1479 p1 = mtod(m, caddr_t);
1485 p2 = iovs[i].iov_base;
1486 l2 = iovs[i].iov_len;
1494 #endif /* AFS_SUN5_ENV */
1496 #if !defined(AFS_LINUX20_ENV)
1498 rx_mb_to_packet(amb, free, hdr_len, data_len, phandle)
1499 #if defined(AFS_SUN5_ENV) || defined(AFS_HPUX110_ENV)
1505 struct rx_packet *phandle;
1506 int hdr_len, data_len;
1511 m_cpytoiovec(amb, hdr_len, data_len, phandle->wirevec,
1518 #endif /*KERNEL && !UKERNEL */
1521 /* send a response to a debug packet */
1524 rxi_ReceiveDebugPacket(register struct rx_packet *ap, osi_socket asocket,
1525 afs_int32 ahost, short aport, int istack)
1527 struct rx_debugIn tin;
1529 struct rx_serverQueueEntry *np, *nqe;
1532 * Only respond to client-initiated Rx debug packets,
1533 * and clear the client flag in the response.
1535 if (ap->header.flags & RX_CLIENT_INITIATED) {
1536 ap->header.flags = ap->header.flags & ~RX_CLIENT_INITIATED;
1537 rxi_EncodePacketHeader(ap);
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);
1547 tin.type = ntohl(tin.type);
1548 tin.index = ntohl(tin.index);
1550 case RX_DEBUGI_GETSTATS:{
1551 struct rx_debugStats tstat;
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;
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,
1568 MUTEX_EXIT(&rx_serverPool_lock);
1569 tstat.idleThreads = htonl(tstat.idleThreads);
1570 tl = sizeof(struct rx_debugStats) - ap->length;
1572 tl = rxi_AllocDataBuf(ap, tl, RX_PACKET_CLASS_SEND_CBUF);
1575 rx_packetwrite(ap, 0, sizeof(struct rx_debugStats),
1577 ap->length = sizeof(struct rx_debugStats);
1578 rxi_SendDebugPacket(ap, asocket, ahost, aport, istack);
1579 rx_computelen(ap, ap->length);
1584 case RX_DEBUGI_GETALLCONN:
1585 case RX_DEBUGI_GETCONN:{
1587 register struct rx_connection *tc;
1588 struct rx_call *tcall;
1589 struct rx_debugConn tconn;
1590 int all = (tin.type == RX_DEBUGI_GETALLCONN);
1593 tl = sizeof(struct rx_debugConn) - ap->length;
1595 tl = rxi_AllocDataBuf(ap, tl, RX_PACKET_CLASS_SEND_CBUF);
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.
1606 #ifdef AFS_PTHREAD_ENV
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.
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;
1635 tconn.callState[j] = RX_STATE_NOTINIT;
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,
1646 #define DOHTONL(a) (tconn.secStats.a = htonl(tconn.secStats.a))
1647 #define DOHTONS(a) (tconn.secStats.a = htons(tconn.secStats.a))
1650 DOHTONL(packetsReceived);
1651 DOHTONL(packetsSent);
1652 DOHTONL(bytesReceived);
1656 sizeof(tconn.secStats.spares) /
1661 sizeof(tconn.secStats.sparel) /
1662 sizeof(afs_int32); i++)
1666 MUTEX_EXIT(&rx_connHashTable_lock);
1667 rx_packetwrite(ap, 0, sizeof(struct rx_debugConn),
1670 ap->length = sizeof(struct rx_debugConn);
1671 rxi_SendDebugPacket(ap, asocket, ahost, aport,
1677 MUTEX_EXIT(&rx_connHashTable_lock);
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),
1684 ap->length = sizeof(struct rx_debugConn);
1685 rxi_SendDebugPacket(ap, asocket, ahost, aport, istack);
1691 * Pass back all the peer structures we have available
1694 case RX_DEBUGI_GETPEER:{
1696 register struct rx_peer *tp;
1697 struct rx_debugPeer tpeer;
1700 tl = sizeof(struct rx_debugPeer) - ap->length;
1702 tl = rxi_AllocDataBuf(ap, tl, RX_PACKET_CLASS_SEND_CBUF);
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.
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
1718 #ifdef AFS_PTHREAD_ENV
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);
1760 MUTEX_EXIT(&rx_peerHashTable_lock);
1761 rx_packetwrite(ap, 0, sizeof(struct rx_debugPeer),
1764 ap->length = sizeof(struct rx_debugPeer);
1765 rxi_SendDebugPacket(ap, asocket, ahost, aport,
1771 MUTEX_EXIT(&rx_peerHashTable_lock);
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),
1778 ap->length = sizeof(struct rx_debugPeer);
1779 rxi_SendDebugPacket(ap, asocket, ahost, aport, istack);
1784 case RX_DEBUGI_RXSTATS:{
1788 tl = sizeof(rx_stats) - ap->length;
1790 tl = rxi_AllocDataBuf(ap, tl, RX_PACKET_CLASS_SEND_CBUF);
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));
1801 ap->length = sizeof(rx_stats);
1802 MUTEX_EXIT(&rx_stats_mutex);
1803 rxi_SendDebugPacket(ap, asocket, ahost, aport, istack);
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);
1814 ap->length = sizeof(struct rx_debugIn);
1815 rxi_SendDebugPacket(ap, asocket, ahost, aport, istack);
1823 rxi_ReceiveVersionPacket(register struct rx_packet *ap, osi_socket asocket,
1824 afs_int32 ahost, short aport, int istack)
1829 * Only respond to client-initiated version requests, and
1830 * clear that flag in the response.
1832 if (ap->header.flags & RX_CLIENT_INITIATED) {
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);
1842 rxi_SendDebugPacket(ap, asocket, ahost, aport, istack);
1850 /* send a debug packet back to the sender */
1852 rxi_SendDebugPacket(struct rx_packet *apacket, osi_socket asocket,
1853 afs_int32 ahost, short aport, afs_int32 istack)
1855 struct sockaddr_in taddr;
1861 int waslocked = ISAFS_GLOCK();
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);
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 */
1880 nbytes -= apacket->wirevec[i].iov_len;
1883 #ifdef RX_KERNEL_TRACE
1884 if (ICL_SETACTIVE(afs_iclSetp)) {
1887 afs_Trace1(afs_iclSetp, CM_TRACE_TIMESTAMP, ICL_TYPE_STRING,
1888 "before osi_NetSend()");
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);
1900 #ifdef RX_KERNEL_TRACE
1901 if (ICL_SETACTIVE(afs_iclSetp)) {
1903 afs_Trace1(afs_iclSetp, CM_TRACE_TIMESTAMP, ICL_TYPE_STRING,
1904 "after osi_NetSend()");
1913 if (saven) { /* means we truncated the packet above. */
1914 apacket->wirevec[i - 1].iov_len = savelen;
1915 apacket->niovecs = saven;
1920 /* Send the packet to appropriate destination for the specified
1921 * call. The header is first encoded and placed in the packet.
1924 rxi_SendPacket(struct rx_call *call, struct rx_connection *conn,
1925 struct rx_packet *p, int istack)
1931 struct sockaddr_in addr;
1932 register struct rx_peer *peer = conn->peer;
1935 char deliveryType = 'S';
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;
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 */
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
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.
1960 if (p->firstSerial == 0) {
1961 p->firstSerial = p->header.serial;
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? */
1970 deliveryType = 'D'; /* Drop the packet */
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 */
1978 /* Send the packet out on the same socket that related packets are being
1982 RX_CLIENT_CONNECTION ? rx_socket : conn->service->socket);
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 */
1991 deliveryType = 'S'; /* Send the packet */
1992 #endif /* RXDEBUG */
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 */
1999 waslocked = ISAFS_GLOCK();
2000 #ifdef RX_KERNEL_TRACE
2001 if (ICL_SETACTIVE(afs_iclSetp)) {
2004 afs_Trace1(afs_iclSetp, CM_TRACE_TIMESTAMP, ICL_TYPE_STRING,
2005 "before osi_NetSend()");
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));
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.
2030 if (call && code == -ENETUNREACH)
2031 call->lastReceiveTime = 0;
2035 #ifdef RX_KERNEL_TRACE
2036 if (ICL_SETACTIVE(afs_iclSetp)) {
2038 afs_Trace1(afs_iclSetp, CM_TRACE_TIMESTAMP, ICL_TYPE_STRING,
2039 "after osi_NetSend()");
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));
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);
2060 /* Send a list of packets to appropriate destination for the specified
2061 * connection. The headers are first encoded and placed in the packets.
2064 rxi_SendPacketList(struct rx_call *call, struct rx_connection *conn,
2065 struct rx_packet **list, int len, int istack)
2067 #if defined(AFS_SUN5_ENV) && defined(KERNEL)
2070 struct sockaddr_in addr;
2071 register struct rx_peer *peer = conn->peer;
2073 struct rx_packet *p = NULL;
2074 struct iovec wirevec[RX_MAXIOVECS];
2075 int i, length, code;
2078 struct rx_jumboHeader *jp;
2080 char deliveryType = 'S';
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;
2087 if (len + 1 > RX_MAXIOVECS) {
2088 osi_Panic("rxi_SendPacketList, len > RX_MAXIOVECS\n");
2092 * Stamp the packets in this jumbogram with consecutive serial numbers
2094 MUTEX_ENTER(&conn->conn_data_lock);
2095 serial = conn->serial;
2096 conn->serial += len;
2097 MUTEX_EXIT(&conn->conn_data_lock);
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 */
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++) {
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");
2117 /* Set the RX_JUMBO_PACKET flags in all but the last packets
2120 if (p->length != RX_JUMBOBUFFERSIZE) {
2121 osi_Panic("rxi_SendPacketList, length != jumbo size\n");
2123 p->header.flags |= RX_JUMBO_PACKET;
2124 length += RX_JUMBOBUFFERSIZE + RX_JUMBOHEADERSIZE;
2125 wirevec[i + 1].iov_len = RX_JUMBOBUFFERSIZE + RX_JUMBOHEADERSIZE;
2127 wirevec[i + 1].iov_len = p->length;
2128 length += p->length;
2130 wirevec[i + 1].iov_base = (char *)(&p->localdata[0]);
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);
2137 jp = (struct rx_jumboHeader *)
2138 ((char *)(&p->localdata[0]) + RX_JUMBOBUFFERSIZE);
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
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.
2151 if (p->firstSerial == 0) {
2152 p->firstSerial = p->header.serial;
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? */
2161 deliveryType = 'D'; /* Drop the packet */
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 */
2170 /* Send the packet out on the same socket that related packets are being
2174 RX_CLIENT_CONNECTION ? rx_socket : conn->service->socket);
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 */
2183 deliveryType = 'S'; /* Send the packet */
2184 #endif /* RXDEBUG */
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)
2196 osi_NetSend(socket, &addr, &wirevec[0], len + 1, length,
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++) {
2204 p->retryTime = p->timeSent; /* resend it very soon */
2205 clock_Addmsec(&(p->retryTime),
2206 10 + (((afs_uint32) p->backoff) << 8));
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.
2214 if (call && code == -ENETUNREACH)
2215 call->lastReceiveTime = 0;
2218 #if defined(AFS_SUN5_ENV) && defined(KERNEL)
2219 if (!istack && waslocked)
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));
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);
2235 hadd32(peer->bytesSent, p->length);
2236 MUTEX_EXIT(&peer->peer_lock);
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. */
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)
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;
2259 int savelen = 0, saven = 0;
2260 int channel, callNumber;
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) {
2274 p = rxi_AllocPacket(RX_PACKET_CLASS_SPECIAL);
2276 osi_Panic("rxi_SendSpecial failure");
2283 p->header.serviceId = conn->serviceId;
2284 p->header.securityIndex = conn->securityIndex;
2285 p->header.cid = (conn->cid | channel);
2286 p->header.callNumber = callNumber;
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;
2294 rx_packetwrite(p, 0, nbytes, data);
2296 for (i = 1; i < p->niovecs; i++) {
2297 if (nbytes <= p->wirevec[i].iov_len) {
2298 savelen = p->wirevec[i].iov_len;
2300 p->wirevec[i].iov_len = nbytes;
2301 p->niovecs = i + 1; /* so condition fails because i == niovecs */
2303 nbytes -= p->wirevec[i].iov_len;
2307 rxi_Send(call, p, istack);
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;
2316 if (!optionalPacket)
2318 return optionalPacket;
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) */
2326 rxi_EncodePacketHeader(register struct rx_packet *p)
2328 register afs_uint32 *buf = (afs_uint32 *) (p->wirevec[0].iov_base); /* MTUXXX */
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));
2343 /* Decode the packet's header (from net byte order to a struct header) */
2345 rxi_DecodePacketHeader(register struct rx_packet *p)
2347 register afs_uint32 *buf = (afs_uint32 *) (p->wirevec[0].iov_base); /* MTUXXX */
2350 p->header.epoch = ntohl(*buf);
2352 p->header.cid = ntohl(*buf);
2354 p->header.callNumber = ntohl(*buf);
2356 p->header.seq = ntohl(*buf);
2358 p->header.serial = ntohl(*buf);
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;
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 */
2379 rxi_PrepareSendPacket(register struct rx_call *call,
2380 register struct rx_packet *p, register int last)
2382 register struct rx_connection *conn = call->conn;
2384 ssize_t len; /* len must be a signed type; it can go negative */
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;
2400 p->header.flags |= RX_LAST_PACKET;
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... */
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;
2411 for (i = 1; i < p->niovecs && len > 0; i++) {
2412 len -= p->wirevec[i].iov_len;
2415 osi_Panic("PrepareSendPacket 1\n"); /* MTUXXX */
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));
2422 p->wirevec[i - 1].iov_len += len;
2424 RXS_PreparePacket(conn->securityObject, call, p);
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. */
2431 rxi_AdjustIfMTU(int mtu)
2436 adjMTU = RX_HEADER_SIZE + RX_JUMBOBUFFERSIZE + RX_JUMBOHEADERSIZE;
2437 if (mtu <= adjMTU) {
2444 frags = mtu / (RX_JUMBOBUFFERSIZE + RX_JUMBOHEADERSIZE);
2445 return (adjMTU + (frags * (RX_JUMBOBUFFERSIZE + RX_JUMBOHEADERSIZE)));
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. */
2452 rxi_AdjustMaxMTU(int mtu, int peerMaxMTU)
2454 int maxMTU = mtu * rxi_nSendFrags;
2455 maxMTU = MIN(maxMTU, peerMaxMTU);
2456 return rxi_AdjustIfMTU(maxMTU);
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 */
2464 rxi_AdjustDgramPackets(int frags, int mtu)
2467 if (mtu + IPv6_FRAG_HDR_SIZE < RX_JUMBOBUFFERSIZE + RX_HEADER_SIZE) {
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;
2477 return (2 + (maxMTU / (RX_JUMBOBUFFERSIZE + RX_JUMBOHEADERSIZE)));