Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / rx / rx_user.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 /* rx_user.c contains routines specific to the user space UNIX implementation of rx */
11
12 /* rxi_syscall is currently not prototyped */
13
14 #include <afsconfig.h>
15 #include <afs/param.h>
16
17 #include <roken.h>
18
19 #include <afs/opr.h>
20
21 #ifdef AFS_NT40_ENV
22 # include <WINNT/syscfg.h>
23 #else
24 # include <net/if.h>
25 #endif
26 #if !defined(AFS_AIX_ENV) && !defined(AFS_NT40_ENV)
27 # include <sys/syscall.h>
28 #endif
29 #include <afs/afs_args.h>
30 #include <afs/afsutil.h>
31
32 #ifndef IPPORT_USERRESERVED
33 /* If in.h doesn't define this, define it anyway. Unfortunately, defining
34 this doesn't put the code into the kernel to restrict kernel assigned
35 port numbers to numbers below IPPORT_USERRESERVED... */
36 #define IPPORT_USERRESERVED 5000
37 # endif
38
39 #if defined(AFS_LINUX22_ENV) && defined(AFS_RXERRQ_ENV)
40 # include <linux/types.h>
41 # include <linux/errqueue.h>
42 # if defined(AFS_ADAPT_PMTU) && !defined(IP_MTU)
43 # define IP_MTU 14
44 # endif
45 #endif
46
47 #include "rx.h"
48 #include "rx_atomic.h"
49 #include "rx_globals.h"
50 #include "rx_stats.h"
51 #include "rx_peer.h"
52 #include "rx_packet.h"
53 #include "rx_internal.h"
54
55 #ifdef AFS_PTHREAD_ENV
56
57 /*
58 * The rx_if_init_mutex mutex protects the following global variables:
59 * Inited
60 */
61
62 afs_kmutex_t rx_if_init_mutex;
63 #define LOCK_IF_INIT MUTEX_ENTER(&rx_if_init_mutex)
64 #define UNLOCK_IF_INIT MUTEX_EXIT(&rx_if_init_mutex)
65
66 /*
67 * The rx_if_mutex mutex protects the following global variables:
68 * myNetFlags
69 * myNetMTUs
70 * myNetMasks
71 */
72
73 afs_kmutex_t rx_if_mutex;
74 #define LOCK_IF MUTEX_ENTER(&rx_if_mutex)
75 #define UNLOCK_IF MUTEX_EXIT(&rx_if_mutex)
76 #else
77 #define LOCK_IF_INIT
78 #define UNLOCK_IF_INIT
79 #define LOCK_IF
80 #define UNLOCK_IF
81 #endif /* AFS_PTHREAD_ENV */
82
83
84 /*
85 * Make a socket for receiving/sending IP packets. Set it into non-blocking
86 * and large buffering modes. If port isn't specified, the kernel will pick
87 * one. Returns the socket (>= 0) on success. Returns OSI_NULLSOCKET on
88 * failure. Port must be in network byte order.
89 */
90 osi_socket
91 rxi_GetHostUDPSocket(u_int ahost, u_short port)
92 {
93 int binds, code = 0;
94 osi_socket socketFd = OSI_NULLSOCKET;
95 struct sockaddr_in taddr;
96 char *name = "rxi_GetUDPSocket: ";
97 #ifdef AFS_LINUX22_ENV
98 # if defined(AFS_ADAPT_PMTU)
99 int pmtu = IP_PMTUDISC_WANT;
100 # else
101 int pmtu = IP_PMTUDISC_DONT;
102 # endif
103 #endif
104
105 #if !defined(AFS_NT40_ENV)
106 if (ntohs(port) >= IPPORT_RESERVED && ntohs(port) < IPPORT_USERRESERVED) {
107 /* (osi_Msg "%s*WARNING* port number %d is not a reserved port number. Use port numbers above %d\n", name, port, IPPORT_USERRESERVED);
108 */ ;
109 }
110 if (ntohs(port) > 0 && ntohs(port) < IPPORT_RESERVED && geteuid() != 0) {
111 (osi_Msg
112 "%sport number %d is a reserved port number which may only be used by root. Use port numbers above %d\n",
113 name, ntohs(port), IPPORT_USERRESERVED);
114 goto error;
115 }
116 #endif
117 socketFd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
118
119 if (socketFd == OSI_NULLSOCKET) {
120 #ifdef AFS_NT40_ENV
121 fprintf(stderr, "socket() failed with error %u\n", WSAGetLastError());
122 #else
123 perror("socket");
124 #endif
125 goto error;
126 }
127
128 #ifdef AFS_NT40_ENV
129 rxi_xmit_init(socketFd);
130 #endif /* AFS_NT40_ENV */
131
132 taddr.sin_addr.s_addr = ahost;
133 taddr.sin_family = AF_INET;
134 taddr.sin_port = (u_short) port;
135 memset(&taddr.sin_zero, 0, sizeof(taddr.sin_zero));
136 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
137 taddr.sin_len = sizeof(struct sockaddr_in);
138 #endif
139 #define MAX_RX_BINDS 10
140 for (binds = 0; binds < MAX_RX_BINDS; binds++) {
141 if (binds)
142 rxi_Delay(10);
143 code = bind(socketFd, (struct sockaddr *)&taddr, sizeof(taddr));
144 break;
145 }
146 if (code) {
147 (osi_Msg "%sbind failed\n", name);
148 goto error;
149 }
150 #if !defined(AFS_NT40_ENV)
151 /*
152 * Set close-on-exec on rx socket
153 */
154 fcntl(socketFd, F_SETFD, 1);
155 #endif
156
157 /* Use one of three different ways of getting a socket buffer expanded to
158 * a reasonable size.
159 */
160 {
161 int greedy = 0;
162 int len1, len2;
163
164 len1 = 32766;
165 len2 = rx_UdpBufSize;
166
167 /* find the size closest to rx_UdpBufSize that will be accepted */
168 while (!greedy && len2 > len1) {
169 greedy =
170 (setsockopt
171 (socketFd, SOL_SOCKET, SO_RCVBUF, (char *)&len2,
172 sizeof(len2)) >= 0);
173 if (!greedy)
174 len2 /= 2;
175 }
176
177 /* but do not let it get smaller than 32K */
178 if (len2 < len1)
179 len2 = len1;
180
181 if (len1 < len2)
182 len1 = len2;
183
184
185 greedy =
186 (setsockopt
187 (socketFd, SOL_SOCKET, SO_SNDBUF, (char *)&len1,
188 sizeof(len1)) >= 0)
189 &&
190 (setsockopt
191 (socketFd, SOL_SOCKET, SO_RCVBUF, (char *)&len2,
192 sizeof(len2)) >= 0);
193 if (!greedy)
194 (osi_Msg "%s*WARNING* Unable to increase buffering on socket\n",
195 name);
196 if (rx_stats_active)
197 rx_atomic_set(&rx_stats.socketGreedy, greedy);
198 }
199
200 #ifdef AFS_LINUX22_ENV
201 setsockopt(socketFd, SOL_IP, IP_MTU_DISCOVER, &pmtu, sizeof(pmtu));
202 #endif
203 #ifdef AFS_RXERRQ_ENV
204 {
205 int recverr = 1;
206 setsockopt(socketFd, SOL_IP, IP_RECVERR, &recverr, sizeof(recverr));
207 }
208 #endif
209 if (rxi_Listen(socketFd) < 0) {
210 goto error;
211 }
212
213 return socketFd;
214
215 error:
216 #ifdef AFS_NT40_ENV
217 if (socketFd != OSI_NULLSOCKET)
218 closesocket(socketFd);
219 #else
220 if (socketFd != OSI_NULLSOCKET)
221 close(socketFd);
222 #endif
223
224 return OSI_NULLSOCKET;
225 }
226
227 osi_socket
228 rxi_GetUDPSocket(u_short port)
229 {
230 return rxi_GetHostUDPSocket(htonl(INADDR_ANY), port);
231 }
232
233 void
234 osi_Panic(char *msg, ...)
235 {
236 va_list ap;
237 va_start(ap, msg);
238 (osi_Msg "Fatal Rx error: ");
239 (osi_VMsg msg, ap);
240 va_end(ap);
241 fflush(stderr);
242 fflush(stdout);
243 opr_abort();
244 }
245
246 /*
247 * osi_AssertFailU() -- used by the osi_Assert() macro.
248 */
249
250 void
251 osi_AssertFailU(const char *expr, const char *file, int line)
252 {
253 osi_Panic("assertion failed: %s, file: %s, line: %d\n", expr,
254 file, line);
255 }
256
257 #if defined(AFS_AIX32_ENV) && !defined(KERNEL)
258 #ifndef osi_Alloc
259 static const char memZero;
260 void *
261 osi_Alloc(afs_int32 x)
262 {
263 /*
264 * 0-length allocs may return NULL ptr from malloc, so we special-case
265 * things so that NULL returned iff an error occurred
266 */
267 if (x == 0)
268 return (void *)&memZero;
269 return(malloc(x));
270 }
271
272 void
273 osi_Free(void *x, afs_int32 size)
274 {
275 if (x == &memZero)
276 return;
277 free(x);
278 }
279 #endif
280 #endif /* defined(AFS_AIX32_ENV) && !defined(KERNEL) */
281
282 #define ADDRSPERSITE 16
283
284
285 static afs_uint32 rxi_NetAddrs[ADDRSPERSITE]; /* host order */
286 static int myNetMTUs[ADDRSPERSITE];
287 static int myNetMasks[ADDRSPERSITE];
288 static int myNetFlags[ADDRSPERSITE];
289 static u_int rxi_numNetAddrs;
290 static int Inited = 0;
291
292 #if defined(AFS_NT40_ENV)
293 int
294 rxi_getaddr(void)
295 {
296 /* The IP address list can change so we must query for it */
297 rx_GetIFInfo();
298
299 /* we don't want to use the loopback adapter which is first */
300 /* this is a bad bad hack */
301 if (rxi_numNetAddrs > 1)
302 return htonl(rxi_NetAddrs[1]);
303 else if (rxi_numNetAddrs > 0)
304 return htonl(rxi_NetAddrs[0]);
305 else
306 return 0;
307 }
308
309 /*
310 ** return number of addresses
311 ** and the addresses themselves in the buffer
312 ** maxSize - max number of interfaces to return.
313 */
314 int
315 rx_getAllAddr(afs_uint32 * buffer, int maxSize)
316 {
317 int count = 0, offset = 0;
318
319 /* The IP address list can change so we must query for it */
320 rx_GetIFInfo();
321
322 for (count = 0; offset < rxi_numNetAddrs && maxSize > 0;
323 count++, offset++, maxSize--)
324 buffer[count] = htonl(rxi_NetAddrs[offset]);
325
326 return count;
327 }
328
329 /* this function returns the total number of interface addresses
330 * the buffer has to be passed in by the caller. It also returns
331 * the matching interface mask and mtu. All values are returned
332 * in network byte order.
333 */
334 int
335 rx_getAllAddrMaskMtu(afs_uint32 addrBuffer[], afs_uint32 maskBuffer[],
336 afs_uint32 mtuBuffer[], int maxSize)
337 {
338 int count = 0, offset = 0;
339
340 /* The IP address list can change so we must query for it */
341 rx_GetIFInfo();
342
343 for (count = 0;
344 offset < rxi_numNetAddrs && maxSize > 0;
345 count++, offset++, maxSize--) {
346 addrBuffer[count] = htonl(rxi_NetAddrs[offset]);
347 maskBuffer[count] = htonl(myNetMasks[offset]);
348 mtuBuffer[count] = htonl(myNetMTUs[offset]);
349 }
350 return count;
351 }
352 #endif
353
354 #ifdef AFS_NT40_ENV
355 void
356 rxi_InitMorePackets(void) {
357 int npackets, ncbufs;
358
359 ncbufs = (rx_maxJumboRecvSize - RX_FIRSTBUFFERSIZE);
360 if (ncbufs > 0) {
361 ncbufs = ncbufs / RX_CBUFFERSIZE;
362 npackets = rx_initSendWindow - 1;
363 rxi_MorePackets(npackets * (ncbufs + 1));
364 }
365 }
366 void
367 rx_GetIFInfo(void)
368 {
369 u_int maxsize;
370 u_int rxsize;
371 afs_uint32 i;
372
373 LOCK_IF_INIT;
374 if (Inited) {
375 if (Inited < 2 && rxi_IsRunning()) {
376 /* We couldn't initialize more packets earlier.
377 * Do it now. */
378 rxi_InitMorePackets();
379 Inited = 2;
380 }
381 UNLOCK_IF_INIT;
382 return;
383 }
384 Inited = 1;
385 UNLOCK_IF_INIT;
386
387 LOCK_IF;
388 rxi_numNetAddrs = ADDRSPERSITE;
389 (void)syscfg_GetIFInfo(&rxi_numNetAddrs, rxi_NetAddrs,
390 myNetMasks, myNetMTUs, myNetFlags);
391
392 for (i = 0; i < rxi_numNetAddrs; i++) {
393 rxsize = rxi_AdjustIfMTU(myNetMTUs[i] - RX_IPUDP_SIZE);
394 maxsize =
395 rxi_nRecvFrags * rxsize + (rxi_nRecvFrags - 1) * UDP_HDR_SIZE;
396 maxsize = rxi_AdjustMaxMTU(rxsize, maxsize);
397 if (rx_maxReceiveSize > maxsize) {
398 rx_maxReceiveSize = MIN(RX_MAX_PACKET_SIZE, maxsize);
399 rx_maxReceiveSize =
400 MIN(rx_maxReceiveSize, rx_maxReceiveSizeUser);
401 }
402 if (rx_MyMaxSendSize > maxsize) {
403 rx_MyMaxSendSize = MIN(RX_MAX_PACKET_SIZE, maxsize);
404 }
405 }
406 UNLOCK_IF;
407
408 /*
409 * If rxi_IsRunning is false, rx_InitHost() has yet to be called
410 * and we therefore do not have any mutex locks initialized. As a
411 * result we cannot call rxi_MorePackets() without crashing.
412 */
413 if (!rxi_IsRunning())
414 return;
415
416 rxi_InitMorePackets();
417 }
418 #endif
419
420 static afs_uint32
421 fudge_netmask(afs_uint32 addr)
422 {
423 afs_uint32 msk;
424
425 if (IN_CLASSA(addr))
426 msk = IN_CLASSA_NET;
427 else if (IN_CLASSB(addr))
428 msk = IN_CLASSB_NET;
429 else if (IN_CLASSC(addr))
430 msk = IN_CLASSC_NET;
431 else
432 msk = 0;
433
434 return msk;
435 }
436
437
438
439 #if !defined(AFS_AIX_ENV) && !defined(AFS_NT40_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN160_ENV)
440 int
441 rxi_syscall(afs_uint32 a3, afs_uint32 a4, void *a5)
442 {
443 afs_uint32 rcode;
444 void (*old) (int);
445
446 old = signal(SIGSYS, SIG_IGN);
447
448 #if defined(AFS_SGI_ENV)
449 rcode = afs_syscall(AFS_SYSCALL, 28, a3, a4, a5);
450 #elif defined(AFS_SYSCALL)
451 rcode = syscall(AFS_SYSCALL, 28 /* AFSCALL_CALL */ , a3, a4, a5);
452 #else
453 rcode = -1;
454 #endif /* AFS_SGI_ENV */
455
456 signal(SIGSYS, old);
457
458 return rcode;
459 }
460 #endif /* AFS_AIX_ENV */
461
462 #ifndef AFS_NT40_ENV
463 void
464 rx_GetIFInfo(void)
465 {
466 int s;
467 int i, j, len, res;
468 struct ifconf ifc;
469 struct ifreq ifs[ADDRSPERSITE];
470 struct ifreq *ifr;
471 #ifdef AFS_AIX41_ENV
472 char buf[BUFSIZ], *cp, *cplim;
473 #endif
474 struct sockaddr_in *a;
475
476 LOCK_IF_INIT;
477 if (Inited) {
478 UNLOCK_IF_INIT;
479 return;
480 }
481 Inited = 1;
482 UNLOCK_IF_INIT;
483 LOCK_IF;
484 rxi_numNetAddrs = 0;
485 memset(rxi_NetAddrs, 0, sizeof(rxi_NetAddrs));
486 memset(myNetFlags, 0, sizeof(myNetFlags));
487 memset(myNetMTUs, 0, sizeof(myNetMTUs));
488 memset(myNetMasks, 0, sizeof(myNetMasks));
489 UNLOCK_IF;
490 s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
491 if (s == OSI_NULLSOCKET)
492 return;
493 #ifdef AFS_AIX41_ENV
494 ifc.ifc_len = sizeof(buf);
495 ifc.ifc_buf = buf;
496 ifr = ifc.ifc_req;
497 #else
498 ifc.ifc_len = sizeof(ifs);
499 ifc.ifc_buf = (caddr_t) & ifs[0];
500 memset(&ifs[0], 0, sizeof(ifs));
501 #endif
502 res = ioctl(s, SIOCGIFCONF, &ifc);
503 if (res < 0) {
504 /* fputs(stderr, "ioctl error IFCONF\n"); */
505 close(s);
506 return;
507 }
508
509 LOCK_IF;
510 #ifdef AFS_AIX41_ENV
511 #define size(p) MAX((p).sa_len, sizeof(p))
512 cplim = buf + ifc.ifc_len; /*skip over if's with big ifr_addr's */
513 for (cp = buf; cp < cplim;
514 cp += sizeof(ifr->ifr_name) + MAX(a->sin_len, sizeof(*a))) {
515 if (rxi_numNetAddrs >= ADDRSPERSITE)
516 break;
517
518 ifr = (struct ifreq *)cp;
519 #else
520 len = ifc.ifc_len / sizeof(struct ifreq);
521 if (len > ADDRSPERSITE)
522 len = ADDRSPERSITE;
523
524 for (i = 0; i < len; ++i) {
525 ifr = &ifs[i];
526 res = ioctl(s, SIOCGIFADDR, ifr);
527 #endif
528 if (res < 0) {
529 /* fputs(stderr, "ioctl error IFADDR\n");
530 * perror(ifr->ifr_name); */
531 continue;
532 }
533 a = (struct sockaddr_in *)&ifr->ifr_addr;
534 if (a->sin_family != AF_INET)
535 continue;
536 rxi_NetAddrs[rxi_numNetAddrs] = ntohl(a->sin_addr.s_addr);
537 if (rx_IsLoopbackAddr(rxi_NetAddrs[rxi_numNetAddrs])) {
538 /* we don't really care about "localhost" */
539 continue;
540 }
541 for (j = 0; j < rxi_numNetAddrs; j++) {
542 if (rxi_NetAddrs[j] == rxi_NetAddrs[rxi_numNetAddrs])
543 break;
544 }
545 if (j < rxi_numNetAddrs)
546 continue;
547
548 /* fprintf(stderr, "if %s addr=%x\n", ifr->ifr_name,
549 * rxi_NetAddrs[rxi_numNetAddrs]); */
550
551 #ifdef SIOCGIFFLAGS
552 res = ioctl(s, SIOCGIFFLAGS, ifr);
553 if (res == 0) {
554 myNetFlags[rxi_numNetAddrs] = ifr->ifr_flags;
555 #ifdef IFF_LOOPBACK
556 /* Handle aliased loopbacks as well. */
557 if (ifr->ifr_flags & IFF_LOOPBACK)
558 continue;
559 #endif
560 /* fprintf(stderr, "if %s flags=%x\n",
561 * ifr->ifr_name, ifr->ifr_flags); */
562 } else { /*
563 * fputs(stderr, "ioctl error IFFLAGS\n");
564 * perror(ifr->ifr_name); */
565 }
566 #endif /* SIOCGIFFLAGS */
567
568 #if !defined(AFS_AIX_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN160_ENV)
569 /* this won't run on an AIX system w/o a cache manager */
570 rxi_syscallp = rxi_syscall;
571 #endif
572
573 /* If I refer to kernel extensions that aren't loaded on AIX, the
574 * program refuses to load and run, so I simply can't include the
575 * following code. Fortunately, AIX is the one operating system in
576 * which the subsequent ioctl works reliably. */
577 if (rxi_syscallp) {
578 if ((*rxi_syscallp) (20 /*AFSOP_GETMTU */ ,
579 htonl(rxi_NetAddrs[rxi_numNetAddrs]),
580 &(myNetMTUs[rxi_numNetAddrs]))) {
581 /* fputs(stderr, "syscall error GETMTU\n");
582 * perror(ifr->ifr_name); */
583 myNetMTUs[rxi_numNetAddrs] = 0;
584 }
585 if ((*rxi_syscallp) (42 /*AFSOP_GETMASK */ ,
586 htonl(rxi_NetAddrs[rxi_numNetAddrs]),
587 &(myNetMasks[rxi_numNetAddrs]))) {
588 /* fputs(stderr, "syscall error GETMASK\n");
589 * perror(ifr->ifr_name); */
590 myNetMasks[rxi_numNetAddrs] = 0;
591 } else
592 myNetMasks[rxi_numNetAddrs] =
593 ntohl(myNetMasks[rxi_numNetAddrs]);
594 /* fprintf(stderr, "if %s mask=0x%x\n",
595 * ifr->ifr_name, myNetMasks[rxi_numNetAddrs]); */
596 }
597
598 if (myNetMTUs[rxi_numNetAddrs] == 0) {
599 myNetMTUs[rxi_numNetAddrs] = OLD_MAX_PACKET_SIZE + RX_IPUDP_SIZE;
600 #ifdef SIOCGIFMTU
601 res = ioctl(s, SIOCGIFMTU, ifr);
602 if ((res == 0) && (ifr->ifr_metric > 128)) { /* sanity check */
603 myNetMTUs[rxi_numNetAddrs] = ifr->ifr_metric;
604 /* fprintf(stderr, "if %s mtu=%d\n",
605 * ifr->ifr_name, ifr->ifr_metric); */
606 } else {
607 /* fputs(stderr, "ioctl error IFMTU\n");
608 * perror(ifr->ifr_name); */
609 }
610 #endif
611 }
612
613 if (myNetMasks[rxi_numNetAddrs] == 0) {
614 myNetMasks[rxi_numNetAddrs] =
615 fudge_netmask(rxi_NetAddrs[rxi_numNetAddrs]);
616 #ifdef SIOCGIFNETMASK
617 res = ioctl(s, SIOCGIFNETMASK, ifr);
618 if (res == 0) {
619 a = (struct sockaddr_in *)&ifr->ifr_addr;
620 myNetMasks[rxi_numNetAddrs] = ntohl(a->sin_addr.s_addr);
621 /* fprintf(stderr, "if %s subnetmask=0x%x\n",
622 * ifr->ifr_name, myNetMasks[rxi_numNetAddrs]); */
623 } else {
624 /* fputs(stderr, "ioctl error IFMASK\n");
625 * perror(ifr->ifr_name); */
626 }
627 #endif
628 }
629
630 if (!rx_IsLoopbackAddr(rxi_NetAddrs[rxi_numNetAddrs])) { /* ignore lo0 */
631 int maxsize;
632 maxsize =
633 rxi_nRecvFrags * (myNetMTUs[rxi_numNetAddrs] - RX_IP_SIZE);
634 maxsize -= UDP_HDR_SIZE; /* only the first frag has a UDP hdr */
635 if (rx_maxReceiveSize < maxsize)
636 rx_maxReceiveSize = MIN(RX_MAX_PACKET_SIZE, maxsize);
637 ++rxi_numNetAddrs;
638 }
639 }
640 UNLOCK_IF;
641 close(s);
642
643 /* have to allocate at least enough to allow a single packet to reach its
644 * maximum size, so ReadPacket will work. Allocate enough for a couple
645 * of packets to do so, for good measure */
646 {
647 int npackets, ncbufs;
648
649 rx_maxJumboRecvSize =
650 RX_HEADER_SIZE + rxi_nDgramPackets * RX_JUMBOBUFFERSIZE +
651 (rxi_nDgramPackets - 1) * RX_JUMBOHEADERSIZE;
652 rx_maxJumboRecvSize = MAX(rx_maxJumboRecvSize, rx_maxReceiveSize);
653 ncbufs = (rx_maxJumboRecvSize - RX_FIRSTBUFFERSIZE);
654 if (ncbufs > 0) {
655 ncbufs = ncbufs / RX_CBUFFERSIZE;
656 npackets = rx_initSendWindow - 1;
657 rxi_MorePackets(npackets * (ncbufs + 1));
658 }
659 }
660 }
661 #endif /* AFS_NT40_ENV */
662
663 /* Called from rxi_FindPeer, when initializing a clear rx_peer structure,
664 * to get interesting information.
665 * Curiously enough, the rx_peerHashTable_lock currently protects the
666 * Inited variable (and hence rx_GetIFInfo). When the fs suite uses
667 * pthreads, this issue will need to be revisited.
668 */
669
670 void
671 rxi_InitPeerParams(struct rx_peer *pp)
672 {
673 afs_uint32 ppaddr;
674 u_short rxmtu;
675 int ix;
676 #ifdef AFS_ADAPT_PMTU
677 int sock;
678 struct sockaddr_in addr;
679 #endif
680
681 LOCK_IF_INIT;
682 if (!Inited) {
683 UNLOCK_IF_INIT;
684 /*
685 * there's a race here since more than one thread could call
686 * rx_GetIFInfo. The race stops in rx_GetIFInfo.
687 */
688 rx_GetIFInfo();
689 } else {
690 UNLOCK_IF_INIT;
691 }
692
693 /* try to second-guess IP, and identify which link is most likely to
694 * be used for traffic to/from this host. */
695 ppaddr = ntohl(pp->host);
696
697 pp->ifMTU = 0;
698 rx_rto_setPeerTimeoutSecs(pp, 2);
699 /* I don't initialize these, because I presume they are bzero'd...
700 * pp->burstSize pp->burst pp->burstWait.sec pp->burstWait.usec
701 */
702
703 LOCK_IF;
704 for (ix = 0; ix < rxi_numNetAddrs; ++ix) {
705 if ((rxi_NetAddrs[ix] & myNetMasks[ix]) == (ppaddr & myNetMasks[ix])) {
706 #ifdef IFF_POINTOPOINT
707 if (myNetFlags[ix] & IFF_POINTOPOINT)
708 rx_rto_setPeerTimeoutSecs(pp, 4);
709 #endif /* IFF_POINTOPOINT */
710
711 rxmtu = myNetMTUs[ix] - RX_IPUDP_SIZE;
712 if (rxmtu < RX_MIN_PACKET_SIZE)
713 rxmtu = RX_MIN_PACKET_SIZE;
714 if (pp->ifMTU < rxmtu)
715 pp->ifMTU = MIN(rx_MyMaxSendSize, rxmtu);
716 }
717 }
718 UNLOCK_IF;
719 if (!pp->ifMTU) { /* not local */
720 rx_rto_setPeerTimeoutSecs(pp, 3);
721 pp->ifMTU = MIN(rx_MyMaxSendSize, RX_REMOTE_PACKET_SIZE);
722 }
723 #ifdef AFS_ADAPT_PMTU
724 sock=socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
725 if (sock != OSI_NULLSOCKET) {
726 addr.sin_family = AF_INET;
727 addr.sin_addr.s_addr = pp->host;
728 addr.sin_port = pp->port;
729 memset(&addr.sin_zero, 0, sizeof(addr.sin_zero));
730 if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0) {
731 int mtu=0;
732 socklen_t s = sizeof(mtu);
733 if (getsockopt(sock, SOL_IP, IP_MTU, &mtu, &s)== 0) {
734 pp->ifMTU = MIN(mtu - RX_IPUDP_SIZE, pp->ifMTU);
735 }
736 }
737 # ifdef AFS_NT40_ENV
738 closesocket(sock);
739 # else
740 close(sock);
741 # endif
742 }
743 #endif
744 pp->ifMTU = rxi_AdjustIfMTU(pp->ifMTU);
745 pp->maxMTU = OLD_MAX_PACKET_SIZE; /* for compatibility with old guys */
746 pp->natMTU = MIN((int)pp->ifMTU, OLD_MAX_PACKET_SIZE);
747 pp->maxDgramPackets =
748 MIN(rxi_nDgramPackets,
749 rxi_AdjustDgramPackets(rxi_nSendFrags, pp->ifMTU));
750 pp->ifDgramPackets =
751 MIN(rxi_nDgramPackets,
752 rxi_AdjustDgramPackets(rxi_nSendFrags, pp->ifMTU));
753 pp->maxDgramPackets = 1;
754 /* Initialize slow start parameters */
755 pp->MTU = MIN(pp->natMTU, pp->maxMTU);
756 pp->cwind = 1;
757 pp->nDgramPackets = 1;
758 pp->congestSeq = 0;
759 }
760
761 /* Don't expose jumobgram internals. */
762 void
763 rx_SetNoJumbo(void)
764 {
765 rx_maxReceiveSize = OLD_MAX_PACKET_SIZE;
766 rxi_nSendFrags = rxi_nRecvFrags = 1;
767 }
768
769 /* Override max MTU. If rx_SetNoJumbo is called, it must be
770 called before calling rx_SetMaxMTU since SetNoJumbo clobbers rx_maxReceiveSize */
771 int
772 rx_SetMaxMTU(int mtu)
773 {
774 if (mtu < RX_MIN_PACKET_SIZE || mtu > RX_MAX_PACKET_DATA_SIZE)
775 return EINVAL;
776
777 rx_MyMaxSendSize = rx_maxReceiveSizeUser = rx_maxReceiveSize = mtu;
778
779 return 0;
780 }
781
782 #ifdef AFS_RXERRQ_ENV
783 int
784 rxi_HandleSocketError(int socket)
785 {
786 struct msghdr msg;
787 struct cmsghdr *cmsg;
788 struct sock_extended_err *err;
789 struct sockaddr_in addr;
790 char controlmsgbuf[256];
791 int code;
792
793 msg.msg_name = &addr;
794 msg.msg_namelen = sizeof(addr);
795 msg.msg_iov = NULL;
796 msg.msg_iovlen = 0;
797 msg.msg_control = controlmsgbuf;
798 msg.msg_controllen = 256;
799 msg.msg_flags = 0;
800 code = recvmsg(socket, &msg, MSG_ERRQUEUE|MSG_DONTWAIT|MSG_TRUNC);
801
802 if (code < 0 || !(msg.msg_flags & MSG_ERRQUEUE))
803 return 0;
804
805 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
806 if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVERR) {
807 err = (struct sock_extended_err *)CMSG_DATA(cmsg);
808 rxi_ProcessNetError(err, addr.sin_addr.s_addr, addr.sin_port);
809 }
810 }
811
812 return 1;
813 }
814 #endif