xref: /illumos-gate/usr/src/lib/libnsl/rpc/svc_vc.c (revision a69e76ca)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 /*
27  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
28  */
29 
30 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
31 /* All Rights Reserved */
32 /*
33  * Portions of this source code were derived from Berkeley
34  * 4.3 BSD under license from the Regents of the University of
35  * California.
36  */
37 
38 /*
39  * Server side for Connection Oriented RPC.
40  *
41  * Actually implements two flavors of transporter -
42  * a rendezvouser (a listener and connection establisher)
43  * and a record stream.
44  */
45 
46 #include "mt.h"
47 #include "rpc_mt.h"
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <rpc/rpc.h>
51 #include <sys/types.h>
52 #include <errno.h>
53 #include <sys/stat.h>
54 #include <sys/mkdev.h>
55 #include <sys/poll.h>
56 #include <syslog.h>
57 #include <rpc/nettype.h>
58 #include <tiuser.h>
59 #include <string.h>
60 #include <stropts.h>
61 #include <stdlib.h>
62 #include <unistd.h>
63 #include <sys/timod.h>
64 #include <limits.h>
65 
66 #ifndef MIN
67 #define	MIN(a, b)	(((a) < (b)) ? (a) : (b))
68 #endif
69 
70 #define	CLEANUP_SIZE	1024
71 
72 extern int nsvc_xdrs;
73 extern int __rpc_connmaxrec;
74 extern int __rpc_irtimeout;
75 
76 extern SVCXPRT	**svc_xports;
77 extern int	__td_setnodelay(int);
78 extern bool_t	__xdrrec_getbytes_nonblock(XDR *, enum xprt_stat *);
79 extern bool_t	__xdrrec_set_conn_nonblock(XDR *, uint32_t);
80 extern int	__rpc_legal_connmaxrec(int);
81 /* Structure used to initialize SVC_XP_AUTH(xprt).svc_ah_ops. */
82 extern struct svc_auth_ops svc_auth_any_ops;
83 extern void	__xprt_unregister_private(const SVCXPRT *, bool_t);
84 
85 static struct xp_ops 	*svc_vc_ops(void);
86 static struct xp_ops 	*svc_vc_rendezvous_ops(void);
87 static void		svc_vc_destroy(SVCXPRT *);
88 static bool_t		svc_vc_nonblock(SVCXPRT *, SVCXPRT *);
89 static int		read_vc(SVCXPRT *, caddr_t, int);
90 static int		write_vc(SVCXPRT *, caddr_t, int);
91 static SVCXPRT		*makefd_xprt(int, uint_t, uint_t, t_scalar_t, char *);
92 static void		update_nonblock_timestamps(SVCXPRT *);
93 
94 struct cf_rendezvous { /* kept in xprt->xp_p1 for rendezvouser */
95 	uint_t sendsize;
96 	uint_t recvsize;
97 	struct t_call *t_call;
98 	struct t_bind *t_bind;
99 	t_scalar_t cf_tsdu;
100 	char *cf_cache;
101 	int tcp_flag;
102 	int tcp_keepalive;
103 	int cf_connmaxrec;
104 };
105 
106 struct cf_conn {	/* kept in xprt->xp_p1 for actual connection */
107 	uint_t sendsize;
108 	uint_t recvsize;
109 	enum xprt_stat strm_stat;
110 	uint32_t x_id;
111 	t_scalar_t cf_tsdu;
112 	XDR xdrs;
113 	char *cf_cache;
114 	char verf_body[MAX_AUTH_BYTES];
115 	bool_t cf_conn_nonblock;
116 	time_t cf_conn_nonblock_timestamp;
117 };
118 
119 static int t_rcvall(int, char *, int);
120 static int t_rcvnonblock(SVCXPRT *, caddr_t, int);
121 static void svc_timeout_nonblock_xprt_and_LRU(bool_t);
122 
123 extern int __xdrrec_setfirst(XDR *);
124 extern int __xdrrec_resetfirst(XDR *);
125 extern int __is_xdrrec_first(XDR *);
126 
127 /*
128  * This is intended as a performance improvement on the old string handling
129  * stuff by read only moving data into the  text segment.
130  * Format = <routine> : <error>
131  */
132 
133 static const char errstring[] = " %s : %s";
134 
135 /* Routine names */
136 
137 static const char svc_vc_create_str[] = "svc_vc_create";
138 static const char svc_fd_create_str[] = "svc_fd_create";
139 static const char makefd_xprt_str[] = "svc_vc_create: makefd_xprt ";
140 static const char rendezvous_request_str[] = "rendezvous_request";
141 static const char svc_vc_fderr[] =
142 		"fd > FD_SETSIZE; Use rpc_control(RPC_SVC_USE_POLLFD,...);";
143 static const char do_accept_str[] = "do_accept";
144 
145 /* error messages */
146 
147 static const char no_mem_str[] = "out of memory";
148 static const char no_tinfo_str[] = "could not get transport information";
149 static const char no_fcntl_getfl_str[] = "could not get status flags and modes";
150 static const char no_nonblock_str[] = "could not set transport non-blocking";
151 
152 /*
153  * Used to determine whether the time-out logic should be executed.
154  */
155 static bool_t check_nonblock_timestamps = FALSE;
156 
157 void
svc_vc_xprtfree(SVCXPRT * xprt)158 svc_vc_xprtfree(SVCXPRT *xprt)
159 {
160 /* LINTED pointer alignment */
161 	SVCXPRT_EXT		*xt = xprt ? SVCEXT(xprt) : NULL;
162 	struct cf_rendezvous	*r = xprt ?
163 /* LINTED pointer alignment */
164 	    (struct cf_rendezvous *)xprt->xp_p1 : NULL;
165 
166 	if (!xprt)
167 		return;
168 
169 	if (xprt->xp_tp)
170 		free(xprt->xp_tp);
171 	if (xprt->xp_netid)
172 		free(xprt->xp_netid);
173 	if (xt && (xt->parent == NULL)) {
174 		if (xprt->xp_ltaddr.buf)
175 			free(xprt->xp_ltaddr.buf);
176 		if (xprt->xp_rtaddr.buf)
177 			free(xprt->xp_rtaddr.buf);
178 	}
179 	if (r) {
180 		if (r->t_call)
181 			(void) t_free((char *)r->t_call, T_CALL);
182 		if (r->t_bind)
183 			(void) t_free((char *)r->t_bind, T_BIND);
184 		free(r);
185 	}
186 	svc_xprt_free(xprt);
187 }
188 
189 /*
190  * Usage:
191  *	xprt = svc_vc_create(fd, sendsize, recvsize);
192  * Since connection streams do buffered io similar to stdio, the caller
193  * can specify how big the send and receive buffers are. If recvsize
194  * or sendsize are 0, defaults will be chosen.
195  * fd should be open and bound.
196  */
197 SVCXPRT *
svc_vc_create_private(int fd,uint_t sendsize,uint_t recvsize)198 svc_vc_create_private(int fd, uint_t sendsize, uint_t recvsize)
199 {
200 	struct cf_rendezvous *r;
201 	SVCXPRT *xprt;
202 	struct t_info tinfo;
203 
204 	if (RPC_FD_NOTIN_FDSET(fd)) {
205 		errno = EBADF;
206 		t_errno = TBADF;
207 		(void) syslog(LOG_ERR, errstring, svc_vc_create_str,
208 		    svc_vc_fderr);
209 		return (NULL);
210 	}
211 	if ((xprt = svc_xprt_alloc()) == NULL) {
212 		(void) syslog(LOG_ERR, errstring,
213 		    svc_vc_create_str, no_mem_str);
214 		return (NULL);
215 	}
216 /* LINTED pointer alignment */
217 	svc_flags(xprt) |= SVC_RENDEZVOUS;
218 
219 	r = calloc(1, sizeof (*r));
220 	if (r == NULL) {
221 		(void) syslog(LOG_ERR, errstring,
222 		    svc_vc_create_str, no_mem_str);
223 		svc_vc_xprtfree(xprt);
224 		return (NULL);
225 	}
226 	if (t_getinfo(fd, &tinfo) == -1) {
227 		char errorstr[100];
228 
229 		__tli_sys_strerror(errorstr, sizeof (errorstr),
230 		    t_errno, errno);
231 		(void) syslog(LOG_ERR, "%s : %s : %s",
232 		    svc_vc_create_str, no_tinfo_str, errorstr);
233 		free(r);
234 		svc_vc_xprtfree(xprt);
235 		return (NULL);
236 	}
237 	/*
238 	 * Find the receive and the send size
239 	 */
240 	r->sendsize = __rpc_get_t_size((int)sendsize, tinfo.tsdu);
241 	r->recvsize = __rpc_get_t_size((int)recvsize, tinfo.tsdu);
242 	if ((r->sendsize == 0) || (r->recvsize == 0)) {
243 		syslog(LOG_ERR,
244 		    "svc_vc_create:  transport does not support "
245 		    "data transfer");
246 		free(r);
247 		svc_vc_xprtfree(xprt);
248 		return (NULL);
249 	}
250 
251 /* LINTED pointer alignment */
252 	r->t_call = (struct t_call *)t_alloc(fd, T_CALL, T_ADDR | T_OPT);
253 	if (r->t_call == NULL) {
254 		(void) syslog(LOG_ERR, errstring,
255 		    svc_vc_create_str, no_mem_str);
256 		free(r);
257 		svc_vc_xprtfree(xprt);
258 		return (NULL);
259 	}
260 
261 /* LINTED pointer alignment */
262 	r->t_bind = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR);
263 	if (r->t_bind == NULL) {
264 		(void) syslog(LOG_ERR, errstring,
265 		    svc_vc_create_str, no_mem_str);
266 		(void) t_free((char *)r->t_call, T_CALL);
267 		free(r);
268 		svc_vc_xprtfree(xprt);
269 		return (NULL);
270 	}
271 
272 	r->cf_tsdu = tinfo.tsdu;
273 	r->tcp_flag = FALSE;
274 	r->tcp_keepalive = FALSE;
275 	r->cf_connmaxrec = __rpc_connmaxrec;
276 	xprt->xp_fd = fd;
277 	xprt->xp_p1 = (caddr_t)r;
278 	xprt->xp_p2 = NULL;
279 	xprt->xp_verf = _null_auth;
280 	xprt->xp_ops = svc_vc_rendezvous_ops();
281 /* LINTED pointer alignment */
282 	SVC_XP_AUTH(xprt).svc_ah_ops = svc_auth_any_ops;
283 /* LINTED pointer alignment */
284 	SVC_XP_AUTH(xprt).svc_ah_private = NULL;
285 
286 	return (xprt);
287 }
288 
289 SVCXPRT *
svc_vc_create(const int fd,const uint_t sendsize,const uint_t recvsize)290 svc_vc_create(const int fd, const uint_t sendsize, const uint_t recvsize)
291 {
292 	SVCXPRT *xprt;
293 
294 	if ((xprt = svc_vc_create_private(fd, sendsize, recvsize)) != NULL)
295 		xprt_register(xprt);
296 	return (xprt);
297 }
298 
299 SVCXPRT *
svc_vc_xprtcopy(SVCXPRT * parent)300 svc_vc_xprtcopy(SVCXPRT *parent)
301 {
302 	SVCXPRT			*xprt;
303 	struct cf_rendezvous	*r, *pr;
304 	int			fd = parent->xp_fd;
305 
306 	if ((xprt = svc_xprt_alloc()) == NULL)
307 		return (NULL);
308 
309 /* LINTED pointer alignment */
310 	SVCEXT(xprt)->parent = parent;
311 /* LINTED pointer alignment */
312 	SVCEXT(xprt)->flags = SVCEXT(parent)->flags;
313 
314 	xprt->xp_fd = fd;
315 	xprt->xp_ops = svc_vc_rendezvous_ops();
316 	if (parent->xp_tp) {
317 		xprt->xp_tp = (char *)strdup(parent->xp_tp);
318 		if (xprt->xp_tp == NULL) {
319 			syslog(LOG_ERR, "svc_vc_xprtcopy: strdup failed");
320 			svc_vc_xprtfree(xprt);
321 			return (NULL);
322 		}
323 	}
324 	if (parent->xp_netid) {
325 		xprt->xp_netid = (char *)strdup(parent->xp_netid);
326 		if (xprt->xp_netid == NULL) {
327 			syslog(LOG_ERR, "svc_vc_xprtcopy: strdup failed");
328 			if (xprt->xp_tp)
329 				free(xprt->xp_tp);
330 			svc_vc_xprtfree(xprt);
331 			return (NULL);
332 		}
333 	}
334 
335 	/*
336 	 * can share both local and remote address
337 	 */
338 	xprt->xp_ltaddr = parent->xp_ltaddr;
339 	xprt->xp_rtaddr = parent->xp_rtaddr; /* XXX - not used for rendezvous */
340 	xprt->xp_type = parent->xp_type;
341 	xprt->xp_verf = parent->xp_verf;
342 
343 	if ((r = calloc(1, sizeof (*r))) == NULL) {
344 		svc_vc_xprtfree(xprt);
345 		return (NULL);
346 	}
347 	xprt->xp_p1 = (caddr_t)r;
348 /* LINTED pointer alignment */
349 	pr = (struct cf_rendezvous *)parent->xp_p1;
350 	r->sendsize = pr->sendsize;
351 	r->recvsize = pr->recvsize;
352 	r->cf_tsdu = pr->cf_tsdu;
353 	r->cf_cache = pr->cf_cache;
354 	r->tcp_flag = pr->tcp_flag;
355 	r->tcp_keepalive = pr->tcp_keepalive;
356 	r->cf_connmaxrec = pr->cf_connmaxrec;
357 /* LINTED pointer alignment */
358 	r->t_call = (struct t_call *)t_alloc(fd, T_CALL, T_ADDR | T_OPT);
359 	if (r->t_call == NULL) {
360 		svc_vc_xprtfree(xprt);
361 		return (NULL);
362 	}
363 /* LINTED pointer alignment */
364 	r->t_bind = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR);
365 	if (r->t_bind == NULL) {
366 		svc_vc_xprtfree(xprt);
367 		return (NULL);
368 	}
369 
370 	return (xprt);
371 }
372 
373 /*
374  * XXX : Used for setting flag to indicate that this is TCP
375  */
376 
377 /*ARGSUSED*/
378 int
__svc_vc_setflag(SVCXPRT * xprt,int flag)379 __svc_vc_setflag(SVCXPRT *xprt, int flag)
380 {
381 	struct cf_rendezvous *r;
382 
383 /* LINTED pointer alignment */
384 	r = (struct cf_rendezvous *)xprt->xp_p1;
385 	r->tcp_flag = TRUE;
386 	return (1);
387 }
388 
389 /*
390  * used for the actual connection.
391  */
392 SVCXPRT *
svc_fd_create_private(int fd,uint_t sendsize,uint_t recvsize)393 svc_fd_create_private(int fd, uint_t sendsize, uint_t recvsize)
394 {
395 	struct t_info tinfo;
396 	SVCXPRT *dummy;
397 	struct netbuf tres = {0};
398 
399 	if (RPC_FD_NOTIN_FDSET(fd)) {
400 		errno = EBADF;
401 		t_errno = TBADF;
402 		(void) syslog(LOG_ERR, errstring,
403 		    svc_fd_create_str, svc_vc_fderr);
404 		return (NULL);
405 	}
406 	if (t_getinfo(fd, &tinfo) == -1) {
407 		char errorstr[100];
408 
409 		__tli_sys_strerror(errorstr, sizeof (errorstr),
410 		    t_errno, errno);
411 		(void) syslog(LOG_ERR, "%s : %s : %s",
412 		    svc_fd_create_str, no_tinfo_str, errorstr);
413 		return (NULL);
414 	}
415 	/*
416 	 * Find the receive and the send size
417 	 */
418 	sendsize = __rpc_get_t_size((int)sendsize, tinfo.tsdu);
419 	recvsize = __rpc_get_t_size((int)recvsize, tinfo.tsdu);
420 	if ((sendsize == 0) || (recvsize == 0)) {
421 		syslog(LOG_ERR, errstring, svc_fd_create_str,
422 		    "transport does not support data transfer");
423 		return (NULL);
424 	}
425 	dummy = makefd_xprt(fd, sendsize, recvsize, tinfo.tsdu, NULL);
426 				/* NULL signifies no dup cache */
427 	/* Assign the local bind address */
428 	if (t_getname(fd, &tres, LOCALNAME) == -1)
429 		tres.len = 0;
430 	dummy->xp_ltaddr = tres;
431 	/* Fill in type of service */
432 	dummy->xp_type = tinfo.servtype;
433 	return (dummy);
434 }
435 
436 SVCXPRT *
svc_fd_create(const int fd,const uint_t sendsize,const uint_t recvsize)437 svc_fd_create(const int fd, const uint_t sendsize, const uint_t recvsize)
438 {
439 	SVCXPRT *xprt;
440 
441 	if ((xprt = svc_fd_create_private(fd, sendsize, recvsize)) != NULL)
442 		xprt_register(xprt);
443 	return (xprt);
444 }
445 
446 void
svc_fd_xprtfree(SVCXPRT * xprt)447 svc_fd_xprtfree(SVCXPRT *xprt)
448 {
449 /* LINTED pointer alignment */
450 	SVCXPRT_EXT	*xt = xprt ? SVCEXT(xprt) : NULL;
451 /* LINTED pointer alignment */
452 	struct cf_conn	*cd = xprt ? (struct cf_conn *)xprt->xp_p1 : NULL;
453 
454 	if (!xprt)
455 		return;
456 
457 	if (xprt->xp_tp)
458 		free(xprt->xp_tp);
459 	if (xprt->xp_netid)
460 		free(xprt->xp_netid);
461 	if (xt && (xt->parent == NULL)) {
462 		if (xprt->xp_ltaddr.buf)
463 			free(xprt->xp_ltaddr.buf);
464 		if (xprt->xp_rtaddr.buf)
465 			free(xprt->xp_rtaddr.buf);
466 	}
467 	if (cd) {
468 		XDR_DESTROY(&(cd->xdrs));
469 		free(cd);
470 	}
471 	if (xt && (xt->parent == NULL) && xprt->xp_p2) {
472 /* LINTED pointer alignment */
473 		free(((struct netbuf *)xprt->xp_p2)->buf);
474 		free(xprt->xp_p2);
475 	}
476 	svc_xprt_free(xprt);
477 }
478 
479 static SVCXPRT *
makefd_xprt(int fd,uint_t sendsize,uint_t recvsize,t_scalar_t tsdu,char * cache)480 makefd_xprt(int fd, uint_t sendsize, uint_t recvsize, t_scalar_t tsdu,
481     char *cache)
482 {
483 	SVCXPRT *xprt;
484 	struct cf_conn *cd;
485 
486 	xprt = svc_xprt_alloc();
487 	if (xprt == NULL) {
488 		(void) syslog(LOG_ERR, errstring, makefd_xprt_str, no_mem_str);
489 		return (NULL);
490 	}
491 /* LINTED pointer alignment */
492 	svc_flags(xprt) |= SVC_CONNECTION;
493 
494 	cd = malloc(sizeof (struct cf_conn));
495 	if (cd == NULL) {
496 		(void) syslog(LOG_ERR, errstring, makefd_xprt_str, no_mem_str);
497 		svc_fd_xprtfree(xprt);
498 		return (NULL);
499 	}
500 	cd->sendsize = sendsize;
501 	cd->recvsize = recvsize;
502 	cd->strm_stat = XPRT_IDLE;
503 	cd->cf_tsdu = tsdu;
504 	cd->cf_cache = cache;
505 	cd->cf_conn_nonblock = FALSE;
506 	cd->cf_conn_nonblock_timestamp = 0;
507 	cd->xdrs.x_ops = NULL;
508 	xdrrec_create(&(cd->xdrs), sendsize, 0, (caddr_t)xprt,
509 	    (int(*)())NULL, (int(*)(void *, char *, int))write_vc);
510 	if (cd->xdrs.x_ops == NULL) {
511 		(void) syslog(LOG_ERR, errstring, makefd_xprt_str, no_mem_str);
512 		free(cd);
513 		svc_fd_xprtfree(xprt);
514 		return (NULL);
515 	}
516 
517 	(void) rw_wrlock(&svc_fd_lock);
518 	if (svc_xdrs == NULL) {
519 		svc_xdrs = calloc(FD_INCREMENT,  sizeof (XDR *));
520 		if (svc_xdrs == NULL) {
521 			(void) syslog(LOG_ERR, errstring, makefd_xprt_str,
522 			    no_mem_str);
523 			XDR_DESTROY(&(cd->xdrs));
524 			free(cd);
525 			svc_fd_xprtfree(xprt);
526 			(void) rw_unlock(&svc_fd_lock);
527 			return (NULL);
528 		}
529 		nsvc_xdrs = FD_INCREMENT;
530 	}
531 
532 	while (fd >= nsvc_xdrs) {
533 		XDR **tmp_xdrs = realloc(svc_xdrs,
534 		    sizeof (XDR *) * (nsvc_xdrs + FD_INCREMENT));
535 		if (tmp_xdrs == NULL) {
536 			(void) syslog(LOG_ERR, errstring, makefd_xprt_str,
537 			    no_mem_str);
538 			XDR_DESTROY(&(cd->xdrs));
539 			free(cd);
540 			svc_fd_xprtfree(xprt);
541 			(void) rw_unlock(&svc_fd_lock);
542 			return (NULL);
543 		}
544 
545 		svc_xdrs = tmp_xdrs;
546 		/* initial the new array to 0 from the last allocated array */
547 		(void) memset(&svc_xdrs[nsvc_xdrs], 0,
548 		    sizeof (XDR *) * FD_INCREMENT);
549 		nsvc_xdrs += FD_INCREMENT;
550 	}
551 
552 	if (svc_xdrs[fd] != NULL) {
553 		XDR_DESTROY(svc_xdrs[fd]);
554 	} else if ((svc_xdrs[fd] = malloc(sizeof (XDR))) == NULL) {
555 		(void) syslog(LOG_ERR, errstring, makefd_xprt_str, no_mem_str);
556 		XDR_DESTROY(&(cd->xdrs));
557 		free(cd);
558 		svc_fd_xprtfree(xprt);
559 		(void) rw_unlock(&svc_fd_lock);
560 		return (NULL);
561 	}
562 	(void) memset(svc_xdrs[fd], 0, sizeof (XDR));
563 	xdrrec_create(svc_xdrs[fd], 0, recvsize, (caddr_t)xprt,
564 	    (int(*)(void *, char *, int))read_vc, (int(*)())NULL);
565 	if (svc_xdrs[fd]->x_ops == NULL) {
566 		free(svc_xdrs[fd]);
567 		svc_xdrs[fd] = NULL;
568 		XDR_DESTROY(&(cd->xdrs));
569 		free(cd);
570 		svc_fd_xprtfree(xprt);
571 		(void) rw_unlock(&svc_fd_lock);
572 		return (NULL);
573 	}
574 	(void) rw_unlock(&svc_fd_lock);
575 
576 	xprt->xp_p1 = (caddr_t)cd;
577 	xprt->xp_p2 = NULL;
578 	xprt->xp_verf.oa_base = cd->verf_body;
579 	xprt->xp_ops = svc_vc_ops();	/* truely deals with calls */
580 	xprt->xp_fd = fd;
581 	return (xprt);
582 }
583 
584 SVCXPRT *
svc_fd_xprtcopy(SVCXPRT * parent)585 svc_fd_xprtcopy(SVCXPRT *parent)
586 {
587 	SVCXPRT			*xprt;
588 	struct cf_conn		*cd, *pcd;
589 
590 	if ((xprt = svc_xprt_alloc()) == NULL)
591 		return (NULL);
592 
593 /* LINTED pointer alignment */
594 	SVCEXT(xprt)->parent = parent;
595 /* LINTED pointer alignment */
596 	SVCEXT(xprt)->flags = SVCEXT(parent)->flags;
597 
598 	xprt->xp_fd = parent->xp_fd;
599 	xprt->xp_ops = svc_vc_ops();
600 	if (parent->xp_tp) {
601 		xprt->xp_tp = (char *)strdup(parent->xp_tp);
602 		if (xprt->xp_tp == NULL) {
603 			syslog(LOG_ERR, "svc_fd_xprtcopy: strdup failed");
604 			svc_fd_xprtfree(xprt);
605 			return (NULL);
606 		}
607 	}
608 	if (parent->xp_netid) {
609 		xprt->xp_netid = (char *)strdup(parent->xp_netid);
610 		if (xprt->xp_netid == NULL) {
611 			syslog(LOG_ERR, "svc_fd_xprtcopy: strdup failed");
612 			if (xprt->xp_tp)
613 				free(xprt->xp_tp);
614 			svc_fd_xprtfree(xprt);
615 			return (NULL);
616 		}
617 	}
618 	/*
619 	 * share local and remote addresses with parent
620 	 */
621 	xprt->xp_ltaddr = parent->xp_ltaddr;
622 	xprt->xp_rtaddr = parent->xp_rtaddr;
623 	xprt->xp_type = parent->xp_type;
624 
625 	if ((cd = malloc(sizeof (struct cf_conn))) == NULL) {
626 		svc_fd_xprtfree(xprt);
627 		return (NULL);
628 	}
629 /* LINTED pointer alignment */
630 	pcd = (struct cf_conn *)parent->xp_p1;
631 	cd->sendsize = pcd->sendsize;
632 	cd->recvsize = pcd->recvsize;
633 	cd->strm_stat = pcd->strm_stat;
634 	cd->x_id = pcd->x_id;
635 	cd->cf_tsdu = pcd->cf_tsdu;
636 	cd->cf_cache = pcd->cf_cache;
637 	cd->cf_conn_nonblock = pcd->cf_conn_nonblock;
638 	cd->cf_conn_nonblock_timestamp = pcd->cf_conn_nonblock_timestamp;
639 	cd->xdrs.x_ops = NULL;
640 	xdrrec_create(&(cd->xdrs), cd->sendsize, 0, (caddr_t)xprt,
641 	    (int(*)())NULL, (int(*)(void *, char *, int))write_vc);
642 	if (cd->xdrs.x_ops == NULL) {
643 		free(cd);
644 		svc_fd_xprtfree(xprt);
645 		return (NULL);
646 	}
647 	xprt->xp_verf.oa_base = cd->verf_body;
648 	xprt->xp_p1 = (char *)cd;
649 	xprt->xp_p2 = parent->xp_p2;	/* shared */
650 
651 	return (xprt);
652 }
653 
654 static void do_accept();
655 
656 /*
657  * This routine is called by svc_getreqset(), when a packet is recd.
658  * The listener process creates another end point on which the actual
659  * connection is carried. It returns FALSE to indicate that it was
660  * not a rpc packet (falsely though), but as a side effect creates
661  * another endpoint which is also registered, which then always
662  * has a request ready to be served.
663  */
664 /* ARGSUSED1 */
665 static bool_t
rendezvous_request(SVCXPRT * xprt,struct rpc_msg * msg)666 rendezvous_request(SVCXPRT *xprt, struct rpc_msg *msg)
667 {
668 	struct cf_rendezvous *r;
669 	char *tpname = NULL;
670 	char devbuf[256];
671 
672 /* LINTED pointer alignment */
673 	r = (struct cf_rendezvous *)xprt->xp_p1;
674 
675 again:
676 	switch (t_look(xprt->xp_fd)) {
677 	case T_DISCONNECT:
678 		(void) t_rcvdis(xprt->xp_fd, NULL);
679 		return (FALSE);
680 
681 	case T_LISTEN:
682 
683 		if (t_listen(xprt->xp_fd, r->t_call) == -1) {
684 			if ((t_errno == TSYSERR) && (errno == EINTR))
685 				goto again;
686 
687 			if (t_errno == TLOOK) {
688 				if (t_look(xprt->xp_fd) == T_DISCONNECT)
689 					(void) t_rcvdis(xprt->xp_fd, NULL);
690 			}
691 			return (FALSE);
692 		}
693 		break;
694 	default:
695 		return (FALSE);
696 	}
697 	/*
698 	 * Now create another endpoint, and accept the connection
699 	 * on it.
700 	 */
701 
702 	if (xprt->xp_tp) {
703 		tpname = xprt->xp_tp;
704 	} else {
705 		/*
706 		 * If xprt->xp_tp is NULL, then try to extract the
707 		 * transport protocol information from the transport
708 		 * protcol corresponding to xprt->xp_fd
709 		 */
710 		struct netconfig *nconf;
711 		tpname = devbuf;
712 		if ((nconf = __rpcfd_to_nconf(xprt->xp_fd, xprt->xp_type))
713 		    == NULL) {
714 			(void) syslog(LOG_ERR, errstring,
715 			    rendezvous_request_str, "no suitable transport");
716 			goto err;
717 		}
718 		(void) strcpy(tpname, nconf->nc_device);
719 		freenetconfigent(nconf);
720 	}
721 
722 	do_accept(xprt->xp_fd, tpname, xprt->xp_netid, r);
723 
724 err:
725 	return (FALSE); /* there is never an rpc msg to be processed */
726 }
727 
728 struct entry {
729 	struct t_call *t_call;
730 	struct entry *next;
731 };
732 
733 static void
do_accept(int srcfd,char * tpname,char * netid,struct cf_rendezvous * r)734 do_accept(int srcfd, char *tpname, char *netid, struct cf_rendezvous *r)
735 {
736 	int	destfd;
737 	struct t_call	t_call;
738 	struct t_call	*tcp2 = NULL;
739 	struct t_info	tinfo;
740 	SVCXPRT	*xprt;
741 	SVCXPRT	*xprt_srcfd;
742 	struct entry *head = NULL;
743 	struct entry *tail = NULL;
744 	struct entry *e;
745 	struct t_call *tcp;
746 
747 restart:
748 	tcp = r->t_call;
749 
750 	destfd = t_open(tpname, O_RDWR, &tinfo);
751 	if (check_nonblock_timestamps) {
752 		if (destfd == -1 && t_errno == TSYSERR && errno == EMFILE) {
753 			/*
754 			 * Since there are nonblocking connection xprts and
755 			 * too many open files, the LRU connection xprt should
756 			 * get destroyed in case an attacker has been creating
757 			 * many connections.
758 			 */
759 			(void) mutex_lock(&svc_mutex);
760 			svc_timeout_nonblock_xprt_and_LRU(TRUE);
761 			(void) mutex_unlock(&svc_mutex);
762 			destfd = t_open(tpname, O_RDWR, &tinfo);
763 		} else {
764 			/*
765 			 * Destroy/timeout all nonblock connection xprts
766 			 * that have not had recent activity.
767 			 * Do not destroy LRU xprt unless there are
768 			 * too many open files.
769 			 */
770 			(void) mutex_lock(&svc_mutex);
771 			svc_timeout_nonblock_xprt_and_LRU(FALSE);
772 			(void) mutex_unlock(&svc_mutex);
773 		}
774 	}
775 	if (destfd == -1) {
776 		char errorstr[100];
777 
778 		__tli_sys_strerror(errorstr, sizeof (errorstr), t_errno, errno);
779 		(void) syslog(LOG_ERR, "%s : %s : %s", do_accept_str,
780 		    "can't open connection", errorstr);
781 		(void) t_snddis(srcfd, tcp);
782 
783 		goto end;
784 	}
785 	if (RPC_FD_NOTIN_FDSET(destfd)) {
786 		(void) syslog(LOG_ERR, errstring, do_accept_str, svc_vc_fderr);
787 		(void) t_close(destfd);
788 		(void) t_snddis(srcfd, tcp);
789 
790 		goto end;
791 	}
792 	(void) fcntl(destfd, F_SETFD, FD_CLOEXEC);
793 	if ((tinfo.servtype != T_COTS) && (tinfo.servtype != T_COTS_ORD)) {
794 		/* Not a connection oriented mode */
795 		(void) syslog(LOG_ERR, errstring, do_accept_str,
796 		    "do_accept:  illegal transport");
797 		(void) t_close(destfd);
798 		(void) t_snddis(srcfd, tcp);
799 
800 		goto end;
801 	}
802 
803 
804 	if (t_bind(destfd, NULL, r->t_bind) == -1) {
805 		char errorstr[100];
806 
807 		__tli_sys_strerror(errorstr, sizeof (errorstr), t_errno, errno);
808 		(void) syslog(LOG_ERR, " %s : %s : %s", do_accept_str,
809 		    "t_bind failed", errorstr);
810 		(void) t_close(destfd);
811 		(void) t_snddis(srcfd, tcp);
812 
813 		goto end;
814 	}
815 
816 	if (r->tcp_flag)	/* if TCP, set NODELAY flag */
817 		(void) __td_setnodelay(destfd);
818 
819 	/*
820 	 * This connection is not listening, hence no need to set
821 	 * the qlen.
822 	 */
823 
824 	/*
825 	 * XXX: The local transport chokes on its own listen
826 	 * options so we zero them for now
827 	 */
828 	t_call = *tcp;
829 	t_call.opt.len = 0;
830 	t_call.opt.maxlen = 0;
831 	t_call.opt.buf = NULL;
832 
833 	while (t_accept(srcfd, destfd, &t_call) == -1) {
834 		char errorstr[100];
835 
836 		switch (t_errno) {
837 		case TLOOK:
838 again:
839 			switch (t_look(srcfd)) {
840 			case T_CONNECT:
841 			case T_DATA:
842 			case T_EXDATA:
843 				/* this should not happen */
844 				break;
845 
846 			case T_DISCONNECT:
847 				(void) t_rcvdis(srcfd, NULL);
848 				break;
849 
850 			case T_LISTEN:
851 				if (tcp2 == NULL)
852 /* LINTED pointer alignment */
853 					tcp2 = (struct t_call *)t_alloc(srcfd,
854 					    T_CALL, T_ADDR | T_OPT);
855 				if (tcp2 == NULL) {
856 					(void) t_close(destfd);
857 					(void) t_snddis(srcfd, tcp);
858 					syslog(LOG_ERR, errstring,
859 					    do_accept_str, no_mem_str);
860 
861 					goto end;
862 				}
863 				if (t_listen(srcfd, tcp2) == -1) {
864 					switch (t_errno) {
865 					case TSYSERR:
866 						if (errno == EINTR)
867 							goto again;
868 						break;
869 
870 					case TLOOK:
871 						goto again;
872 					}
873 					(void) t_close(destfd);
874 					(void) t_snddis(srcfd, tcp);
875 
876 					goto end;
877 				}
878 
879 				e = malloc(sizeof (struct entry));
880 				if (e == NULL) {
881 					(void) t_snddis(srcfd, tcp2);
882 					(void) t_free((char *)tcp2, T_CALL);
883 					tcp2 = NULL;
884 
885 					break;
886 				}
887 
888 				e->t_call = tcp2;
889 				tcp2 = NULL;
890 				e->next = NULL;
891 
892 				if (head == NULL)
893 					head = e;
894 				else
895 					tail->next = e;
896 				tail = e;
897 
898 				break;
899 
900 			case T_ORDREL:
901 				(void) t_rcvrel(srcfd);
902 				(void) t_sndrel(srcfd);
903 				break;
904 			}
905 			break;
906 
907 		case TBADSEQ:
908 			/*
909 			 * This can happen if the remote side has
910 			 * disconnected before the connection is
911 			 * accepted.  In this case, a disconnect
912 			 * should not be sent on srcfd (important!
913 			 * the listening fd will be hosed otherwise!).
914 			 * This error is not logged since this is an
915 			 * operational situation that is recoverable.
916 			 */
917 			(void) t_close(destfd);
918 
919 			goto end;
920 
921 		case TOUTSTATE:
922 			/*
923 			 * This can happen if the t_rcvdis() or t_rcvrel()/
924 			 * t_sndrel() put srcfd into the T_IDLE state.
925 			 */
926 			if (t_getstate(srcfd) == T_IDLE) {
927 				(void) t_close(destfd);
928 				(void) t_snddis(srcfd, tcp);
929 
930 				goto end;
931 			}
932 			/* FALLTHROUGH */
933 
934 		default:
935 			__tli_sys_strerror(errorstr, sizeof (errorstr),
936 			    t_errno, errno);
937 			(void) syslog(LOG_ERR,
938 			    "cannot accept connection:  %s (current state %d)",
939 			    errorstr, t_getstate(srcfd));
940 			(void) t_close(destfd);
941 			(void) t_snddis(srcfd, tcp);
942 
943 			goto end;
944 		}
945 	}
946 
947 	if (r->tcp_flag && r->tcp_keepalive) {
948 		char *option;
949 		char *option_ret;
950 
951 		option = malloc(sizeof (struct opthdr) + sizeof (int));
952 		option_ret = malloc(sizeof (struct opthdr) + sizeof (int));
953 		if (option != NULL && option_ret != NULL) {
954 			struct opthdr *opt;
955 			struct t_optmgmt optreq, optret;
956 			int *p_optval;
957 
958 			/* LINTED pointer cast */
959 			opt = (struct opthdr *)option;
960 			opt->level = SOL_SOCKET;
961 			opt->name  = SO_KEEPALIVE;
962 			opt->len  = sizeof (int);
963 			p_optval = (int *)(opt + 1);
964 			*p_optval = SO_KEEPALIVE;
965 			optreq.opt.maxlen = optreq.opt.len =
966 			    sizeof (struct opthdr) + sizeof (int);
967 			optreq.opt.buf = (char *)option;
968 			optreq.flags = T_NEGOTIATE;
969 			optret.opt.maxlen = sizeof (struct opthdr)
970 			    + sizeof (int);
971 			optret.opt.buf = (char *)option_ret;
972 			(void) t_optmgmt(destfd, &optreq, &optret);
973 		}
974 		free(option);
975 		free(option_ret);
976 	}
977 
978 
979 	/*
980 	 * make a new transporter
981 	 */
982 	xprt = makefd_xprt(destfd, r->sendsize, r->recvsize, r->cf_tsdu,
983 	    r->cf_cache);
984 	if (xprt == NULL) {
985 		/*
986 		 * makefd_xprt() returns a NULL xprt only when
987 		 * it's out of memory.
988 		 */
989 		goto memerr;
990 	}
991 
992 	/*
993 	 * Copy the new local and remote bind information
994 	 */
995 
996 	xprt->xp_rtaddr.len = tcp->addr.len;
997 	xprt->xp_rtaddr.maxlen = tcp->addr.len;
998 	if ((xprt->xp_rtaddr.buf = malloc(tcp->addr.len)) == NULL)
999 		goto memerr;
1000 	(void) memcpy(xprt->xp_rtaddr.buf, tcp->addr.buf, tcp->addr.len);
1001 
1002 	if (strcmp(netid, "tcp") == 0) {
1003 		xprt->xp_ltaddr.maxlen = sizeof (struct sockaddr_in);
1004 		if ((xprt->xp_ltaddr.buf =
1005 		    malloc(xprt->xp_ltaddr.maxlen)) == NULL)
1006 			goto memerr;
1007 		if (t_getname(destfd, &xprt->xp_ltaddr, LOCALNAME) < 0) {
1008 			(void) syslog(LOG_ERR,
1009 			    "do_accept: t_getname for tcp failed!");
1010 			goto xprt_err;
1011 		}
1012 	} else if (strcmp(netid, "tcp6") == 0) {
1013 		xprt->xp_ltaddr.maxlen = sizeof (struct sockaddr_in6);
1014 		if ((xprt->xp_ltaddr.buf =
1015 		    malloc(xprt->xp_ltaddr.maxlen)) == NULL)
1016 			goto memerr;
1017 		if (t_getname(destfd, &xprt->xp_ltaddr, LOCALNAME) < 0) {
1018 			(void) syslog(LOG_ERR,
1019 			    "do_accept: t_getname for tcp6 failed!");
1020 			goto xprt_err;
1021 		}
1022 	}
1023 
1024 	xprt->xp_tp = strdup(tpname);
1025 	xprt->xp_netid = strdup(netid);
1026 	if ((xprt->xp_tp == NULL) ||
1027 	    (xprt->xp_netid == NULL)) {
1028 		goto memerr;
1029 	}
1030 	if (tcp->opt.len > 0) {
1031 		xprt->xp_p2 = malloc(sizeof (struct netbuf));
1032 
1033 		if (xprt->xp_p2 != NULL) {
1034 /* LINTED pointer alignment */
1035 			struct netbuf *netptr = (struct netbuf *)xprt->xp_p2;
1036 
1037 			netptr->len = tcp->opt.len;
1038 			netptr->maxlen = tcp->opt.len;
1039 			if ((netptr->buf = malloc(tcp->opt.len)) == NULL)
1040 				goto memerr;
1041 			(void) memcpy(netptr->buf, tcp->opt.buf, tcp->opt.len);
1042 		} else
1043 			goto memerr;
1044 	}
1045 /*	(void) ioctl(destfd, I_POP, NULL);    */
1046 
1047 	/*
1048 	 * If a nonblocked connection fd has been requested,
1049 	 * perform the necessary operations.
1050 	 */
1051 	xprt_srcfd = svc_xports[srcfd];
1052 	/* LINTED pointer cast */
1053 	if (((struct cf_rendezvous *)(xprt_srcfd->xp_p1))->cf_connmaxrec) {
1054 		if (!svc_vc_nonblock(xprt_srcfd, xprt))
1055 			goto xprt_err;
1056 	}
1057 
1058 	/*
1059 	 * Copy the call back declared for the service to the current
1060 	 * connection
1061 	 */
1062 	xprt->xp_closeclnt = xprt_srcfd->xp_closeclnt;
1063 	xprt_register(xprt);
1064 
1065 end:
1066 	if (head != NULL) {
1067 		(void) t_free((char *)r->t_call, T_CALL);
1068 		r->t_call = head->t_call;
1069 		e = head;
1070 		head = head->next;
1071 		free(e);
1072 		goto restart;
1073 	}
1074 
1075 	if (tcp2)
1076 		(void) t_free((char *)tcp2, T_CALL);
1077 
1078 	return;
1079 
1080 memerr:
1081 	(void) syslog(LOG_ERR, errstring, do_accept_str, no_mem_str);
1082 xprt_err:
1083 	if (xprt)
1084 		svc_vc_destroy(xprt);
1085 	(void) t_close(destfd);
1086 
1087 	goto end;
1088 }
1089 
1090 /*
1091  * This routine performs the necessary fcntl() operations to create
1092  * a nonblocked connection fd.
1093  * It also adjusts the sizes and allocates the buffer
1094  * for the nonblocked operations, and updates the associated
1095  * timestamp field in struct cf_conn for timeout bookkeeping.
1096  */
1097 static bool_t
svc_vc_nonblock(SVCXPRT * xprt_rendezvous,SVCXPRT * xprt_conn)1098 svc_vc_nonblock(SVCXPRT *xprt_rendezvous, SVCXPRT *xprt_conn)
1099 {
1100 	int nn;
1101 	int fdconn = xprt_conn->xp_fd;
1102 	struct cf_rendezvous *r =
1103 	    /* LINTED pointer cast */
1104 	    (struct cf_rendezvous *)xprt_rendezvous->xp_p1;
1105 	/* LINTED pointer cast */
1106 	struct cf_conn *cd = (struct cf_conn *)xprt_conn->xp_p1;
1107 	uint32_t maxrecsz;
1108 
1109 	if ((nn = fcntl(fdconn, F_GETFL, 0)) < 0) {
1110 		(void) syslog(LOG_ERR, "%s : %s : %m", do_accept_str,
1111 		    no_fcntl_getfl_str);
1112 		return (FALSE);
1113 	}
1114 
1115 	if (fcntl(fdconn, F_SETFL, nn|O_NONBLOCK) != 0) {
1116 		(void) syslog(LOG_ERR, "%s : %s : %m", do_accept_str,
1117 		    no_nonblock_str);
1118 		return (FALSE);
1119 	}
1120 
1121 	cd->cf_conn_nonblock = TRUE;
1122 	/*
1123 	 * If the max fragment size has not been set via
1124 	 * rpc_control(), use the default.
1125 	 */
1126 	if ((maxrecsz = r->cf_connmaxrec) == 0)
1127 		maxrecsz = r->recvsize;
1128 	/* Set XDR stream to use non-blocking semantics. */
1129 	if (__xdrrec_set_conn_nonblock(svc_xdrs[fdconn], maxrecsz)) {
1130 		check_nonblock_timestamps = TRUE;
1131 		update_nonblock_timestamps(xprt_conn);
1132 		return (TRUE);
1133 	}
1134 	return (FALSE);
1135 }
1136 
1137 /* ARGSUSED */
1138 static enum xprt_stat
rendezvous_stat(SVCXPRT * xprt)1139 rendezvous_stat(SVCXPRT *xprt)
1140 {
1141 	return (XPRT_IDLE);
1142 }
1143 
1144 static void
svc_vc_destroy(SVCXPRT * xprt)1145 svc_vc_destroy(SVCXPRT *xprt)
1146 {
1147 	(void) mutex_lock(&svc_mutex);
1148 	_svc_vc_destroy_private(xprt, TRUE);
1149 	(void) svc_timeout_nonblock_xprt_and_LRU(FALSE);
1150 	(void) mutex_unlock(&svc_mutex);
1151 }
1152 
1153 void
_svc_vc_destroy_private(SVCXPRT * xprt,bool_t lock_not_held)1154 _svc_vc_destroy_private(SVCXPRT *xprt, bool_t lock_not_held)
1155 {
1156 	if (svc_mt_mode != RPC_SVC_MT_NONE) {
1157 /* LINTED pointer alignment */
1158 		if (SVCEXT(xprt)->parent)
1159 /* LINTED pointer alignment */
1160 			xprt = SVCEXT(xprt)->parent;
1161 /* LINTED pointer alignment */
1162 		svc_flags(xprt) |= SVC_DEFUNCT;
1163 /* LINTED pointer alignment */
1164 		if (SVCEXT(xprt)->refcnt > 0)
1165 			return;
1166 	}
1167 
1168 	if (xprt->xp_closeclnt != NULL) {
1169 		svc_errorhandler_t cb = xprt->xp_closeclnt;
1170 
1171 		/*
1172 		 * Reset the pointer here to avoid reentrance on the same
1173 		 * SVCXPRT handle.
1174 		 */
1175 		xprt->xp_closeclnt = NULL;
1176 		cb(xprt, (xprt->xp_rtaddr.len != 0));
1177 	}
1178 
1179 	__xprt_unregister_private(xprt, lock_not_held);
1180 	(void) t_close(xprt->xp_fd);
1181 
1182 	if (svc_mt_mode != RPC_SVC_MT_NONE) {
1183 		svc_xprt_destroy(xprt);
1184 	} else {
1185 /* LINTED pointer alignment */
1186 		if (svc_type(xprt) == SVC_RENDEZVOUS)
1187 			svc_vc_xprtfree(xprt);
1188 		else
1189 			svc_fd_xprtfree(xprt);
1190 	}
1191 }
1192 
1193 /*ARGSUSED*/
1194 static bool_t
svc_vc_control(SVCXPRT * xprt,const uint_t rq,void * in)1195 svc_vc_control(SVCXPRT *xprt, const uint_t rq, void *in)
1196 {
1197 	switch (rq) {
1198 	case SVCSET_RECVERRHANDLER:
1199 		xprt->xp_closeclnt = (svc_errorhandler_t)in;
1200 		return (TRUE);
1201 	case SVCGET_RECVERRHANDLER:
1202 		*(svc_errorhandler_t *)in = xprt->xp_closeclnt;
1203 		return (TRUE);
1204 	case SVCGET_XID:
1205 		if (xprt->xp_p1 == NULL)
1206 			return (FALSE);
1207 		/* LINTED pointer alignment */
1208 		*(uint32_t *)in = ((struct cf_conn *)(xprt->xp_p1))->x_id;
1209 		return (TRUE);
1210 	default:
1211 		return (FALSE);
1212 	}
1213 }
1214 
1215 static bool_t
rendezvous_control(SVCXPRT * xprt,const uint_t rq,void * in)1216 rendezvous_control(SVCXPRT *xprt, const uint_t rq, void *in)
1217 {
1218 	struct cf_rendezvous *r;
1219 	int tmp;
1220 
1221 	switch (rq) {
1222 	case SVCSET_RECVERRHANDLER:
1223 		xprt->xp_closeclnt = (svc_errorhandler_t)in;
1224 		return (TRUE);
1225 	case SVCGET_RECVERRHANDLER:
1226 		*(svc_errorhandler_t *)in = xprt->xp_closeclnt;
1227 		return (TRUE);
1228 	case SVCSET_KEEPALIVE:
1229 		/* LINTED pointer cast */
1230 		r = (struct cf_rendezvous *)xprt->xp_p1;
1231 		if (r->tcp_flag) {
1232 			r->tcp_keepalive = (int)(intptr_t)in;
1233 			return (TRUE);
1234 		}
1235 		return (FALSE);
1236 	case SVCSET_CONNMAXREC:
1237 		/*
1238 		 * Override the default maximum record size, set via
1239 		 * rpc_control(), for this connection. Only appropriate
1240 		 * for connection oriented transports, but is ignored for
1241 		 * the connectionless case, so no need to check the
1242 		 * connection type here.
1243 		 */
1244 		/* LINTED pointer cast */
1245 		r = (struct cf_rendezvous *)xprt->xp_p1;
1246 		tmp = __rpc_legal_connmaxrec(*(int *)in);
1247 		if (r != 0 && tmp >= 0) {
1248 			r->cf_connmaxrec = tmp;
1249 			return (TRUE);
1250 		}
1251 		return (FALSE);
1252 	case SVCGET_CONNMAXREC:
1253 		/* LINTED pointer cast */
1254 		r = (struct cf_rendezvous *)xprt->xp_p1;
1255 		if (r != 0) {
1256 			*(int *)in = r->cf_connmaxrec;
1257 			return (TRUE);
1258 		}
1259 		return (FALSE);
1260 	case SVCGET_XID:	/* fall through for now */
1261 	default:
1262 		return (FALSE);
1263 	}
1264 }
1265 
1266 /*
1267  * All read operations timeout after 35 seconds.
1268  * A timeout is fatal for the connection.
1269  * update_nonblock_timestamps() is used for nonblocked
1270  * connection fds.
1271  */
1272 #define	WAIT_PER_TRY	35000	/* milliseconds */
1273 
1274 static  void
update_nonblock_timestamps(SVCXPRT * xprt_conn)1275 update_nonblock_timestamps(SVCXPRT *xprt_conn)
1276 {
1277 	struct timeval tv;
1278 	/* LINTED pointer cast */
1279 	struct cf_conn *cd = (struct cf_conn *)xprt_conn->xp_p1;
1280 
1281 	(void) gettimeofday(&tv, NULL);
1282 	cd->cf_conn_nonblock_timestamp = tv.tv_sec;
1283 }
1284 
1285 /*
1286  * reads data from the vc conection.
1287  * any error is fatal and the connection is closed.
1288  * (And a read of zero bytes is a half closed stream => error.)
1289  */
1290 static int
read_vc(SVCXPRT * xprt,caddr_t buf,int len)1291 read_vc(SVCXPRT *xprt, caddr_t buf, int len)
1292 {
1293 	int fd = xprt->xp_fd;
1294 	XDR *xdrs = svc_xdrs[fd];
1295 	struct pollfd pfd;
1296 	int ret;
1297 
1298 	/*
1299 	 * Make sure the connection is not already dead.
1300 	 */
1301 /* LINTED pointer alignment */
1302 	if (svc_failed(xprt))
1303 		return (-1);
1304 
1305 	/* LINTED pointer cast */
1306 	if (((struct cf_conn *)(xprt->xp_p1))->cf_conn_nonblock) {
1307 		/*
1308 		 * For nonblocked reads, only update the
1309 		 * timestamps to record the activity so the
1310 		 * connection will not be timedout.
1311 		 * Up to "len" bytes are requested.
1312 		 * If fewer than "len" bytes are received, the
1313 		 * connection is poll()ed again.
1314 		 * The poll() for the connection fd is performed
1315 		 * in the main poll() so that all outstanding fds
1316 		 * are polled rather than just the vc connection.
1317 		 * Polling on only the vc connection until the entire
1318 		 * fragment has been read can be exploited in
1319 		 * a Denial of Service Attack such as telnet <host> 111.
1320 		 */
1321 		if ((len = t_rcvnonblock(xprt, buf, len)) >= 0) {
1322 			if (len > 0) {
1323 				update_nonblock_timestamps(xprt);
1324 			}
1325 			return (len);
1326 		}
1327 		goto fatal_err;
1328 	}
1329 
1330 	if (!__is_xdrrec_first(xdrs)) {
1331 
1332 		pfd.fd = fd;
1333 		pfd.events = MASKVAL;
1334 
1335 		do {
1336 			if ((ret = poll(&pfd, 1, WAIT_PER_TRY)) <= 0) {
1337 				/*
1338 				 * If errno is EINTR, ERESTART, or EAGAIN
1339 				 * ignore error and repeat poll
1340 				 */
1341 				if (ret < 0 && (errno == EINTR ||
1342 				    errno == ERESTART || errno == EAGAIN))
1343 					continue;
1344 				goto fatal_err;
1345 			}
1346 		} while (pfd.revents == 0);
1347 		if (pfd.revents & POLLNVAL)
1348 			goto fatal_err;
1349 	}
1350 	(void) __xdrrec_resetfirst(xdrs);
1351 	if ((len = t_rcvall(fd, buf, len)) > 0) {
1352 		return (len);
1353 	}
1354 
1355 fatal_err:
1356 /* LINTED pointer alignment */
1357 	((struct cf_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED;
1358 /* LINTED pointer alignment */
1359 	svc_flags(xprt) |= SVC_FAILED;
1360 	return (-1);
1361 }
1362 
1363 /*
1364  * Requests up to "len" bytes of data.
1365  * Returns number of bytes actually received, or error indication.
1366  */
1367 static int
t_rcvnonblock(SVCXPRT * xprt,caddr_t buf,int len)1368 t_rcvnonblock(SVCXPRT *xprt, caddr_t buf, int len)
1369 {
1370 	int fd = xprt->xp_fd;
1371 	int flag;
1372 	int res;
1373 
1374 	res = t_rcv(fd, buf, (unsigned)len, &flag);
1375 	if (res == -1) {
1376 		switch (t_errno) {
1377 		case TLOOK:
1378 			switch (t_look(fd)) {
1379 			case T_DISCONNECT:
1380 				(void) t_rcvdis(fd, NULL);
1381 				break;
1382 			case T_ORDREL:
1383 				(void) t_rcvrel(fd);
1384 				(void) t_sndrel(fd);
1385 				break;
1386 			default:
1387 				break;
1388 			}
1389 			break;
1390 		case TNODATA:
1391 			/*
1392 			 * Either poll() lied, or the xprt/fd was closed and
1393 			 * re-opened under our feet. Return 0, so that we go
1394 			 * back to waiting for data.
1395 			 */
1396 			res = 0;
1397 			break;
1398 		/* Should handle TBUFOVFLW TSYSERR ? */
1399 		default:
1400 			break;
1401 		}
1402 	}
1403 	return (res);
1404 }
1405 
1406 /*
1407  * Timeout out nonblocked connection fds
1408  * If there has been no activity on the fd for __rpc_irtimeout
1409  * seconds, timeout the fd  by destroying its xprt.
1410  * If the caller gets an EMFILE error, the caller may also request
1411  * that the least busy xprt gets destroyed as well.
1412  * svc_thr_mutex is held when this is called.
1413  * svc_mutex is held when this is called.
1414  */
1415 static void
svc_timeout_nonblock_xprt_and_LRU(bool_t destroy_lru)1416 svc_timeout_nonblock_xprt_and_LRU(bool_t destroy_lru)
1417 {
1418 	SVCXPRT *xprt;
1419 	SVCXPRT *dead_xprt[CLEANUP_SIZE];
1420 	SVCXPRT *candidate_xprt = NULL;
1421 	struct cf_conn *cd;
1422 	int i, fd_idx = 0, dead_idx = 0;
1423 	struct timeval now;
1424 	time_t lasttime, maxctime = 0;
1425 	extern rwlock_t svc_fd_lock;
1426 
1427 	if (!check_nonblock_timestamps)
1428 		return;
1429 
1430 	(void) gettimeofday(&now, NULL);
1431 	if (svc_xports == NULL)
1432 		return;
1433 	/*
1434 	 * Hold svc_fd_lock to protect
1435 	 * svc_xports, svc_maxpollfd, svc_max_pollfd
1436 	 */
1437 	(void) rw_wrlock(&svc_fd_lock);
1438 	for (;;) {
1439 		/*
1440 		 * Timeout upto CLEANUP_SIZE connection fds per
1441 		 * iteration for the while(1) loop
1442 		 */
1443 		for (dead_idx = 0; fd_idx < svc_max_pollfd; fd_idx++) {
1444 			if ((xprt = svc_xports[fd_idx]) == NULL) {
1445 				continue;
1446 			}
1447 			/* Only look at connection fds */
1448 			/* LINTED pointer cast */
1449 			if (svc_type(xprt) != SVC_CONNECTION) {
1450 				continue;
1451 			}
1452 			/* LINTED pointer cast */
1453 			cd = (struct cf_conn *)xprt->xp_p1;
1454 			if (!cd->cf_conn_nonblock)
1455 				continue;
1456 			lasttime = now.tv_sec - cd->cf_conn_nonblock_timestamp;
1457 			if (lasttime >= __rpc_irtimeout &&
1458 			    __rpc_irtimeout != 0) {
1459 				/* Enter in timedout/dead array */
1460 				dead_xprt[dead_idx++] = xprt;
1461 				if (dead_idx >= CLEANUP_SIZE)
1462 					break;
1463 			} else
1464 			if (lasttime > maxctime) {
1465 				/* Possible LRU xprt */
1466 				candidate_xprt = xprt;
1467 				maxctime = lasttime;
1468 			}
1469 		}
1470 
1471 		for (i = 0; i < dead_idx; i++) {
1472 			/* Still holding svc_fd_lock */
1473 			_svc_vc_destroy_private(dead_xprt[i], FALSE);
1474 		}
1475 
1476 		/*
1477 		 * If all the nonblocked fds have been checked, we're done.
1478 		 */
1479 		if (fd_idx++ >= svc_max_pollfd)
1480 			break;
1481 	}
1482 	if ((destroy_lru) && (candidate_xprt != NULL)) {
1483 		_svc_vc_destroy_private(candidate_xprt, FALSE);
1484 	}
1485 	(void) rw_unlock(&svc_fd_lock);
1486 }
1487 /*
1488  * Receive the required bytes of data, even if it is fragmented.
1489  */
1490 static int
t_rcvall(int fd,char * buf,int len)1491 t_rcvall(int fd, char *buf, int len)
1492 {
1493 	int flag;
1494 	int final = 0;
1495 	int res;
1496 
1497 	do {
1498 		res = t_rcv(fd, buf, (unsigned)len, &flag);
1499 		if (res == -1) {
1500 			if (t_errno == TLOOK) {
1501 				switch (t_look(fd)) {
1502 				case T_DISCONNECT:
1503 					(void) t_rcvdis(fd, NULL);
1504 					break;
1505 				case T_ORDREL:
1506 					(void) t_rcvrel(fd);
1507 					(void) t_sndrel(fd);
1508 					break;
1509 				default:
1510 					break;
1511 				}
1512 			}
1513 			break;
1514 		}
1515 		final += res;
1516 		buf += res;
1517 		len -= res;
1518 	} while (len && (flag & T_MORE));
1519 	return (res == -1 ? -1 : final);
1520 }
1521 
1522 /*
1523  * writes data to the vc connection.
1524  * Any error is fatal and the connection is closed.
1525  */
1526 static int
write_vc(SVCXPRT * xprt,caddr_t buf,int len)1527 write_vc(SVCXPRT *xprt, caddr_t buf, int len)
1528 {
1529 	int i, cnt;
1530 	int flag;
1531 	int maxsz;
1532 	int nonblock;
1533 	struct pollfd pfd;
1534 
1535 /* LINTED pointer alignment */
1536 	maxsz = ((struct cf_conn *)(xprt->xp_p1))->cf_tsdu;
1537 	/* LINTED pointer cast */
1538 	nonblock = ((struct cf_conn *)(xprt->xp_p1))->cf_conn_nonblock;
1539 	if (nonblock && maxsz <= 0)
1540 		maxsz = len;
1541 	if ((maxsz == 0) || (maxsz == -1)) {
1542 		if ((len = t_snd(xprt->xp_fd, buf, (unsigned)len,
1543 		    (int)0)) == -1) {
1544 			if (t_errno == TLOOK) {
1545 				switch (t_look(xprt->xp_fd)) {
1546 				case T_DISCONNECT:
1547 					(void) t_rcvdis(xprt->xp_fd, NULL);
1548 					break;
1549 				case T_ORDREL:
1550 					(void) t_rcvrel(xprt->xp_fd);
1551 					(void) t_sndrel(xprt->xp_fd);
1552 					break;
1553 				default:
1554 					break;
1555 				}
1556 			}
1557 /* LINTED pointer alignment */
1558 			((struct cf_conn *)(xprt->xp_p1))->strm_stat =
1559 			    XPRT_DIED;
1560 /* LINTED pointer alignment */
1561 			svc_flags(xprt) |= SVC_FAILED;
1562 		}
1563 		return (len);
1564 	}
1565 
1566 	/*
1567 	 * Setup for polling. We want to be able to write normal
1568 	 * data to the transport
1569 	 */
1570 	pfd.fd = xprt->xp_fd;
1571 	pfd.events = POLLWRNORM;
1572 
1573 	/*
1574 	 * This for those transports which have a max size for data,
1575 	 * and for the non-blocking case, where t_snd() may send less
1576 	 * than requested.
1577 	 */
1578 	for (cnt = len, i = 0; cnt > 0; cnt -= i, buf += i) {
1579 		flag = cnt > maxsz ? T_MORE : 0;
1580 		if ((i = t_snd(xprt->xp_fd, buf,
1581 		    (unsigned)MIN(cnt, maxsz), flag)) == -1) {
1582 			if (t_errno == TLOOK) {
1583 				switch (t_look(xprt->xp_fd)) {
1584 				case T_DISCONNECT:
1585 					(void) t_rcvdis(xprt->xp_fd, NULL);
1586 					break;
1587 				case T_ORDREL:
1588 					(void) t_rcvrel(xprt->xp_fd);
1589 					break;
1590 				default:
1591 					break;
1592 				}
1593 			} else if (t_errno == TFLOW) {
1594 				/* Try again */
1595 				i = 0;
1596 				/* Wait till we can write to the transport */
1597 				do {
1598 					if (poll(&pfd, 1, WAIT_PER_TRY) < 0) {
1599 						/*
1600 						 * If errno is ERESTART, or
1601 						 * EAGAIN ignore error and
1602 						 * repeat poll
1603 						 */
1604 						if (errno == ERESTART ||
1605 						    errno == EAGAIN)
1606 							continue;
1607 						else
1608 							goto fatal_err;
1609 					}
1610 				} while (pfd.revents == 0);
1611 				if (pfd.revents & (POLLNVAL | POLLERR |
1612 				    POLLHUP))
1613 					goto fatal_err;
1614 				continue;
1615 			}
1616 fatal_err:
1617 /* LINTED pointer alignment */
1618 			((struct cf_conn *)(xprt->xp_p1))->strm_stat =
1619 			    XPRT_DIED;
1620 /* LINTED pointer alignment */
1621 			svc_flags(xprt) |= SVC_FAILED;
1622 			return (-1);
1623 		}
1624 	}
1625 	return (len);
1626 }
1627 
1628 static enum xprt_stat
svc_vc_stat(SVCXPRT * xprt)1629 svc_vc_stat(SVCXPRT *xprt)
1630 {
1631 /* LINTED pointer alignment */
1632 	SVCXPRT *parent = SVCEXT(xprt)->parent ? SVCEXT(xprt)->parent : xprt;
1633 
1634 /* LINTED pointer alignment */
1635 	if (svc_failed(parent) || svc_failed(xprt))
1636 		return (XPRT_DIED);
1637 	if (!xdrrec_eof(svc_xdrs[xprt->xp_fd]))
1638 		return (XPRT_MOREREQS);
1639 	/*
1640 	 * xdrrec_eof could have noticed that the connection is dead, so
1641 	 * check status again.
1642 	 */
1643 /* LINTED pointer alignment */
1644 	if (svc_failed(parent) || svc_failed(xprt))
1645 		return (XPRT_DIED);
1646 	return (XPRT_IDLE);
1647 }
1648 
1649 
1650 
1651 static bool_t
svc_vc_recv(SVCXPRT * xprt,struct rpc_msg * msg)1652 svc_vc_recv(SVCXPRT *xprt, struct rpc_msg *msg)
1653 {
1654 /* LINTED pointer alignment */
1655 	struct cf_conn *cd = (struct cf_conn *)(xprt->xp_p1);
1656 	XDR *xdrs = svc_xdrs[xprt->xp_fd];
1657 
1658 	xdrs->x_op = XDR_DECODE;
1659 
1660 	if (cd->cf_conn_nonblock) {
1661 		/* Get the next input */
1662 		if (!__xdrrec_getbytes_nonblock(xdrs, &cd->strm_stat)) {
1663 			/*
1664 			 * The entire record has not been received.
1665 			 * If the xprt has died, pass it along in svc_flags.
1666 			 * Return FALSE; For nonblocked vc connection,
1667 			 * xdr_callmsg() is called only after the entire
1668 			 * record has been received.  For blocked vc
1669 			 * connection, the data is received on the fly as it
1670 			 * is being processed through the xdr routines.
1671 			 */
1672 			if (cd->strm_stat == XPRT_DIED)
1673 				/* LINTED pointer cast */
1674 				svc_flags(xprt) |= SVC_FAILED;
1675 			return (FALSE);
1676 		}
1677 	} else {
1678 		if (!xdrrec_skiprecord(xdrs))
1679 			return (FALSE);
1680 		(void) __xdrrec_setfirst(xdrs);
1681 	}
1682 
1683 	if (xdr_callmsg(xdrs, msg)) {
1684 		cd->x_id = msg->rm_xid;
1685 		return (TRUE);
1686 	}
1687 
1688 	/*
1689 	 * If a non-blocking connection, drop it when message decode fails.
1690 	 * We are either under attack, or we're talking to a broken client.
1691 	 */
1692 	if (cd->cf_conn_nonblock) {
1693 		/* LINTED pointer cast */
1694 		svc_flags(xprt) |= SVC_FAILED;
1695 	}
1696 
1697 	return (FALSE);
1698 }
1699 
1700 static bool_t
svc_vc_getargs(SVCXPRT * xprt,xdrproc_t xdr_args,caddr_t args_ptr)1701 svc_vc_getargs(SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
1702 {
1703 	bool_t dummy;
1704 
1705 /* LINTED pointer alignment */
1706 	dummy = SVCAUTH_UNWRAP(&SVC_XP_AUTH(xprt), svc_xdrs[xprt->xp_fd],
1707 	    xdr_args, args_ptr);
1708 	if (svc_mt_mode != RPC_SVC_MT_NONE)
1709 		svc_args_done(xprt);
1710 	return (dummy);
1711 }
1712 
1713 static bool_t
svc_vc_freeargs(SVCXPRT * xprt,xdrproc_t xdr_args,caddr_t args_ptr)1714 svc_vc_freeargs(SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
1715 {
1716 /* LINTED pointer alignment */
1717 	XDR *xdrs = &(((struct cf_conn *)(xprt->xp_p1))->xdrs);
1718 
1719 	xdrs->x_op = XDR_FREE;
1720 	return ((*xdr_args)(xdrs, args_ptr));
1721 }
1722 
1723 static bool_t
svc_vc_reply(SVCXPRT * xprt,struct rpc_msg * msg)1724 svc_vc_reply(SVCXPRT *xprt, struct rpc_msg *msg)
1725 {
1726 /* LINTED pointer alignment */
1727 	struct cf_conn *cd = (struct cf_conn *)(xprt->xp_p1);
1728 	XDR *xdrs = &(cd->xdrs);
1729 	bool_t stat = FALSE;
1730 	xdrproc_t xdr_results;
1731 	caddr_t xdr_location;
1732 	bool_t has_args;
1733 
1734 	if (svc_mt_mode != RPC_SVC_MT_NONE)
1735 /* LINTED pointer alignment */
1736 		(void) mutex_lock(&svc_send_mutex(SVCEXT(xprt)->parent));
1737 
1738 	if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
1739 	    msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
1740 		has_args = TRUE;
1741 		xdr_results = msg->acpted_rply.ar_results.proc;
1742 		xdr_location = msg->acpted_rply.ar_results.where;
1743 		msg->acpted_rply.ar_results.proc = xdr_void;
1744 		msg->acpted_rply.ar_results.where = NULL;
1745 	} else
1746 		has_args = FALSE;
1747 
1748 	xdrs->x_op = XDR_ENCODE;
1749 	msg->rm_xid = cd->x_id;
1750 /* LINTED pointer alignment */
1751 	if (xdr_replymsg(xdrs, msg) && (!has_args || SVCAUTH_WRAP(
1752 	    &SVC_XP_AUTH(xprt), xdrs, xdr_results, xdr_location))) {
1753 		stat = TRUE;
1754 	}
1755 	(void) xdrrec_endofrecord(xdrs, TRUE);
1756 
1757 	if (svc_mt_mode != RPC_SVC_MT_NONE)
1758 /* LINTED pointer alignment */
1759 		(void) mutex_unlock(&svc_send_mutex(SVCEXT(xprt)->parent));
1760 
1761 	return (stat);
1762 }
1763 
1764 static struct xp_ops *
svc_vc_ops(void)1765 svc_vc_ops(void)
1766 {
1767 	static struct xp_ops ops;
1768 	extern mutex_t ops_lock;
1769 
1770 /* VARIABLES PROTECTED BY ops_lock: ops */
1771 
1772 	(void) mutex_lock(&ops_lock);
1773 	if (ops.xp_recv == NULL) {
1774 		ops.xp_recv = svc_vc_recv;
1775 		ops.xp_stat = svc_vc_stat;
1776 		ops.xp_getargs = svc_vc_getargs;
1777 		ops.xp_reply = svc_vc_reply;
1778 		ops.xp_freeargs = svc_vc_freeargs;
1779 		ops.xp_destroy = svc_vc_destroy;
1780 		ops.xp_control = svc_vc_control;
1781 	}
1782 	(void) mutex_unlock(&ops_lock);
1783 	return (&ops);
1784 }
1785 
1786 static struct xp_ops *
svc_vc_rendezvous_ops(void)1787 svc_vc_rendezvous_ops(void)
1788 {
1789 	static struct xp_ops ops;
1790 	extern mutex_t ops_lock;
1791 
1792 	(void) mutex_lock(&ops_lock);
1793 	if (ops.xp_recv == NULL) {
1794 		ops.xp_recv = rendezvous_request;
1795 		ops.xp_stat = rendezvous_stat;
1796 		ops.xp_getargs = (bool_t (*)())abort;
1797 		ops.xp_reply = (bool_t (*)())abort;
1798 		ops.xp_freeargs = (bool_t (*)())abort;
1799 		ops.xp_destroy = svc_vc_destroy;
1800 		ops.xp_control = rendezvous_control;
1801 	}
1802 	(void) mutex_unlock(&ops_lock);
1803 	return (&ops);
1804 }
1805 
1806 /*
1807  * dup cache wrapper functions for vc requests. The set of dup
1808  * functions were written with the view that they may be expanded
1809  * during creation of a generic svc_vc_enablecache routine
1810  * which would have a size based cache, rather than a time based cache.
1811  * The real work is done in generic svc.c
1812  */
1813 bool_t
__svc_vc_dupcache_init(SVCXPRT * xprt,void * condition,int basis)1814 __svc_vc_dupcache_init(SVCXPRT *xprt, void *condition, int basis)
1815 {
1816 	return (__svc_dupcache_init(condition, basis,
1817 	    /* LINTED pointer alignment */
1818 	    &(((struct cf_rendezvous *)xprt->xp_p1)->cf_cache)));
1819 }
1820 
1821 int
__svc_vc_dup(struct svc_req * req,caddr_t * resp_buf,uint_t * resp_bufsz)1822 __svc_vc_dup(struct svc_req *req, caddr_t *resp_buf, uint_t *resp_bufsz)
1823 {
1824 	return (__svc_dup(req, resp_buf, resp_bufsz,
1825 	    /* LINTED pointer alignment */
1826 	    ((struct cf_conn *)req->rq_xprt->xp_p1)->cf_cache));
1827 }
1828 
1829 int
__svc_vc_dupdone(struct svc_req * req,caddr_t resp_buf,uint_t resp_bufsz,int status)1830 __svc_vc_dupdone(struct svc_req *req, caddr_t resp_buf, uint_t resp_bufsz,
1831     int status)
1832 {
1833 	return (__svc_dupdone(req, resp_buf, resp_bufsz, status,
1834 	    /* LINTED pointer alignment */
1835 	    ((struct cf_conn *)req->rq_xprt->xp_p1)->cf_cache));
1836 }
1837