1dfdcada3SDoug Rabson /* $NetBSD: clnt_dg.c,v 1.4 2000/07/14 08:40:41 fvdl Exp $ */ 2dfdcada3SDoug Rabson 3dfdcada3SDoug Rabson /* 4dfdcada3SDoug Rabson * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 5dfdcada3SDoug Rabson * unrestricted use provided that this legend is included on all tape 6dfdcada3SDoug Rabson * media and as a part of the software program in whole or part. Users 7dfdcada3SDoug Rabson * may copy or modify Sun RPC without charge, but are not authorized 8dfdcada3SDoug Rabson * to license or distribute it to anyone else except as part of a product or 9dfdcada3SDoug Rabson * program developed by the user. 10dfdcada3SDoug Rabson * 11dfdcada3SDoug Rabson * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 12dfdcada3SDoug Rabson * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 13dfdcada3SDoug Rabson * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 14dfdcada3SDoug Rabson * 15dfdcada3SDoug Rabson * Sun RPC is provided with no support and without any obligation on the 16dfdcada3SDoug Rabson * part of Sun Microsystems, Inc. to assist in its use, correction, 17dfdcada3SDoug Rabson * modification or enhancement. 18dfdcada3SDoug Rabson * 19dfdcada3SDoug Rabson * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 20dfdcada3SDoug Rabson * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 21dfdcada3SDoug Rabson * OR ANY PART THEREOF. 22dfdcada3SDoug Rabson * 23dfdcada3SDoug Rabson * In no event will Sun Microsystems, Inc. be liable for any lost revenue 24dfdcada3SDoug Rabson * or profits or other special, indirect and consequential damages, even if 25dfdcada3SDoug Rabson * Sun has been advised of the possibility of such damages. 26dfdcada3SDoug Rabson * 27dfdcada3SDoug Rabson * Sun Microsystems, Inc. 28dfdcada3SDoug Rabson * 2550 Garcia Avenue 29dfdcada3SDoug Rabson * Mountain View, California 94043 30dfdcada3SDoug Rabson */ 31dfdcada3SDoug Rabson /* 32dfdcada3SDoug Rabson * Copyright (c) 1986-1991 by Sun Microsystems Inc. 33dfdcada3SDoug Rabson */ 34dfdcada3SDoug Rabson 35dfdcada3SDoug Rabson #if defined(LIBC_SCCS) && !defined(lint) 36dfdcada3SDoug Rabson #ident "@(#)clnt_dg.c 1.23 94/04/22 SMI" 37dfdcada3SDoug Rabson static char sccsid[] = "@(#)clnt_dg.c 1.19 89/03/16 Copyr 1988 Sun Micro"; 38dfdcada3SDoug Rabson #endif 39dfdcada3SDoug Rabson #include <sys/cdefs.h> 40dfdcada3SDoug Rabson __FBSDID("$FreeBSD$"); 41dfdcada3SDoug Rabson 42dfdcada3SDoug Rabson /* 43dfdcada3SDoug Rabson * Implements a connectionless client side RPC. 44dfdcada3SDoug Rabson */ 45dfdcada3SDoug Rabson 46dfdcada3SDoug Rabson #include <sys/param.h> 47dfdcada3SDoug Rabson #include <sys/systm.h> 48c675522fSDoug Rabson #include <sys/kernel.h> 49dfdcada3SDoug Rabson #include <sys/lock.h> 50dfdcada3SDoug Rabson #include <sys/malloc.h> 51dfdcada3SDoug Rabson #include <sys/mbuf.h> 52dfdcada3SDoug Rabson #include <sys/mutex.h> 53dfdcada3SDoug Rabson #include <sys/pcpu.h> 54dfdcada3SDoug Rabson #include <sys/proc.h> 55dfdcada3SDoug Rabson #include <sys/socket.h> 56dfdcada3SDoug Rabson #include <sys/socketvar.h> 57dfdcada3SDoug Rabson #include <sys/time.h> 58dfdcada3SDoug Rabson #include <sys/uio.h> 59dfdcada3SDoug Rabson 60dfdcada3SDoug Rabson #include <rpc/rpc.h> 61ee31b83aSDoug Rabson #include <rpc/rpc_com.h> 62dfdcada3SDoug Rabson 63dfdcada3SDoug Rabson 64dfdcada3SDoug Rabson #ifdef _FREEFALL_CONFIG 65dfdcada3SDoug Rabson /* 66dfdcada3SDoug Rabson * Disable RPC exponential back-off for FreeBSD.org systems. 67dfdcada3SDoug Rabson */ 68dfdcada3SDoug Rabson #define RPC_MAX_BACKOFF 1 /* second */ 69dfdcada3SDoug Rabson #else 70dfdcada3SDoug Rabson #define RPC_MAX_BACKOFF 30 /* seconds */ 71dfdcada3SDoug Rabson #endif 72dfdcada3SDoug Rabson 73dfdcada3SDoug Rabson static bool_t time_not_ok(struct timeval *); 74c675522fSDoug Rabson static enum clnt_stat clnt_dg_call(CLIENT *, struct rpc_callextra *, 75a9148abdSDoug Rabson rpcproc_t, struct mbuf *, struct mbuf **, struct timeval); 76dfdcada3SDoug Rabson static void clnt_dg_geterr(CLIENT *, struct rpc_err *); 77dfdcada3SDoug Rabson static bool_t clnt_dg_freeres(CLIENT *, xdrproc_t, void *); 78dfdcada3SDoug Rabson static void clnt_dg_abort(CLIENT *); 79dfdcada3SDoug Rabson static bool_t clnt_dg_control(CLIENT *, u_int, void *); 80a9148abdSDoug Rabson static void clnt_dg_close(CLIENT *); 81dfdcada3SDoug Rabson static void clnt_dg_destroy(CLIENT *); 82dfdcada3SDoug Rabson static void clnt_dg_soupcall(struct socket *so, void *arg, int waitflag); 83dfdcada3SDoug Rabson 84dfdcada3SDoug Rabson static struct clnt_ops clnt_dg_ops = { 85dfdcada3SDoug Rabson .cl_call = clnt_dg_call, 86dfdcada3SDoug Rabson .cl_abort = clnt_dg_abort, 87dfdcada3SDoug Rabson .cl_geterr = clnt_dg_geterr, 88dfdcada3SDoug Rabson .cl_freeres = clnt_dg_freeres, 89a9148abdSDoug Rabson .cl_close = clnt_dg_close, 90dfdcada3SDoug Rabson .cl_destroy = clnt_dg_destroy, 91dfdcada3SDoug Rabson .cl_control = clnt_dg_control 92dfdcada3SDoug Rabson }; 93dfdcada3SDoug Rabson 94dfdcada3SDoug Rabson static const char mem_err_clnt_dg[] = "clnt_dg_create: out of memory"; 95dfdcada3SDoug Rabson 96dfdcada3SDoug Rabson /* 97c675522fSDoug Rabson * A pending RPC request which awaits a reply. Requests which have 98c675522fSDoug Rabson * received their reply will have cr_xid set to zero and cr_mrep to 99c675522fSDoug Rabson * the mbuf chain of the reply. 100dfdcada3SDoug Rabson */ 101dfdcada3SDoug Rabson struct cu_request { 102dfdcada3SDoug Rabson TAILQ_ENTRY(cu_request) cr_link; 103c675522fSDoug Rabson CLIENT *cr_client; /* owner */ 104dfdcada3SDoug Rabson uint32_t cr_xid; /* XID of request */ 105dfdcada3SDoug Rabson struct mbuf *cr_mrep; /* reply received by upcall */ 106dfdcada3SDoug Rabson int cr_error; /* any error from upcall */ 107a9148abdSDoug Rabson char cr_verf[MAX_AUTH_BYTES]; /* reply verf */ 108dfdcada3SDoug Rabson }; 109dfdcada3SDoug Rabson 110dfdcada3SDoug Rabson TAILQ_HEAD(cu_request_list, cu_request); 111dfdcada3SDoug Rabson 112dfdcada3SDoug Rabson #define MCALL_MSG_SIZE 24 113dfdcada3SDoug Rabson 114dfdcada3SDoug Rabson /* 115dfdcada3SDoug Rabson * This structure is pointed to by the socket's so_upcallarg 116dfdcada3SDoug Rabson * member. It is separate from the client private data to facilitate 117dfdcada3SDoug Rabson * multiple clients sharing the same socket. The cs_lock mutex is used 118dfdcada3SDoug Rabson * to protect all fields of this structure, the socket's receive 119dfdcada3SDoug Rabson * buffer SOCKBUF_LOCK is used to ensure that exactly one of these 120dfdcada3SDoug Rabson * structures is installed on the socket. 121dfdcada3SDoug Rabson */ 122dfdcada3SDoug Rabson struct cu_socket { 123dfdcada3SDoug Rabson struct mtx cs_lock; 124dfdcada3SDoug Rabson int cs_refs; /* Count of clients */ 125dfdcada3SDoug Rabson struct cu_request_list cs_pending; /* Requests awaiting replies */ 126dfdcada3SDoug Rabson }; 127dfdcada3SDoug Rabson 128dfdcada3SDoug Rabson /* 129dfdcada3SDoug Rabson * Private data kept per client handle 130dfdcada3SDoug Rabson */ 131dfdcada3SDoug Rabson struct cu_data { 132c675522fSDoug Rabson int cu_threads; /* # threads in clnt_vc_call */ 133a9148abdSDoug Rabson bool_t cu_closing; /* TRUE if we are closing */ 134a9148abdSDoug Rabson bool_t cu_closed; /* TRUE if we are closed */ 135dfdcada3SDoug Rabson struct socket *cu_socket; /* connection socket */ 136dfdcada3SDoug Rabson bool_t cu_closeit; /* opened by library */ 137dfdcada3SDoug Rabson struct sockaddr_storage cu_raddr; /* remote address */ 138dfdcada3SDoug Rabson int cu_rlen; 139dfdcada3SDoug Rabson struct timeval cu_wait; /* retransmit interval */ 140dfdcada3SDoug Rabson struct timeval cu_total; /* total time for the call */ 141dfdcada3SDoug Rabson struct rpc_err cu_error; 142dfdcada3SDoug Rabson uint32_t cu_xid; 143dfdcada3SDoug Rabson char cu_mcallc[MCALL_MSG_SIZE]; /* marshalled callmsg */ 144dfdcada3SDoug Rabson size_t cu_mcalllen; 145dfdcada3SDoug Rabson size_t cu_sendsz; /* send size */ 146dfdcada3SDoug Rabson size_t cu_recvsz; /* recv size */ 147dfdcada3SDoug Rabson int cu_async; 148dfdcada3SDoug Rabson int cu_connect; /* Use connect(). */ 149dfdcada3SDoug Rabson int cu_connected; /* Have done connect(). */ 150dfdcada3SDoug Rabson const char *cu_waitchan; 151dfdcada3SDoug Rabson int cu_waitflag; 152a9148abdSDoug Rabson int cu_cwnd; /* congestion window */ 153a9148abdSDoug Rabson int cu_sent; /* number of in-flight RPCs */ 154a9148abdSDoug Rabson bool_t cu_cwnd_wait; 155dfdcada3SDoug Rabson }; 156dfdcada3SDoug Rabson 157a9148abdSDoug Rabson #define CWNDSCALE 256 158a9148abdSDoug Rabson #define MAXCWND (32 * CWNDSCALE) 159a9148abdSDoug Rabson 160dfdcada3SDoug Rabson /* 161dfdcada3SDoug Rabson * Connection less client creation returns with client handle parameters. 162dfdcada3SDoug Rabson * Default options are set, which the user can change using clnt_control(). 163dfdcada3SDoug Rabson * fd should be open and bound. 164dfdcada3SDoug Rabson * NB: The rpch->cl_auth is initialized to null authentication. 165dfdcada3SDoug Rabson * Caller may wish to set this something more useful. 166dfdcada3SDoug Rabson * 167dfdcada3SDoug Rabson * sendsz and recvsz are the maximum allowable packet sizes that can be 168dfdcada3SDoug Rabson * sent and received. Normally they are the same, but they can be 169dfdcada3SDoug Rabson * changed to improve the program efficiency and buffer allocation. 170dfdcada3SDoug Rabson * If they are 0, use the transport default. 171dfdcada3SDoug Rabson * 172dfdcada3SDoug Rabson * If svcaddr is NULL, returns NULL. 173dfdcada3SDoug Rabson */ 174dfdcada3SDoug Rabson CLIENT * 175dfdcada3SDoug Rabson clnt_dg_create( 176dfdcada3SDoug Rabson struct socket *so, 177dfdcada3SDoug Rabson struct sockaddr *svcaddr, /* servers address */ 178dfdcada3SDoug Rabson rpcprog_t program, /* program number */ 179dfdcada3SDoug Rabson rpcvers_t version, /* version number */ 180dfdcada3SDoug Rabson size_t sendsz, /* buffer recv size */ 181dfdcada3SDoug Rabson size_t recvsz) /* buffer send size */ 182dfdcada3SDoug Rabson { 183dfdcada3SDoug Rabson CLIENT *cl = NULL; /* client handle */ 184dfdcada3SDoug Rabson struct cu_data *cu = NULL; /* private data */ 185dfdcada3SDoug Rabson struct cu_socket *cs = NULL; 186dfdcada3SDoug Rabson struct timeval now; 187dfdcada3SDoug Rabson struct rpc_msg call_msg; 188dfdcada3SDoug Rabson struct __rpc_sockinfo si; 189dfdcada3SDoug Rabson XDR xdrs; 190dfdcada3SDoug Rabson 191dfdcada3SDoug Rabson if (svcaddr == NULL) { 192dfdcada3SDoug Rabson rpc_createerr.cf_stat = RPC_UNKNOWNADDR; 193dfdcada3SDoug Rabson return (NULL); 194dfdcada3SDoug Rabson } 195dfdcada3SDoug Rabson 196dfdcada3SDoug Rabson if (!__rpc_socket2sockinfo(so, &si)) { 197dfdcada3SDoug Rabson rpc_createerr.cf_stat = RPC_TLIERROR; 198dfdcada3SDoug Rabson rpc_createerr.cf_error.re_errno = 0; 199dfdcada3SDoug Rabson return (NULL); 200dfdcada3SDoug Rabson } 201dfdcada3SDoug Rabson 202dfdcada3SDoug Rabson /* 203dfdcada3SDoug Rabson * Find the receive and the send size 204dfdcada3SDoug Rabson */ 205dfdcada3SDoug Rabson sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz); 206dfdcada3SDoug Rabson recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz); 207dfdcada3SDoug Rabson if ((sendsz == 0) || (recvsz == 0)) { 208dfdcada3SDoug Rabson rpc_createerr.cf_stat = RPC_TLIERROR; /* XXX */ 209dfdcada3SDoug Rabson rpc_createerr.cf_error.re_errno = 0; 210dfdcada3SDoug Rabson return (NULL); 211dfdcada3SDoug Rabson } 212dfdcada3SDoug Rabson 213dfdcada3SDoug Rabson cl = mem_alloc(sizeof (CLIENT)); 214dfdcada3SDoug Rabson 215dfdcada3SDoug Rabson /* 216dfdcada3SDoug Rabson * Should be multiple of 4 for XDR. 217dfdcada3SDoug Rabson */ 218dfdcada3SDoug Rabson sendsz = ((sendsz + 3) / 4) * 4; 219dfdcada3SDoug Rabson recvsz = ((recvsz + 3) / 4) * 4; 220dfdcada3SDoug Rabson cu = mem_alloc(sizeof (*cu)); 221c675522fSDoug Rabson cu->cu_threads = 0; 222c675522fSDoug Rabson cu->cu_closing = FALSE; 223a9148abdSDoug Rabson cu->cu_closed = FALSE; 224dfdcada3SDoug Rabson (void) memcpy(&cu->cu_raddr, svcaddr, (size_t)svcaddr->sa_len); 225dfdcada3SDoug Rabson cu->cu_rlen = svcaddr->sa_len; 226dfdcada3SDoug Rabson /* Other values can also be set through clnt_control() */ 227c675522fSDoug Rabson cu->cu_wait.tv_sec = 3; /* heuristically chosen */ 228dfdcada3SDoug Rabson cu->cu_wait.tv_usec = 0; 229dfdcada3SDoug Rabson cu->cu_total.tv_sec = -1; 230dfdcada3SDoug Rabson cu->cu_total.tv_usec = -1; 231dfdcada3SDoug Rabson cu->cu_sendsz = sendsz; 232dfdcada3SDoug Rabson cu->cu_recvsz = recvsz; 233dfdcada3SDoug Rabson cu->cu_async = FALSE; 234dfdcada3SDoug Rabson cu->cu_connect = FALSE; 235dfdcada3SDoug Rabson cu->cu_connected = FALSE; 236dfdcada3SDoug Rabson cu->cu_waitchan = "rpcrecv"; 237dfdcada3SDoug Rabson cu->cu_waitflag = 0; 238a9148abdSDoug Rabson cu->cu_cwnd = MAXCWND / 2; 239a9148abdSDoug Rabson cu->cu_sent = 0; 240a9148abdSDoug Rabson cu->cu_cwnd_wait = FALSE; 241dfdcada3SDoug Rabson (void) getmicrotime(&now); 242dfdcada3SDoug Rabson cu->cu_xid = __RPC_GETXID(&now); 243dfdcada3SDoug Rabson call_msg.rm_xid = cu->cu_xid; 244dfdcada3SDoug Rabson call_msg.rm_call.cb_prog = program; 245dfdcada3SDoug Rabson call_msg.rm_call.cb_vers = version; 246dfdcada3SDoug Rabson xdrmem_create(&xdrs, cu->cu_mcallc, MCALL_MSG_SIZE, XDR_ENCODE); 247dfdcada3SDoug Rabson if (! xdr_callhdr(&xdrs, &call_msg)) { 248dfdcada3SDoug Rabson rpc_createerr.cf_stat = RPC_CANTENCODEARGS; /* XXX */ 249dfdcada3SDoug Rabson rpc_createerr.cf_error.re_errno = 0; 250dfdcada3SDoug Rabson goto err2; 251dfdcada3SDoug Rabson } 252dfdcada3SDoug Rabson cu->cu_mcalllen = XDR_GETPOS(&xdrs);; 253dfdcada3SDoug Rabson 254dfdcada3SDoug Rabson /* 255dfdcada3SDoug Rabson * By default, closeit is always FALSE. It is users responsibility 256dfdcada3SDoug Rabson * to do a close on it, else the user may use clnt_control 257dfdcada3SDoug Rabson * to let clnt_destroy do it for him/her. 258dfdcada3SDoug Rabson */ 259dfdcada3SDoug Rabson cu->cu_closeit = FALSE; 260dfdcada3SDoug Rabson cu->cu_socket = so; 261c675522fSDoug Rabson soreserve(so, 256*1024, 256*1024); 262dfdcada3SDoug Rabson 263dfdcada3SDoug Rabson SOCKBUF_LOCK(&so->so_rcv); 264dfdcada3SDoug Rabson recheck_socket: 265dfdcada3SDoug Rabson if (so->so_upcall) { 266dfdcada3SDoug Rabson if (so->so_upcall != clnt_dg_soupcall) { 267dfdcada3SDoug Rabson SOCKBUF_UNLOCK(&so->so_rcv); 268dfdcada3SDoug Rabson printf("clnt_dg_create(): socket already has an incompatible upcall\n"); 269dfdcada3SDoug Rabson goto err2; 270dfdcada3SDoug Rabson } 271dfdcada3SDoug Rabson cs = (struct cu_socket *) so->so_upcallarg; 272dfdcada3SDoug Rabson mtx_lock(&cs->cs_lock); 273dfdcada3SDoug Rabson cs->cs_refs++; 274dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 275dfdcada3SDoug Rabson } else { 276dfdcada3SDoug Rabson /* 277dfdcada3SDoug Rabson * We are the first on this socket - allocate the 278dfdcada3SDoug Rabson * structure and install it in the socket. 279dfdcada3SDoug Rabson */ 280dfdcada3SDoug Rabson SOCKBUF_UNLOCK(&cu->cu_socket->so_rcv); 281dfdcada3SDoug Rabson cs = mem_alloc(sizeof(*cs)); 282dfdcada3SDoug Rabson SOCKBUF_LOCK(&cu->cu_socket->so_rcv); 283dfdcada3SDoug Rabson if (so->so_upcall) { 284dfdcada3SDoug Rabson /* 285dfdcada3SDoug Rabson * We have lost a race with some other client. 286dfdcada3SDoug Rabson */ 287dfdcada3SDoug Rabson mem_free(cs, sizeof(*cs)); 288dfdcada3SDoug Rabson goto recheck_socket; 289dfdcada3SDoug Rabson } 290dfdcada3SDoug Rabson mtx_init(&cs->cs_lock, "cs->cs_lock", NULL, MTX_DEF); 291dfdcada3SDoug Rabson cs->cs_refs = 1; 292dfdcada3SDoug Rabson TAILQ_INIT(&cs->cs_pending); 293dfdcada3SDoug Rabson so->so_upcallarg = cs; 294dfdcada3SDoug Rabson so->so_upcall = clnt_dg_soupcall; 295dfdcada3SDoug Rabson so->so_rcv.sb_flags |= SB_UPCALL; 296dfdcada3SDoug Rabson } 297dfdcada3SDoug Rabson SOCKBUF_UNLOCK(&so->so_rcv); 298dfdcada3SDoug Rabson 299c675522fSDoug Rabson cl->cl_refs = 1; 300dfdcada3SDoug Rabson cl->cl_ops = &clnt_dg_ops; 301dfdcada3SDoug Rabson cl->cl_private = (caddr_t)(void *)cu; 302dfdcada3SDoug Rabson cl->cl_auth = authnone_create(); 303dfdcada3SDoug Rabson cl->cl_tp = NULL; 304dfdcada3SDoug Rabson cl->cl_netid = NULL; 305dfdcada3SDoug Rabson return (cl); 306dfdcada3SDoug Rabson err2: 307dfdcada3SDoug Rabson if (cl) { 308dfdcada3SDoug Rabson mem_free(cl, sizeof (CLIENT)); 309dfdcada3SDoug Rabson if (cu) 310dfdcada3SDoug Rabson mem_free(cu, sizeof (*cu)); 311dfdcada3SDoug Rabson } 312dfdcada3SDoug Rabson return (NULL); 313dfdcada3SDoug Rabson } 314dfdcada3SDoug Rabson 315dfdcada3SDoug Rabson static enum clnt_stat 316dfdcada3SDoug Rabson clnt_dg_call( 317dfdcada3SDoug Rabson CLIENT *cl, /* client handle */ 318c675522fSDoug Rabson struct rpc_callextra *ext, /* call metadata */ 319dfdcada3SDoug Rabson rpcproc_t proc, /* procedure number */ 320a9148abdSDoug Rabson struct mbuf *args, /* pointer to args */ 321a9148abdSDoug Rabson struct mbuf **resultsp, /* pointer to results */ 322dfdcada3SDoug Rabson struct timeval utimeout) /* seconds to wait before giving up */ 323dfdcada3SDoug Rabson { 324dfdcada3SDoug Rabson struct cu_data *cu = (struct cu_data *)cl->cl_private; 325dfdcada3SDoug Rabson struct cu_socket *cs = (struct cu_socket *) cu->cu_socket->so_upcallarg; 326a9148abdSDoug Rabson struct rpc_timers *rt; 327c675522fSDoug Rabson AUTH *auth; 328a9148abdSDoug Rabson struct rpc_err *errp; 329a9148abdSDoug Rabson enum clnt_stat stat; 330dfdcada3SDoug Rabson XDR xdrs; 331dfdcada3SDoug Rabson struct rpc_msg reply_msg; 332dfdcada3SDoug Rabson bool_t ok; 333c675522fSDoug Rabson int retrans; /* number of re-transmits so far */ 334dfdcada3SDoug Rabson int nrefreshes = 2; /* number of times to refresh cred */ 335c675522fSDoug Rabson struct timeval *tvp; 336c675522fSDoug Rabson int timeout; 337c675522fSDoug Rabson int retransmit_time; 338a9148abdSDoug Rabson int next_sendtime, starttime, rtt, time_waited, tv = 0; 339dfdcada3SDoug Rabson struct sockaddr *sa; 340dfdcada3SDoug Rabson socklen_t salen; 341a9148abdSDoug Rabson uint32_t xid = 0; 342a9148abdSDoug Rabson struct mbuf *mreq = NULL, *results; 343c675522fSDoug Rabson struct cu_request *cr; 344dfdcada3SDoug Rabson int error; 345dfdcada3SDoug Rabson 346c675522fSDoug Rabson cr = malloc(sizeof(struct cu_request), M_RPC, M_WAITOK); 347c675522fSDoug Rabson 348dfdcada3SDoug Rabson mtx_lock(&cs->cs_lock); 349dfdcada3SDoug Rabson 350a9148abdSDoug Rabson if (cu->cu_closing || cu->cu_closed) { 351c675522fSDoug Rabson mtx_unlock(&cs->cs_lock); 352c675522fSDoug Rabson free(cr, M_RPC); 353c675522fSDoug Rabson return (RPC_CANTSEND); 354c675522fSDoug Rabson } 355c675522fSDoug Rabson cu->cu_threads++; 356c675522fSDoug Rabson 357a9148abdSDoug Rabson if (ext) { 358c675522fSDoug Rabson auth = ext->rc_auth; 359a9148abdSDoug Rabson errp = &ext->rc_err; 360a9148abdSDoug Rabson } else { 361c675522fSDoug Rabson auth = cl->cl_auth; 362a9148abdSDoug Rabson errp = &cu->cu_error; 363a9148abdSDoug Rabson } 364c675522fSDoug Rabson 365c675522fSDoug Rabson cr->cr_client = cl; 366c675522fSDoug Rabson cr->cr_mrep = NULL; 367c675522fSDoug Rabson cr->cr_error = 0; 368dfdcada3SDoug Rabson 369dfdcada3SDoug Rabson if (cu->cu_total.tv_usec == -1) { 370c675522fSDoug Rabson tvp = &utimeout; /* use supplied timeout */ 371dfdcada3SDoug Rabson } else { 372c675522fSDoug Rabson tvp = &cu->cu_total; /* use default timeout */ 373dfdcada3SDoug Rabson } 374c675522fSDoug Rabson if (tvp->tv_sec || tvp->tv_usec) 375c675522fSDoug Rabson timeout = tvtohz(tvp); 376c675522fSDoug Rabson else 377c675522fSDoug Rabson timeout = 0; 378dfdcada3SDoug Rabson 379dfdcada3SDoug Rabson if (cu->cu_connect && !cu->cu_connected) { 380dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 381dfdcada3SDoug Rabson error = soconnect(cu->cu_socket, 382dfdcada3SDoug Rabson (struct sockaddr *)&cu->cu_raddr, curthread); 383dfdcada3SDoug Rabson mtx_lock(&cs->cs_lock); 384dfdcada3SDoug Rabson if (error) { 385a9148abdSDoug Rabson errp->re_errno = error; 386a9148abdSDoug Rabson errp->re_status = stat = RPC_CANTSEND; 387dfdcada3SDoug Rabson goto out; 388dfdcada3SDoug Rabson } 389dfdcada3SDoug Rabson cu->cu_connected = 1; 390dfdcada3SDoug Rabson } 391dfdcada3SDoug Rabson if (cu->cu_connected) { 392dfdcada3SDoug Rabson sa = NULL; 393dfdcada3SDoug Rabson salen = 0; 394dfdcada3SDoug Rabson } else { 395dfdcada3SDoug Rabson sa = (struct sockaddr *)&cu->cu_raddr; 396dfdcada3SDoug Rabson salen = cu->cu_rlen; 397dfdcada3SDoug Rabson } 398c675522fSDoug Rabson time_waited = 0; 399c675522fSDoug Rabson retrans = 0; 400a9148abdSDoug Rabson if (ext && ext->rc_timers) { 401a9148abdSDoug Rabson rt = ext->rc_timers; 402a9148abdSDoug Rabson if (!rt->rt_rtxcur) 403a9148abdSDoug Rabson rt->rt_rtxcur = tvtohz(&cu->cu_wait); 404a9148abdSDoug Rabson retransmit_time = next_sendtime = rt->rt_rtxcur; 405a9148abdSDoug Rabson } else { 406a9148abdSDoug Rabson rt = NULL; 407c675522fSDoug Rabson retransmit_time = next_sendtime = tvtohz(&cu->cu_wait); 408a9148abdSDoug Rabson } 409dfdcada3SDoug Rabson 410c675522fSDoug Rabson starttime = ticks; 411dfdcada3SDoug Rabson 412dfdcada3SDoug Rabson call_again: 413dfdcada3SDoug Rabson mtx_assert(&cs->cs_lock, MA_OWNED); 414dfdcada3SDoug Rabson 415dfdcada3SDoug Rabson cu->cu_xid++; 416dfdcada3SDoug Rabson xid = cu->cu_xid; 417dfdcada3SDoug Rabson 418dfdcada3SDoug Rabson send_again: 419dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 420dfdcada3SDoug Rabson 421dfdcada3SDoug Rabson MGETHDR(mreq, M_WAIT, MT_DATA); 422a9148abdSDoug Rabson KASSERT(cu->cu_mcalllen <= MHLEN, ("RPC header too big")); 423a9148abdSDoug Rabson bcopy(cu->cu_mcallc, mreq->m_data, cu->cu_mcalllen); 424a9148abdSDoug Rabson mreq->m_len = cu->cu_mcalllen; 425dfdcada3SDoug Rabson 426dfdcada3SDoug Rabson /* 427dfdcada3SDoug Rabson * The XID is the first thing in the request. 428dfdcada3SDoug Rabson */ 429dfdcada3SDoug Rabson *mtod(mreq, uint32_t *) = htonl(xid); 430dfdcada3SDoug Rabson 431dfdcada3SDoug Rabson xdrmbuf_create(&xdrs, mreq, XDR_ENCODE); 432dfdcada3SDoug Rabson 433a9148abdSDoug Rabson if (cu->cu_async == TRUE && args == NULL) 434dfdcada3SDoug Rabson goto get_reply; 435dfdcada3SDoug Rabson 436dfdcada3SDoug Rabson if ((! XDR_PUTINT32(&xdrs, &proc)) || 437a9148abdSDoug Rabson (! AUTH_MARSHALL(auth, xid, &xdrs, 438a9148abdSDoug Rabson m_copym(args, 0, M_COPYALL, M_WAITOK)))) { 439a9148abdSDoug Rabson errp->re_status = stat = RPC_CANTENCODEARGS; 440dfdcada3SDoug Rabson mtx_lock(&cs->cs_lock); 441dfdcada3SDoug Rabson goto out; 442dfdcada3SDoug Rabson } 443a9148abdSDoug Rabson mreq->m_pkthdr.len = m_length(mreq, NULL); 444dfdcada3SDoug Rabson 445c675522fSDoug Rabson cr->cr_xid = xid; 446dfdcada3SDoug Rabson mtx_lock(&cs->cs_lock); 447a9148abdSDoug Rabson 448a9148abdSDoug Rabson /* 449a9148abdSDoug Rabson * Try to get a place in the congestion window. 450a9148abdSDoug Rabson */ 451a9148abdSDoug Rabson while (cu->cu_sent >= cu->cu_cwnd) { 452a9148abdSDoug Rabson cu->cu_cwnd_wait = TRUE; 453a9148abdSDoug Rabson error = msleep(&cu->cu_cwnd_wait, &cs->cs_lock, 454a9148abdSDoug Rabson cu->cu_waitflag, "rpccwnd", 0); 455a9148abdSDoug Rabson if (error) { 456a9148abdSDoug Rabson errp->re_errno = error; 457a9148abdSDoug Rabson errp->re_status = stat = RPC_CANTSEND; 458a9148abdSDoug Rabson goto out; 459a9148abdSDoug Rabson } 460a9148abdSDoug Rabson } 461a9148abdSDoug Rabson cu->cu_sent += CWNDSCALE; 462a9148abdSDoug Rabson 463c675522fSDoug Rabson TAILQ_INSERT_TAIL(&cs->cs_pending, cr, cr_link); 464dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 465dfdcada3SDoug Rabson 466dfdcada3SDoug Rabson /* 467dfdcada3SDoug Rabson * sosend consumes mreq. 468dfdcada3SDoug Rabson */ 469dfdcada3SDoug Rabson error = sosend(cu->cu_socket, sa, NULL, mreq, NULL, 0, curthread); 470dfdcada3SDoug Rabson mreq = NULL; 471dfdcada3SDoug Rabson 472dfdcada3SDoug Rabson /* 473dfdcada3SDoug Rabson * sub-optimal code appears here because we have 474dfdcada3SDoug Rabson * some clock time to spare while the packets are in flight. 475dfdcada3SDoug Rabson * (We assume that this is actually only executed once.) 476dfdcada3SDoug Rabson */ 477a9148abdSDoug Rabson reply_msg.acpted_rply.ar_verf.oa_flavor = AUTH_NULL; 478a9148abdSDoug Rabson reply_msg.acpted_rply.ar_verf.oa_base = cr->cr_verf; 479a9148abdSDoug Rabson reply_msg.acpted_rply.ar_verf.oa_length = 0; 480a9148abdSDoug Rabson reply_msg.acpted_rply.ar_results.where = NULL; 481a9148abdSDoug Rabson reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void; 482dfdcada3SDoug Rabson 483dfdcada3SDoug Rabson mtx_lock(&cs->cs_lock); 484dfdcada3SDoug Rabson if (error) { 485c675522fSDoug Rabson TAILQ_REMOVE(&cs->cs_pending, cr, cr_link); 486a9148abdSDoug Rabson errp->re_errno = error; 487a9148abdSDoug Rabson errp->re_status = stat = RPC_CANTSEND; 488a9148abdSDoug Rabson cu->cu_sent -= CWNDSCALE; 489a9148abdSDoug Rabson if (cu->cu_cwnd_wait) { 490a9148abdSDoug Rabson cu->cu_cwnd_wait = FALSE; 491a9148abdSDoug Rabson wakeup(&cu->cu_cwnd_wait); 492a9148abdSDoug Rabson } 493dfdcada3SDoug Rabson goto out; 494dfdcada3SDoug Rabson } 495dfdcada3SDoug Rabson 496dfdcada3SDoug Rabson /* 497dfdcada3SDoug Rabson * Check to see if we got an upcall while waiting for the 498c675522fSDoug Rabson * lock. 499dfdcada3SDoug Rabson */ 500c675522fSDoug Rabson if (cr->cr_error) { 501c675522fSDoug Rabson TAILQ_REMOVE(&cs->cs_pending, cr, cr_link); 502a9148abdSDoug Rabson errp->re_errno = cr->cr_error; 503a9148abdSDoug Rabson errp->re_status = stat = RPC_CANTRECV; 504a9148abdSDoug Rabson cu->cu_sent -= CWNDSCALE; 505a9148abdSDoug Rabson if (cu->cu_cwnd_wait) { 506a9148abdSDoug Rabson cu->cu_cwnd_wait = FALSE; 507a9148abdSDoug Rabson wakeup(&cu->cu_cwnd_wait); 508a9148abdSDoug Rabson } 509dfdcada3SDoug Rabson goto out; 510dfdcada3SDoug Rabson } 511c675522fSDoug Rabson if (cr->cr_mrep) { 512c675522fSDoug Rabson TAILQ_REMOVE(&cs->cs_pending, cr, cr_link); 513a9148abdSDoug Rabson cu->cu_sent -= CWNDSCALE; 514a9148abdSDoug Rabson if (cu->cu_cwnd_wait) { 515a9148abdSDoug Rabson cu->cu_cwnd_wait = FALSE; 516a9148abdSDoug Rabson wakeup(&cu->cu_cwnd_wait); 517a9148abdSDoug Rabson } 518dfdcada3SDoug Rabson goto got_reply; 519dfdcada3SDoug Rabson } 520dfdcada3SDoug Rabson 521dfdcada3SDoug Rabson /* 522dfdcada3SDoug Rabson * Hack to provide rpc-based message passing 523dfdcada3SDoug Rabson */ 524c675522fSDoug Rabson if (timeout == 0) { 525c675522fSDoug Rabson TAILQ_REMOVE(&cs->cs_pending, cr, cr_link); 526a9148abdSDoug Rabson errp->re_status = stat = RPC_TIMEDOUT; 527a9148abdSDoug Rabson cu->cu_sent -= CWNDSCALE; 528a9148abdSDoug Rabson if (cu->cu_cwnd_wait) { 529a9148abdSDoug Rabson cu->cu_cwnd_wait = FALSE; 530a9148abdSDoug Rabson wakeup(&cu->cu_cwnd_wait); 531a9148abdSDoug Rabson } 532dfdcada3SDoug Rabson goto out; 533dfdcada3SDoug Rabson } 534dfdcada3SDoug Rabson 535dfdcada3SDoug Rabson get_reply: 536dfdcada3SDoug Rabson for (;;) { 537dfdcada3SDoug Rabson /* Decide how long to wait. */ 538c675522fSDoug Rabson if (next_sendtime < timeout) 539dfdcada3SDoug Rabson tv = next_sendtime; 540c675522fSDoug Rabson else 541dfdcada3SDoug Rabson tv = timeout; 542c675522fSDoug Rabson tv -= time_waited; 543dfdcada3SDoug Rabson 544c675522fSDoug Rabson if (tv > 0) { 545a9148abdSDoug Rabson if (cu->cu_closing || cu->cu_closed) 546c675522fSDoug Rabson error = 0; 547c675522fSDoug Rabson else 548c675522fSDoug Rabson error = msleep(cr, &cs->cs_lock, 549c675522fSDoug Rabson cu->cu_waitflag, cu->cu_waitchan, tv); 550c675522fSDoug Rabson } else { 551c675522fSDoug Rabson error = EWOULDBLOCK; 552c675522fSDoug Rabson } 553c675522fSDoug Rabson 554c675522fSDoug Rabson TAILQ_REMOVE(&cs->cs_pending, cr, cr_link); 555a9148abdSDoug Rabson cu->cu_sent -= CWNDSCALE; 556a9148abdSDoug Rabson if (cu->cu_cwnd_wait) { 557a9148abdSDoug Rabson cu->cu_cwnd_wait = FALSE; 558a9148abdSDoug Rabson wakeup(&cu->cu_cwnd_wait); 559a9148abdSDoug Rabson } 560dfdcada3SDoug Rabson 561dfdcada3SDoug Rabson if (!error) { 562dfdcada3SDoug Rabson /* 563dfdcada3SDoug Rabson * We were woken up by the upcall. If the 564dfdcada3SDoug Rabson * upcall had a receive error, report that, 565dfdcada3SDoug Rabson * otherwise we have a reply. 566dfdcada3SDoug Rabson */ 567c675522fSDoug Rabson if (cr->cr_error) { 568a9148abdSDoug Rabson errp->re_errno = cr->cr_error; 569a9148abdSDoug Rabson errp->re_status = stat = RPC_CANTRECV; 570dfdcada3SDoug Rabson goto out; 571dfdcada3SDoug Rabson } 572a9148abdSDoug Rabson 573a9148abdSDoug Rabson cu->cu_cwnd += (CWNDSCALE * CWNDSCALE 574a9148abdSDoug Rabson + cu->cu_cwnd / 2) / cu->cu_cwnd; 575a9148abdSDoug Rabson if (cu->cu_cwnd > MAXCWND) 576a9148abdSDoug Rabson cu->cu_cwnd = MAXCWND; 577a9148abdSDoug Rabson 578a9148abdSDoug Rabson if (rt) { 579a9148abdSDoug Rabson /* 580a9148abdSDoug Rabson * Add one to the time since a tick 581a9148abdSDoug Rabson * count of N means that the actual 582a9148abdSDoug Rabson * time taken was somewhere between N 583a9148abdSDoug Rabson * and N+1. 584a9148abdSDoug Rabson */ 585a9148abdSDoug Rabson rtt = ticks - starttime + 1; 586a9148abdSDoug Rabson 587a9148abdSDoug Rabson /* 588a9148abdSDoug Rabson * Update our estimate of the round 589a9148abdSDoug Rabson * trip time using roughly the 590a9148abdSDoug Rabson * algorithm described in RFC 591a9148abdSDoug Rabson * 2988. Given an RTT sample R: 592a9148abdSDoug Rabson * 593a9148abdSDoug Rabson * RTTVAR = (1-beta) * RTTVAR + beta * |SRTT-R| 594a9148abdSDoug Rabson * SRTT = (1-alpha) * SRTT + alpha * R 595a9148abdSDoug Rabson * 596a9148abdSDoug Rabson * where alpha = 0.125 and beta = 0.25. 597a9148abdSDoug Rabson * 598a9148abdSDoug Rabson * The initial retransmit timeout is 599a9148abdSDoug Rabson * SRTT + 4*RTTVAR and doubles on each 600a9148abdSDoug Rabson * retransmision. 601a9148abdSDoug Rabson */ 602a9148abdSDoug Rabson if (rt->rt_srtt == 0) { 603a9148abdSDoug Rabson rt->rt_srtt = rtt; 604a9148abdSDoug Rabson rt->rt_deviate = rtt / 2; 605a9148abdSDoug Rabson } else { 606a9148abdSDoug Rabson int32_t error = rtt - rt->rt_srtt; 607a9148abdSDoug Rabson rt->rt_srtt += error / 8; 608a9148abdSDoug Rabson error = abs(error) - rt->rt_deviate; 609a9148abdSDoug Rabson rt->rt_deviate += error / 4; 610a9148abdSDoug Rabson } 611a9148abdSDoug Rabson rt->rt_rtxcur = rt->rt_srtt + 4*rt->rt_deviate; 612a9148abdSDoug Rabson } 613a9148abdSDoug Rabson 614dfdcada3SDoug Rabson break; 615dfdcada3SDoug Rabson } 616dfdcada3SDoug Rabson 617dfdcada3SDoug Rabson /* 618dfdcada3SDoug Rabson * The sleep returned an error so our request is still 619dfdcada3SDoug Rabson * on the list. If we got EWOULDBLOCK, we may want to 620dfdcada3SDoug Rabson * re-send the request. 621dfdcada3SDoug Rabson */ 622dfdcada3SDoug Rabson if (error != EWOULDBLOCK) { 623a9148abdSDoug Rabson errp->re_errno = error; 624dfdcada3SDoug Rabson if (error == EINTR) 625a9148abdSDoug Rabson errp->re_status = stat = RPC_INTR; 626dfdcada3SDoug Rabson else 627a9148abdSDoug Rabson errp->re_status = stat = RPC_CANTRECV; 628dfdcada3SDoug Rabson goto out; 629dfdcada3SDoug Rabson } 630dfdcada3SDoug Rabson 631c675522fSDoug Rabson time_waited = ticks - starttime; 632dfdcada3SDoug Rabson 633dfdcada3SDoug Rabson /* Check for timeout. */ 634c675522fSDoug Rabson if (time_waited > timeout) { 635a9148abdSDoug Rabson errp->re_errno = EWOULDBLOCK; 636a9148abdSDoug Rabson errp->re_status = stat = RPC_TIMEDOUT; 637dfdcada3SDoug Rabson goto out; 638dfdcada3SDoug Rabson } 639dfdcada3SDoug Rabson 640dfdcada3SDoug Rabson /* Retransmit if necessary. */ 641c675522fSDoug Rabson if (time_waited >= next_sendtime) { 642a9148abdSDoug Rabson cu->cu_cwnd /= 2; 643a9148abdSDoug Rabson if (cu->cu_cwnd < CWNDSCALE) 644a9148abdSDoug Rabson cu->cu_cwnd = CWNDSCALE; 645c675522fSDoug Rabson if (ext && ext->rc_feedback) { 646c675522fSDoug Rabson mtx_unlock(&cs->cs_lock); 647c675522fSDoug Rabson if (retrans == 0) 648c675522fSDoug Rabson ext->rc_feedback(FEEDBACK_REXMIT1, 649c675522fSDoug Rabson proc, ext->rc_feedback_arg); 650c675522fSDoug Rabson else 651c675522fSDoug Rabson ext->rc_feedback(FEEDBACK_REXMIT2, 652c675522fSDoug Rabson proc, ext->rc_feedback_arg); 653c675522fSDoug Rabson mtx_lock(&cs->cs_lock); 654c675522fSDoug Rabson } 655a9148abdSDoug Rabson if (cu->cu_closing || cu->cu_closed) { 656a9148abdSDoug Rabson errp->re_errno = ESHUTDOWN; 657a9148abdSDoug Rabson errp->re_status = stat = RPC_CANTRECV; 658c675522fSDoug Rabson goto out; 659c675522fSDoug Rabson } 660c675522fSDoug Rabson retrans++; 661dfdcada3SDoug Rabson /* update retransmit_time */ 662c675522fSDoug Rabson if (retransmit_time < RPC_MAX_BACKOFF * hz) 663c675522fSDoug Rabson retransmit_time = 2 * retransmit_time; 664c675522fSDoug Rabson next_sendtime += retransmit_time; 665dfdcada3SDoug Rabson goto send_again; 666dfdcada3SDoug Rabson } 667c675522fSDoug Rabson TAILQ_INSERT_TAIL(&cs->cs_pending, cr, cr_link); 668dfdcada3SDoug Rabson } 669dfdcada3SDoug Rabson 670dfdcada3SDoug Rabson got_reply: 671dfdcada3SDoug Rabson /* 672dfdcada3SDoug Rabson * Now decode and validate the response. We need to drop the 673dfdcada3SDoug Rabson * lock since xdr_replymsg may end up sleeping in malloc. 674dfdcada3SDoug Rabson */ 675dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 676dfdcada3SDoug Rabson 677c675522fSDoug Rabson if (ext && ext->rc_feedback) 678c675522fSDoug Rabson ext->rc_feedback(FEEDBACK_OK, proc, ext->rc_feedback_arg); 679c675522fSDoug Rabson 680c675522fSDoug Rabson xdrmbuf_create(&xdrs, cr->cr_mrep, XDR_DECODE); 681dfdcada3SDoug Rabson ok = xdr_replymsg(&xdrs, &reply_msg); 682c675522fSDoug Rabson cr->cr_mrep = NULL; 683dfdcada3SDoug Rabson 684dfdcada3SDoug Rabson if (ok) { 685dfdcada3SDoug Rabson if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) && 686dfdcada3SDoug Rabson (reply_msg.acpted_rply.ar_stat == SUCCESS)) 687a9148abdSDoug Rabson errp->re_status = stat = RPC_SUCCESS; 688dfdcada3SDoug Rabson else 689a9148abdSDoug Rabson stat = _seterr_reply(&reply_msg, &(cu->cu_error)); 690dfdcada3SDoug Rabson 691a9148abdSDoug Rabson if (errp->re_status == RPC_SUCCESS) { 692a9148abdSDoug Rabson results = xdrmbuf_getall(&xdrs); 693a9148abdSDoug Rabson if (! AUTH_VALIDATE(auth, xid, 694a9148abdSDoug Rabson &reply_msg.acpted_rply.ar_verf, 695a9148abdSDoug Rabson &results)) { 696a9148abdSDoug Rabson errp->re_status = stat = RPC_AUTHERROR; 697a9148abdSDoug Rabson errp->re_why = AUTH_INVALIDRESP; 698a9148abdSDoug Rabson if (retrans && 699a9148abdSDoug Rabson auth->ah_cred.oa_flavor == RPCSEC_GSS) { 700a9148abdSDoug Rabson /* 701a9148abdSDoug Rabson * If we retransmitted, its 702a9148abdSDoug Rabson * possible that we will 703a9148abdSDoug Rabson * receive a reply for one of 704a9148abdSDoug Rabson * the earlier transmissions 705a9148abdSDoug Rabson * (which will use an older 706a9148abdSDoug Rabson * RPCSEC_GSS sequence 707a9148abdSDoug Rabson * number). In this case, just 708a9148abdSDoug Rabson * go back and listen for a 709a9148abdSDoug Rabson * new reply. We could keep a 710a9148abdSDoug Rabson * record of all the seq 711a9148abdSDoug Rabson * numbers we have transmitted 712a9148abdSDoug Rabson * so far so that we could 713a9148abdSDoug Rabson * accept a reply for any of 714a9148abdSDoug Rabson * them here. 715a9148abdSDoug Rabson */ 716a9148abdSDoug Rabson XDR_DESTROY(&xdrs); 717a9148abdSDoug Rabson mtx_lock(&cs->cs_lock); 718a9148abdSDoug Rabson TAILQ_INSERT_TAIL(&cs->cs_pending, 719a9148abdSDoug Rabson cr, cr_link); 720a9148abdSDoug Rabson cr->cr_mrep = NULL; 721a9148abdSDoug Rabson goto get_reply; 722dfdcada3SDoug Rabson } 723a9148abdSDoug Rabson } else { 724a9148abdSDoug Rabson *resultsp = results; 725dfdcada3SDoug Rabson } 726dfdcada3SDoug Rabson } /* end successful completion */ 727dfdcada3SDoug Rabson /* 728dfdcada3SDoug Rabson * If unsuccesful AND error is an authentication error 729dfdcada3SDoug Rabson * then refresh credentials and try again, else break 730dfdcada3SDoug Rabson */ 731a9148abdSDoug Rabson else if (stat == RPC_AUTHERROR) 732dfdcada3SDoug Rabson /* maybe our credentials need to be refreshed ... */ 733dfdcada3SDoug Rabson if (nrefreshes > 0 && 734a9148abdSDoug Rabson AUTH_REFRESH(auth, &reply_msg)) { 735dfdcada3SDoug Rabson nrefreshes--; 736a9148abdSDoug Rabson XDR_DESTROY(&xdrs); 737a9148abdSDoug Rabson mtx_lock(&cs->cs_lock); 738dfdcada3SDoug Rabson goto call_again; 739dfdcada3SDoug Rabson } 740dfdcada3SDoug Rabson /* end of unsuccessful completion */ 741dfdcada3SDoug Rabson } /* end of valid reply message */ 742dfdcada3SDoug Rabson else { 743a9148abdSDoug Rabson errp->re_status = stat = RPC_CANTDECODERES; 744dfdcada3SDoug Rabson 745dfdcada3SDoug Rabson } 746a9148abdSDoug Rabson XDR_DESTROY(&xdrs); 747a9148abdSDoug Rabson mtx_lock(&cs->cs_lock); 748dfdcada3SDoug Rabson out: 749dfdcada3SDoug Rabson mtx_assert(&cs->cs_lock, MA_OWNED); 750dfdcada3SDoug Rabson 751dfdcada3SDoug Rabson if (mreq) 752dfdcada3SDoug Rabson m_freem(mreq); 753c675522fSDoug Rabson if (cr->cr_mrep) 754c675522fSDoug Rabson m_freem(cr->cr_mrep); 755c675522fSDoug Rabson 756c675522fSDoug Rabson cu->cu_threads--; 757c675522fSDoug Rabson if (cu->cu_closing) 758c675522fSDoug Rabson wakeup(cu); 759dfdcada3SDoug Rabson 760dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 761c675522fSDoug Rabson 762a9148abdSDoug Rabson if (auth && stat != RPC_SUCCESS) 763a9148abdSDoug Rabson AUTH_VALIDATE(auth, xid, NULL, NULL); 764a9148abdSDoug Rabson 765c675522fSDoug Rabson free(cr, M_RPC); 766c675522fSDoug Rabson 767a9148abdSDoug Rabson return (stat); 768dfdcada3SDoug Rabson } 769dfdcada3SDoug Rabson 770dfdcada3SDoug Rabson static void 771dfdcada3SDoug Rabson clnt_dg_geterr(CLIENT *cl, struct rpc_err *errp) 772dfdcada3SDoug Rabson { 773dfdcada3SDoug Rabson struct cu_data *cu = (struct cu_data *)cl->cl_private; 774dfdcada3SDoug Rabson 775dfdcada3SDoug Rabson *errp = cu->cu_error; 776dfdcada3SDoug Rabson } 777dfdcada3SDoug Rabson 778dfdcada3SDoug Rabson static bool_t 779dfdcada3SDoug Rabson clnt_dg_freeres(CLIENT *cl, xdrproc_t xdr_res, void *res_ptr) 780dfdcada3SDoug Rabson { 781dfdcada3SDoug Rabson XDR xdrs; 782dfdcada3SDoug Rabson bool_t dummy; 783dfdcada3SDoug Rabson 784dfdcada3SDoug Rabson xdrs.x_op = XDR_FREE; 785dfdcada3SDoug Rabson dummy = (*xdr_res)(&xdrs, res_ptr); 786dfdcada3SDoug Rabson 787dfdcada3SDoug Rabson return (dummy); 788dfdcada3SDoug Rabson } 789dfdcada3SDoug Rabson 790dfdcada3SDoug Rabson /*ARGSUSED*/ 791dfdcada3SDoug Rabson static void 792dfdcada3SDoug Rabson clnt_dg_abort(CLIENT *h) 793dfdcada3SDoug Rabson { 794dfdcada3SDoug Rabson } 795dfdcada3SDoug Rabson 796dfdcada3SDoug Rabson static bool_t 797dfdcada3SDoug Rabson clnt_dg_control(CLIENT *cl, u_int request, void *info) 798dfdcada3SDoug Rabson { 799dfdcada3SDoug Rabson struct cu_data *cu = (struct cu_data *)cl->cl_private; 800dfdcada3SDoug Rabson struct cu_socket *cs = (struct cu_socket *) cu->cu_socket->so_upcallarg; 801dfdcada3SDoug Rabson struct sockaddr *addr; 802dfdcada3SDoug Rabson 803dfdcada3SDoug Rabson mtx_lock(&cs->cs_lock); 804dfdcada3SDoug Rabson 805dfdcada3SDoug Rabson switch (request) { 806dfdcada3SDoug Rabson case CLSET_FD_CLOSE: 807dfdcada3SDoug Rabson cu->cu_closeit = TRUE; 808dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 809dfdcada3SDoug Rabson return (TRUE); 810dfdcada3SDoug Rabson case CLSET_FD_NCLOSE: 811dfdcada3SDoug Rabson cu->cu_closeit = FALSE; 812dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 813dfdcada3SDoug Rabson return (TRUE); 814dfdcada3SDoug Rabson } 815dfdcada3SDoug Rabson 816dfdcada3SDoug Rabson /* for other requests which use info */ 817dfdcada3SDoug Rabson if (info == NULL) { 818dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 819dfdcada3SDoug Rabson return (FALSE); 820dfdcada3SDoug Rabson } 821dfdcada3SDoug Rabson switch (request) { 822dfdcada3SDoug Rabson case CLSET_TIMEOUT: 823dfdcada3SDoug Rabson if (time_not_ok((struct timeval *)info)) { 824dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 825dfdcada3SDoug Rabson return (FALSE); 826dfdcada3SDoug Rabson } 827dfdcada3SDoug Rabson cu->cu_total = *(struct timeval *)info; 828dfdcada3SDoug Rabson break; 829dfdcada3SDoug Rabson case CLGET_TIMEOUT: 830dfdcada3SDoug Rabson *(struct timeval *)info = cu->cu_total; 831dfdcada3SDoug Rabson break; 832dfdcada3SDoug Rabson case CLSET_RETRY_TIMEOUT: 833dfdcada3SDoug Rabson if (time_not_ok((struct timeval *)info)) { 834dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 835dfdcada3SDoug Rabson return (FALSE); 836dfdcada3SDoug Rabson } 837dfdcada3SDoug Rabson cu->cu_wait = *(struct timeval *)info; 838dfdcada3SDoug Rabson break; 839dfdcada3SDoug Rabson case CLGET_RETRY_TIMEOUT: 840dfdcada3SDoug Rabson *(struct timeval *)info = cu->cu_wait; 841dfdcada3SDoug Rabson break; 842dfdcada3SDoug Rabson case CLGET_SVC_ADDR: 843dfdcada3SDoug Rabson /* 844dfdcada3SDoug Rabson * Slightly different semantics to userland - we use 845dfdcada3SDoug Rabson * sockaddr instead of netbuf. 846dfdcada3SDoug Rabson */ 847dfdcada3SDoug Rabson memcpy(info, &cu->cu_raddr, cu->cu_raddr.ss_len); 848dfdcada3SDoug Rabson break; 849dfdcada3SDoug Rabson case CLSET_SVC_ADDR: /* set to new address */ 850dfdcada3SDoug Rabson addr = (struct sockaddr *)info; 851dfdcada3SDoug Rabson (void) memcpy(&cu->cu_raddr, addr, addr->sa_len); 852dfdcada3SDoug Rabson break; 853dfdcada3SDoug Rabson case CLGET_XID: 854dfdcada3SDoug Rabson *(uint32_t *)info = cu->cu_xid; 855dfdcada3SDoug Rabson break; 856dfdcada3SDoug Rabson 857dfdcada3SDoug Rabson case CLSET_XID: 858dfdcada3SDoug Rabson /* This will set the xid of the NEXT call */ 859dfdcada3SDoug Rabson /* decrement by 1 as clnt_dg_call() increments once */ 860dfdcada3SDoug Rabson cu->cu_xid = *(uint32_t *)info - 1; 861dfdcada3SDoug Rabson break; 862dfdcada3SDoug Rabson 863dfdcada3SDoug Rabson case CLGET_VERS: 864dfdcada3SDoug Rabson /* 865dfdcada3SDoug Rabson * This RELIES on the information that, in the call body, 866dfdcada3SDoug Rabson * the version number field is the fifth field from the 867dfdcada3SDoug Rabson * begining of the RPC header. MUST be changed if the 868dfdcada3SDoug Rabson * call_struct is changed 869dfdcada3SDoug Rabson */ 870dfdcada3SDoug Rabson *(uint32_t *)info = 871dfdcada3SDoug Rabson ntohl(*(uint32_t *)(void *)(cu->cu_mcallc + 872dfdcada3SDoug Rabson 4 * BYTES_PER_XDR_UNIT)); 873dfdcada3SDoug Rabson break; 874dfdcada3SDoug Rabson 875dfdcada3SDoug Rabson case CLSET_VERS: 876dfdcada3SDoug Rabson *(uint32_t *)(void *)(cu->cu_mcallc + 4 * BYTES_PER_XDR_UNIT) 877dfdcada3SDoug Rabson = htonl(*(uint32_t *)info); 878dfdcada3SDoug Rabson break; 879dfdcada3SDoug Rabson 880dfdcada3SDoug Rabson case CLGET_PROG: 881dfdcada3SDoug Rabson /* 882dfdcada3SDoug Rabson * This RELIES on the information that, in the call body, 883dfdcada3SDoug Rabson * the program number field is the fourth field from the 884dfdcada3SDoug Rabson * begining of the RPC header. MUST be changed if the 885dfdcada3SDoug Rabson * call_struct is changed 886dfdcada3SDoug Rabson */ 887dfdcada3SDoug Rabson *(uint32_t *)info = 888dfdcada3SDoug Rabson ntohl(*(uint32_t *)(void *)(cu->cu_mcallc + 889dfdcada3SDoug Rabson 3 * BYTES_PER_XDR_UNIT)); 890dfdcada3SDoug Rabson break; 891dfdcada3SDoug Rabson 892dfdcada3SDoug Rabson case CLSET_PROG: 893dfdcada3SDoug Rabson *(uint32_t *)(void *)(cu->cu_mcallc + 3 * BYTES_PER_XDR_UNIT) 894dfdcada3SDoug Rabson = htonl(*(uint32_t *)info); 895dfdcada3SDoug Rabson break; 896dfdcada3SDoug Rabson case CLSET_ASYNC: 897dfdcada3SDoug Rabson cu->cu_async = *(int *)info; 898dfdcada3SDoug Rabson break; 899dfdcada3SDoug Rabson case CLSET_CONNECT: 900dfdcada3SDoug Rabson cu->cu_connect = *(int *)info; 901dfdcada3SDoug Rabson break; 902dfdcada3SDoug Rabson case CLSET_WAITCHAN: 903a9148abdSDoug Rabson cu->cu_waitchan = (const char *)info; 904dfdcada3SDoug Rabson break; 905dfdcada3SDoug Rabson case CLGET_WAITCHAN: 906dfdcada3SDoug Rabson *(const char **) info = cu->cu_waitchan; 907dfdcada3SDoug Rabson break; 908dfdcada3SDoug Rabson case CLSET_INTERRUPTIBLE: 909dfdcada3SDoug Rabson if (*(int *) info) 910dfdcada3SDoug Rabson cu->cu_waitflag = PCATCH; 911dfdcada3SDoug Rabson else 912dfdcada3SDoug Rabson cu->cu_waitflag = 0; 913dfdcada3SDoug Rabson break; 914dfdcada3SDoug Rabson case CLGET_INTERRUPTIBLE: 915dfdcada3SDoug Rabson if (cu->cu_waitflag) 916dfdcada3SDoug Rabson *(int *) info = TRUE; 917dfdcada3SDoug Rabson else 918dfdcada3SDoug Rabson *(int *) info = FALSE; 919dfdcada3SDoug Rabson break; 920dfdcada3SDoug Rabson default: 921dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 922dfdcada3SDoug Rabson return (FALSE); 923dfdcada3SDoug Rabson } 924dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 925dfdcada3SDoug Rabson return (TRUE); 926dfdcada3SDoug Rabson } 927dfdcada3SDoug Rabson 928dfdcada3SDoug Rabson static void 929a9148abdSDoug Rabson clnt_dg_close(CLIENT *cl) 930dfdcada3SDoug Rabson { 931dfdcada3SDoug Rabson struct cu_data *cu = (struct cu_data *)cl->cl_private; 932dfdcada3SDoug Rabson struct cu_socket *cs = (struct cu_socket *) cu->cu_socket->so_upcallarg; 933c675522fSDoug Rabson struct cu_request *cr; 934dfdcada3SDoug Rabson 935dfdcada3SDoug Rabson mtx_lock(&cs->cs_lock); 936c675522fSDoug Rabson 937a9148abdSDoug Rabson if (cu->cu_closed) { 938a9148abdSDoug Rabson mtx_unlock(&cs->cs_lock); 939a9148abdSDoug Rabson return; 940a9148abdSDoug Rabson } 941a9148abdSDoug Rabson 942a9148abdSDoug Rabson if (cu->cu_closing) { 943a9148abdSDoug Rabson while (cu->cu_closing) 944a9148abdSDoug Rabson msleep(cu, &cs->cs_lock, 0, "rpcclose", 0); 945a9148abdSDoug Rabson KASSERT(cu->cu_closed, ("client should be closed")); 946a9148abdSDoug Rabson mtx_unlock(&cs->cs_lock); 947a9148abdSDoug Rabson return; 948a9148abdSDoug Rabson } 949a9148abdSDoug Rabson 950c675522fSDoug Rabson /* 951c675522fSDoug Rabson * Abort any pending requests and wait until everyone 952c675522fSDoug Rabson * has finished with clnt_vc_call. 953c675522fSDoug Rabson */ 954c675522fSDoug Rabson cu->cu_closing = TRUE; 955c675522fSDoug Rabson TAILQ_FOREACH(cr, &cs->cs_pending, cr_link) { 956c675522fSDoug Rabson if (cr->cr_client == cl) { 957c675522fSDoug Rabson cr->cr_xid = 0; 958c675522fSDoug Rabson cr->cr_error = ESHUTDOWN; 959c675522fSDoug Rabson wakeup(cr); 960c675522fSDoug Rabson } 961c675522fSDoug Rabson } 962c675522fSDoug Rabson 963c675522fSDoug Rabson while (cu->cu_threads) 964c675522fSDoug Rabson msleep(cu, &cs->cs_lock, 0, "rpcclose", 0); 965c675522fSDoug Rabson 966a9148abdSDoug Rabson cu->cu_closing = FALSE; 967a9148abdSDoug Rabson cu->cu_closed = TRUE; 968a9148abdSDoug Rabson 969a9148abdSDoug Rabson mtx_unlock(&cs->cs_lock); 970a9148abdSDoug Rabson wakeup(cu); 971a9148abdSDoug Rabson } 972a9148abdSDoug Rabson 973a9148abdSDoug Rabson static void 974a9148abdSDoug Rabson clnt_dg_destroy(CLIENT *cl) 975a9148abdSDoug Rabson { 976a9148abdSDoug Rabson struct cu_data *cu = (struct cu_data *)cl->cl_private; 977a9148abdSDoug Rabson struct cu_socket *cs = (struct cu_socket *) cu->cu_socket->so_upcallarg; 978a9148abdSDoug Rabson struct socket *so = NULL; 979a9148abdSDoug Rabson bool_t lastsocketref; 980a9148abdSDoug Rabson 981a9148abdSDoug Rabson clnt_dg_close(cl); 982a9148abdSDoug Rabson 983a9148abdSDoug Rabson mtx_lock(&cs->cs_lock); 984a9148abdSDoug Rabson 985dfdcada3SDoug Rabson cs->cs_refs--; 986dfdcada3SDoug Rabson if (cs->cs_refs == 0) { 987c675522fSDoug Rabson mtx_destroy(&cs->cs_lock); 988c675522fSDoug Rabson SOCKBUF_LOCK(&cu->cu_socket->so_rcv); 989dfdcada3SDoug Rabson cu->cu_socket->so_upcallarg = NULL; 990dfdcada3SDoug Rabson cu->cu_socket->so_upcall = NULL; 991dfdcada3SDoug Rabson cu->cu_socket->so_rcv.sb_flags &= ~SB_UPCALL; 992dfdcada3SDoug Rabson SOCKBUF_UNLOCK(&cu->cu_socket->so_rcv); 993dfdcada3SDoug Rabson mem_free(cs, sizeof(*cs)); 994dfdcada3SDoug Rabson lastsocketref = TRUE; 995dfdcada3SDoug Rabson } else { 996dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 997dfdcada3SDoug Rabson lastsocketref = FALSE; 998dfdcada3SDoug Rabson } 999dfdcada3SDoug Rabson 1000c675522fSDoug Rabson if (cu->cu_closeit && lastsocketref) { 1001dfdcada3SDoug Rabson so = cu->cu_socket; 1002dfdcada3SDoug Rabson cu->cu_socket = NULL; 1003dfdcada3SDoug Rabson } 1004dfdcada3SDoug Rabson 1005dfdcada3SDoug Rabson if (so) 1006dfdcada3SDoug Rabson soclose(so); 1007dfdcada3SDoug Rabson 1008dfdcada3SDoug Rabson if (cl->cl_netid && cl->cl_netid[0]) 1009dfdcada3SDoug Rabson mem_free(cl->cl_netid, strlen(cl->cl_netid) +1); 1010dfdcada3SDoug Rabson if (cl->cl_tp && cl->cl_tp[0]) 1011dfdcada3SDoug Rabson mem_free(cl->cl_tp, strlen(cl->cl_tp) +1); 1012dfdcada3SDoug Rabson mem_free(cu, sizeof (*cu)); 1013dfdcada3SDoug Rabson mem_free(cl, sizeof (CLIENT)); 1014dfdcada3SDoug Rabson } 1015dfdcada3SDoug Rabson 1016dfdcada3SDoug Rabson /* 1017dfdcada3SDoug Rabson * Make sure that the time is not garbage. -1 value is allowed. 1018dfdcada3SDoug Rabson */ 1019dfdcada3SDoug Rabson static bool_t 1020dfdcada3SDoug Rabson time_not_ok(struct timeval *t) 1021dfdcada3SDoug Rabson { 1022dfdcada3SDoug Rabson return (t->tv_sec < -1 || t->tv_sec > 100000000 || 1023dfdcada3SDoug Rabson t->tv_usec < -1 || t->tv_usec > 1000000); 1024dfdcada3SDoug Rabson } 1025dfdcada3SDoug Rabson 1026dfdcada3SDoug Rabson void 1027dfdcada3SDoug Rabson clnt_dg_soupcall(struct socket *so, void *arg, int waitflag) 1028dfdcada3SDoug Rabson { 1029dfdcada3SDoug Rabson struct cu_socket *cs = (struct cu_socket *) arg; 1030dfdcada3SDoug Rabson struct uio uio; 1031dfdcada3SDoug Rabson struct mbuf *m; 1032dfdcada3SDoug Rabson struct mbuf *control; 1033dfdcada3SDoug Rabson struct cu_request *cr; 1034dfdcada3SDoug Rabson int error, rcvflag, foundreq; 1035dfdcada3SDoug Rabson uint32_t xid; 1036dfdcada3SDoug Rabson 1037dfdcada3SDoug Rabson uio.uio_resid = 1000000000; 1038dfdcada3SDoug Rabson uio.uio_td = curthread; 1039dfdcada3SDoug Rabson do { 1040dfdcada3SDoug Rabson m = NULL; 1041dfdcada3SDoug Rabson control = NULL; 1042dfdcada3SDoug Rabson rcvflag = MSG_DONTWAIT; 1043dfdcada3SDoug Rabson error = soreceive(so, NULL, &uio, &m, &control, &rcvflag); 1044dfdcada3SDoug Rabson if (control) 1045dfdcada3SDoug Rabson m_freem(control); 1046dfdcada3SDoug Rabson 1047dfdcada3SDoug Rabson if (error == EWOULDBLOCK) 1048dfdcada3SDoug Rabson break; 1049dfdcada3SDoug Rabson 1050dfdcada3SDoug Rabson /* 1051dfdcada3SDoug Rabson * If there was an error, wake up all pending 1052dfdcada3SDoug Rabson * requests. 1053dfdcada3SDoug Rabson */ 1054dfdcada3SDoug Rabson if (error) { 1055dfdcada3SDoug Rabson mtx_lock(&cs->cs_lock); 1056dfdcada3SDoug Rabson TAILQ_FOREACH(cr, &cs->cs_pending, cr_link) { 1057c675522fSDoug Rabson cr->cr_xid = 0; 1058dfdcada3SDoug Rabson cr->cr_error = error; 1059dfdcada3SDoug Rabson wakeup(cr); 1060dfdcada3SDoug Rabson } 1061dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 1062dfdcada3SDoug Rabson break; 1063dfdcada3SDoug Rabson } 1064dfdcada3SDoug Rabson 1065dfdcada3SDoug Rabson /* 1066dfdcada3SDoug Rabson * The XID is in the first uint32_t of the reply. 1067dfdcada3SDoug Rabson */ 1068a9148abdSDoug Rabson if (m->m_len < sizeof(xid)) 1069dfdcada3SDoug Rabson m = m_pullup(m, sizeof(xid)); 1070dfdcada3SDoug Rabson if (!m) 1071c675522fSDoug Rabson /* 1072c675522fSDoug Rabson * Should never happen. 1073c675522fSDoug Rabson */ 1074c675522fSDoug Rabson continue; 1075c675522fSDoug Rabson 1076dfdcada3SDoug Rabson xid = ntohl(*mtod(m, uint32_t *)); 1077dfdcada3SDoug Rabson 1078dfdcada3SDoug Rabson /* 1079dfdcada3SDoug Rabson * Attempt to match this reply with a pending request. 1080dfdcada3SDoug Rabson */ 1081dfdcada3SDoug Rabson mtx_lock(&cs->cs_lock); 1082dfdcada3SDoug Rabson foundreq = 0; 1083dfdcada3SDoug Rabson TAILQ_FOREACH(cr, &cs->cs_pending, cr_link) { 1084dfdcada3SDoug Rabson if (cr->cr_xid == xid) { 1085dfdcada3SDoug Rabson /* 1086c675522fSDoug Rabson * This one matches. We leave the 1087dfdcada3SDoug Rabson * reply mbuf in cr->cr_mrep. Set the 1088c675522fSDoug Rabson * XID to zero so that we will ignore 1089c675522fSDoug Rabson * any duplicated replies that arrive 1090c675522fSDoug Rabson * before clnt_dg_call removes it from 1091c675522fSDoug Rabson * the queue. 1092dfdcada3SDoug Rabson */ 1093dfdcada3SDoug Rabson cr->cr_xid = 0; 1094dfdcada3SDoug Rabson cr->cr_mrep = m; 1095dfdcada3SDoug Rabson cr->cr_error = 0; 1096dfdcada3SDoug Rabson foundreq = 1; 1097dfdcada3SDoug Rabson wakeup(cr); 1098dfdcada3SDoug Rabson break; 1099dfdcada3SDoug Rabson } 1100dfdcada3SDoug Rabson } 1101dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 1102dfdcada3SDoug Rabson 1103dfdcada3SDoug Rabson /* 1104dfdcada3SDoug Rabson * If we didn't find the matching request, just drop 1105dfdcada3SDoug Rabson * it - its probably a repeated reply. 1106dfdcada3SDoug Rabson */ 1107dfdcada3SDoug Rabson if (!foundreq) 1108dfdcada3SDoug Rabson m_freem(m); 1109dfdcada3SDoug Rabson } while (m); 1110dfdcada3SDoug Rabson } 1111dfdcada3SDoug Rabson 1112