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 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 26 /* All Rights Reserved */ 27 28 /* 29 * Portions of this source code were derived from Berkeley 4.3 BSD 30 * under license from the Regents of the University of California. 31 */ 32 33 /* 34 * svc_clts.c 35 * Server side for RPC in the kernel. 36 * 37 */ 38 39 #include <sys/param.h> 40 #include <sys/types.h> 41 #include <sys/sysmacros.h> 42 #include <sys/file.h> 43 #include <sys/stream.h> 44 #include <sys/strsubr.h> 45 #include <sys/tihdr.h> 46 #include <sys/tiuser.h> 47 #include <sys/t_kuser.h> 48 #include <sys/fcntl.h> 49 #include <sys/errno.h> 50 #include <sys/kmem.h> 51 #include <sys/systm.h> 52 #include <sys/cmn_err.h> 53 #include <sys/kstat.h> 54 #include <sys/vtrace.h> 55 #include <sys/debug.h> 56 57 #include <rpc/types.h> 58 #include <rpc/xdr.h> 59 #include <rpc/auth.h> 60 #include <rpc/clnt.h> 61 #include <rpc/rpc_msg.h> 62 #include <rpc/svc.h> 63 #include <inet/ip.h> 64 65 /* 66 * Routines exported through ops vector. 67 */ 68 static bool_t svc_clts_krecv(SVCXPRT *, mblk_t *, struct rpc_msg *); 69 static bool_t svc_clts_ksend(SVCXPRT *, struct rpc_msg *); 70 static bool_t svc_clts_kgetargs(SVCXPRT *, xdrproc_t, caddr_t); 71 static bool_t svc_clts_kfreeargs(SVCXPRT *, xdrproc_t, caddr_t); 72 static void svc_clts_kdestroy(SVCMASTERXPRT *); 73 static int svc_clts_kdup(struct svc_req *, caddr_t, int, 74 struct dupreq **, bool_t *); 75 static void svc_clts_kdupdone(struct dupreq *, caddr_t, 76 void (*)(), int, int); 77 static int32_t *svc_clts_kgetres(SVCXPRT *, int); 78 static void svc_clts_kclone_destroy(SVCXPRT *); 79 static void svc_clts_kfreeres(SVCXPRT *); 80 static void svc_clts_kstart(SVCMASTERXPRT *); 81 static void svc_clts_kclone_xprt(SVCXPRT *, SVCXPRT *); 82 static void svc_clts_ktattrs(SVCXPRT *, int, void **); 83 84 /* 85 * Server transport operations vector. 86 */ 87 struct svc_ops svc_clts_op = { 88 svc_clts_krecv, /* Get requests */ 89 svc_clts_kgetargs, /* Deserialize arguments */ 90 svc_clts_ksend, /* Send reply */ 91 svc_clts_kfreeargs, /* Free argument data space */ 92 svc_clts_kdestroy, /* Destroy transport handle */ 93 svc_clts_kdup, /* Check entry in dup req cache */ 94 svc_clts_kdupdone, /* Mark entry in dup req cache as done */ 95 svc_clts_kgetres, /* Get pointer to response buffer */ 96 svc_clts_kfreeres, /* Destroy pre-serialized response header */ 97 svc_clts_kclone_destroy, /* Destroy a clone xprt */ 98 svc_clts_kstart, /* Tell `ready-to-receive' to rpcmod */ 99 svc_clts_kclone_xprt, /* transport specific clone xprt function */ 100 svc_clts_ktattrs /* Transport specific attributes. */ 101 }; 102 103 /* 104 * Transport private data. 105 * Kept in xprt->xp_p2buf. 106 */ 107 struct udp_data { 108 mblk_t *ud_resp; /* buffer for response */ 109 mblk_t *ud_inmp; /* mblk chain of request */ 110 }; 111 112 #define UD_MAXSIZE 8800 113 #define UD_INITSIZE 2048 114 115 /* 116 * Connectionless server statistics 117 */ 118 static const struct rpc_clts_server { 119 kstat_named_t rscalls; 120 kstat_named_t rsbadcalls; 121 kstat_named_t rsnullrecv; 122 kstat_named_t rsbadlen; 123 kstat_named_t rsxdrcall; 124 kstat_named_t rsdupchecks; 125 kstat_named_t rsdupreqs; 126 } clts_rsstat_tmpl = { 127 { "calls", KSTAT_DATA_UINT64 }, 128 { "badcalls", KSTAT_DATA_UINT64 }, 129 { "nullrecv", KSTAT_DATA_UINT64 }, 130 { "badlen", KSTAT_DATA_UINT64 }, 131 { "xdrcall", KSTAT_DATA_UINT64 }, 132 { "dupchecks", KSTAT_DATA_UINT64 }, 133 { "dupreqs", KSTAT_DATA_UINT64 } 134 }; 135 136 static uint_t clts_rsstat_ndata = 137 sizeof (clts_rsstat_tmpl) / sizeof (kstat_named_t); 138 139 #define CLONE2STATS(clone_xprt) \ 140 (struct rpc_clts_server *)(clone_xprt)->xp_master->xp_p2 141 142 #define RSSTAT_INCR(stats, x) \ 143 atomic_add_64(&(stats)->x.value.ui64, 1) 144 145 /* 146 * Create a transport record. 147 * The transport record, output buffer, and private data structure 148 * are allocated. The output buffer is serialized into using xdrmem. 149 * There is one transport record per user process which implements a 150 * set of services. 151 */ 152 /* ARGSUSED */ 153 int 154 svc_clts_kcreate(file_t *fp, uint_t sendsz, struct T_info_ack *tinfo, 155 SVCMASTERXPRT **nxprt) 156 { 157 SVCMASTERXPRT *xprt; 158 struct rpcstat *rpcstat; 159 160 if (nxprt == NULL) 161 return (EINVAL); 162 163 rpcstat = zone_getspecific(rpcstat_zone_key, curproc->p_zone); 164 ASSERT(rpcstat != NULL); 165 166 xprt = kmem_zalloc(sizeof (*xprt), KM_SLEEP); 167 xprt->xp_lcladdr.buf = kmem_zalloc(sizeof (sin6_t), KM_SLEEP); 168 xprt->xp_p2 = (caddr_t)rpcstat->rpc_clts_server; 169 xprt->xp_ops = &svc_clts_op; 170 xprt->xp_msg_size = tinfo->TSDU_size; 171 172 xprt->xp_rtaddr.buf = NULL; 173 xprt->xp_rtaddr.maxlen = tinfo->ADDR_size; 174 xprt->xp_rtaddr.len = 0; 175 176 *nxprt = xprt; 177 178 return (0); 179 } 180 181 /* 182 * Destroy a transport record. 183 * Frees the space allocated for a transport record. 184 */ 185 static void 186 svc_clts_kdestroy(SVCMASTERXPRT *xprt) 187 { 188 if (xprt->xp_netid) 189 kmem_free(xprt->xp_netid, strlen(xprt->xp_netid) + 1); 190 if (xprt->xp_addrmask.maxlen) 191 kmem_free(xprt->xp_addrmask.buf, xprt->xp_addrmask.maxlen); 192 193 mutex_destroy(&xprt->xp_req_lock); 194 mutex_destroy(&xprt->xp_thread_lock); 195 196 kmem_free(xprt->xp_lcladdr.buf, sizeof (sin6_t)); 197 kmem_free(xprt, sizeof (SVCMASTERXPRT)); 198 } 199 200 /* 201 * Transport-type specific part of svc_xprt_cleanup(). 202 * Frees the message buffer space allocated for a clone of a transport record 203 */ 204 static void 205 svc_clts_kclone_destroy(SVCXPRT *clone_xprt) 206 { 207 /* LINTED pointer alignment */ 208 struct udp_data *ud = (struct udp_data *)clone_xprt->xp_p2buf; 209 210 if (ud->ud_resp) { 211 /* 212 * There should not be any left over results buffer. 213 */ 214 ASSERT(ud->ud_resp->b_cont == NULL); 215 216 /* 217 * Free the T_UNITDATA_{REQ/IND} that svc_clts_krecv 218 * saved. 219 */ 220 freeb(ud->ud_resp); 221 } 222 if (ud->ud_inmp) 223 freemsg(ud->ud_inmp); 224 } 225 226 /* 227 * svc_tli_kcreate() calls this function at the end to tell 228 * rpcmod that the transport is ready to receive requests. 229 */ 230 /* ARGSUSED */ 231 static void 232 svc_clts_kstart(SVCMASTERXPRT *xprt) 233 { 234 } 235 236 static void 237 svc_clts_kclone_xprt(SVCXPRT *src_xprt, SVCXPRT *dst_xprt) 238 { 239 struct udp_data *ud_src = 240 (struct udp_data *)src_xprt->xp_p2buf; 241 struct udp_data *ud_dst = 242 (struct udp_data *)dst_xprt->xp_p2buf; 243 244 if (ud_src->ud_resp) 245 ud_dst->ud_resp = dupb(ud_src->ud_resp); 246 247 } 248 249 static void 250 svc_clts_ktattrs(SVCXPRT *clone_xprt, int attrflag, void **tattr) 251 { 252 *tattr = NULL; 253 254 switch (attrflag) { 255 case SVC_TATTR_ADDRMASK: 256 *tattr = (void *)&clone_xprt->xp_master->xp_addrmask; 257 } 258 } 259 260 /* 261 * Receive rpc requests. 262 * Pulls a request in off the socket, checks if the packet is intact, 263 * and deserializes the call packet. 264 */ 265 static bool_t 266 svc_clts_krecv(SVCXPRT *clone_xprt, mblk_t *mp, struct rpc_msg *msg) 267 { 268 /* LINTED pointer alignment */ 269 struct udp_data *ud = (struct udp_data *)clone_xprt->xp_p2buf; 270 XDR *xdrs = &clone_xprt->xp_xdrin; 271 struct rpc_clts_server *stats = CLONE2STATS(clone_xprt); 272 union T_primitives *pptr; 273 int hdrsz; 274 cred_t *cr; 275 276 TRACE_0(TR_FAC_KRPC, TR_SVC_CLTS_KRECV_START, 277 "svc_clts_krecv_start:"); 278 279 RSSTAT_INCR(stats, rscalls); 280 281 /* 282 * The incoming request should start with an M_PROTO message. 283 */ 284 if (mp->b_datap->db_type != M_PROTO) { 285 goto bad; 286 } 287 288 /* 289 * The incoming request should be an T_UNITDTA_IND. There 290 * might be other messages coming up the stream, but we can 291 * ignore them. 292 */ 293 pptr = (union T_primitives *)mp->b_rptr; 294 if (pptr->type != T_UNITDATA_IND) { 295 goto bad; 296 } 297 /* 298 * Do some checking to make sure that the header at least looks okay. 299 */ 300 hdrsz = (int)(mp->b_wptr - mp->b_rptr); 301 if (hdrsz < TUNITDATAINDSZ || 302 hdrsz < (pptr->unitdata_ind.OPT_offset + 303 pptr->unitdata_ind.OPT_length) || 304 hdrsz < (pptr->unitdata_ind.SRC_offset + 305 pptr->unitdata_ind.SRC_length)) { 306 goto bad; 307 } 308 309 /* 310 * Make sure that the transport provided a usable address. 311 */ 312 if (pptr->unitdata_ind.SRC_length <= 0) { 313 goto bad; 314 } 315 /* 316 * Point the remote transport address in the service_transport 317 * handle at the address in the request. 318 */ 319 clone_xprt->xp_rtaddr.buf = (char *)mp->b_rptr + 320 pptr->unitdata_ind.SRC_offset; 321 clone_xprt->xp_rtaddr.len = pptr->unitdata_ind.SRC_length; 322 323 /* 324 * Copy the local transport address in the service_transport 325 * handle at the address in the request. We will have only 326 * the local IP address in options. 327 */ 328 if (pptr->unitdata_ind.OPT_length && pptr->unitdata_ind.OPT_offset) { 329 char *dstopt = (char *)mp->b_rptr + 330 pptr->unitdata_ind.OPT_offset; 331 struct T_opthdr *toh = (struct T_opthdr *)dstopt; 332 333 if (toh->level == IPPROTO_IPV6 && toh->status == 0 && 334 toh->name == IPV6_PKTINFO) { 335 struct in6_pktinfo *pkti; 336 337 dstopt += sizeof (struct T_opthdr); 338 pkti = (struct in6_pktinfo *)dstopt; 339 ((sin6_t *)(clone_xprt->xp_lcladdr.buf))->sin6_addr 340 = pkti->ipi6_addr; 341 } else if (toh->level == IPPROTO_IP && toh->status == 0 && 342 toh->name == IP_RECVDSTADDR) { 343 dstopt += sizeof (struct T_opthdr); 344 ((sin_t *)(clone_xprt->xp_lcladdr.buf))->sin_addr 345 = *(struct in_addr *)dstopt; 346 } 347 } 348 349 /* 350 * Save the first mblk which contains the T_unidata_ind in 351 * ud_resp. It will be used to generate the T_unitdata_req 352 * during the reply. 353 * We reuse any options in the T_unitdata_ind for the T_unitdata_req 354 * since we must pass any SCM_UCRED across in order for TX to 355 * work. We also make sure any cred_t is carried across. 356 */ 357 if (ud->ud_resp) { 358 if (ud->ud_resp->b_cont != NULL) { 359 cmn_err(CE_WARN, "svc_clts_krecv: ud_resp %p, " 360 "b_cont %p", (void *)ud->ud_resp, 361 (void *)ud->ud_resp->b_cont); 362 } 363 freeb(ud->ud_resp); 364 } 365 /* Move any cred_t to the first mblk in the message */ 366 cr = msg_getcred(mp, NULL); 367 if (cr != NULL) 368 mblk_setcred(mp, cr, NOPID); 369 370 ud->ud_resp = mp; 371 mp = mp->b_cont; 372 ud->ud_resp->b_cont = NULL; 373 374 xdrmblk_init(xdrs, mp, XDR_DECODE, 0); 375 376 TRACE_0(TR_FAC_KRPC, TR_XDR_CALLMSG_START, 377 "xdr_callmsg_start:"); 378 if (! xdr_callmsg(xdrs, msg)) { 379 TRACE_1(TR_FAC_KRPC, TR_XDR_CALLMSG_END, 380 "xdr_callmsg_end:(%S)", "bad"); 381 RSSTAT_INCR(stats, rsxdrcall); 382 goto bad; 383 } 384 TRACE_1(TR_FAC_KRPC, TR_XDR_CALLMSG_END, 385 "xdr_callmsg_end:(%S)", "good"); 386 387 clone_xprt->xp_xid = msg->rm_xid; 388 ud->ud_inmp = mp; 389 390 TRACE_1(TR_FAC_KRPC, TR_SVC_CLTS_KRECV_END, 391 "svc_clts_krecv_end:(%S)", "good"); 392 return (TRUE); 393 394 bad: 395 if (mp) 396 freemsg(mp); 397 if (ud->ud_resp) { 398 /* 399 * There should not be any left over results buffer. 400 */ 401 ASSERT(ud->ud_resp->b_cont == NULL); 402 freeb(ud->ud_resp); 403 ud->ud_resp = NULL; 404 } 405 406 RSSTAT_INCR(stats, rsbadcalls); 407 TRACE_1(TR_FAC_KRPC, TR_SVC_CLTS_KRECV_END, 408 "svc_clts_krecv_end:(%S)", "bad"); 409 return (FALSE); 410 } 411 412 /* 413 * Send rpc reply. 414 * Serialize the reply packet into the output buffer then 415 * call t_ksndudata to send it. 416 */ 417 static bool_t 418 svc_clts_ksend(SVCXPRT *clone_xprt, struct rpc_msg *msg) 419 { 420 /* LINTED pointer alignment */ 421 struct udp_data *ud = (struct udp_data *)clone_xprt->xp_p2buf; 422 XDR *xdrs = &clone_xprt->xp_xdrout; 423 int stat = FALSE; 424 mblk_t *mp; 425 int msgsz; 426 struct T_unitdata_req *udreq; 427 xdrproc_t xdr_results; 428 caddr_t xdr_location; 429 bool_t has_args; 430 431 TRACE_0(TR_FAC_KRPC, TR_SVC_CLTS_KSEND_START, 432 "svc_clts_ksend_start:"); 433 434 ASSERT(ud->ud_resp != NULL); 435 436 /* 437 * If there is a result procedure specified in the reply message, 438 * it will be processed in the xdr_replymsg and SVCAUTH_WRAP. 439 * We need to make sure it won't be processed twice, so we null 440 * it for xdr_replymsg here. 441 */ 442 has_args = FALSE; 443 if (msg->rm_reply.rp_stat == MSG_ACCEPTED && 444 msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { 445 if ((xdr_results = msg->acpted_rply.ar_results.proc) != NULL) { 446 has_args = TRUE; 447 xdr_location = msg->acpted_rply.ar_results.where; 448 msg->acpted_rply.ar_results.proc = xdr_void; 449 msg->acpted_rply.ar_results.where = NULL; 450 } 451 } 452 453 if (ud->ud_resp->b_cont == NULL) { 454 /* 455 * Allocate an initial mblk for the response data. 456 */ 457 while ((mp = allocb(UD_INITSIZE, BPRI_LO)) == NULL) { 458 if (strwaitbuf(UD_INITSIZE, BPRI_LO)) { 459 TRACE_1(TR_FAC_KRPC, TR_SVC_CLTS_KSEND_END, 460 "svc_clts_ksend_end:(%S)", "strwaitbuf"); 461 return (FALSE); 462 } 463 } 464 465 /* 466 * Initialize the XDR decode stream. Additional mblks 467 * will be allocated if necessary. They will be UD_MAXSIZE 468 * sized. 469 */ 470 xdrmblk_init(xdrs, mp, XDR_ENCODE, UD_MAXSIZE); 471 472 /* 473 * Leave some space for protocol headers. 474 */ 475 (void) XDR_SETPOS(xdrs, 512); 476 mp->b_rptr += 512; 477 478 msg->rm_xid = clone_xprt->xp_xid; 479 480 ud->ud_resp->b_cont = mp; 481 482 TRACE_0(TR_FAC_KRPC, TR_XDR_REPLYMSG_START, 483 "xdr_replymsg_start:"); 484 if (!(xdr_replymsg(xdrs, msg) && 485 (!has_args || SVCAUTH_WRAP(&clone_xprt->xp_auth, xdrs, 486 xdr_results, xdr_location)))) { 487 TRACE_1(TR_FAC_KRPC, TR_XDR_REPLYMSG_END, 488 "xdr_replymsg_end:(%S)", "bad"); 489 RPCLOG0(1, "xdr_replymsg/SVCAUTH_WRAP failed\n"); 490 goto out; 491 } 492 TRACE_1(TR_FAC_KRPC, TR_XDR_REPLYMSG_END, 493 "xdr_replymsg_end:(%S)", "good"); 494 495 } else if (!(xdr_replymsg_body(xdrs, msg) && 496 (!has_args || SVCAUTH_WRAP(&clone_xprt->xp_auth, xdrs, 497 xdr_results, xdr_location)))) { 498 RPCLOG0(1, "xdr_replymsg_body/SVCAUTH_WRAP failed\n"); 499 goto out; 500 } 501 502 msgsz = (int)xmsgsize(ud->ud_resp->b_cont); 503 504 if (msgsz <= 0 || (clone_xprt->xp_msg_size != -1 && 505 msgsz > clone_xprt->xp_msg_size)) { 506 #ifdef DEBUG 507 cmn_err(CE_NOTE, 508 "KRPC: server response message of %d bytes; transport limits are [0, %d]", 509 msgsz, clone_xprt->xp_msg_size); 510 #endif 511 goto out; 512 } 513 514 /* 515 * Construct the T_unitdata_req. We take advantage 516 * of the fact that T_unitdata_ind looks just like 517 * T_unitdata_req, except for the primitive type. 518 * Reusing it means we preserve any options, and we must preserve 519 * the SCM_UCRED option for TX to work. 520 * This has the side effect of also passing certain receive-side 521 * options like IP_RECVDSTADDR back down the send side. This 522 * implies that we can not ASSERT on a non-NULL db_credp when 523 * we have send-side options in UDP. 524 */ 525 udreq = (struct T_unitdata_req *)ud->ud_resp->b_rptr; 526 udreq->PRIM_type = T_UNITDATA_REQ; 527 put(clone_xprt->xp_wq, ud->ud_resp); 528 stat = TRUE; 529 ud->ud_resp = NULL; 530 531 out: 532 if (stat == FALSE) { 533 freemsg(ud->ud_resp); 534 ud->ud_resp = NULL; 535 } 536 537 /* 538 * This is completely disgusting. If public is set it is 539 * a pointer to a structure whose first field is the address 540 * of the function to free that structure and any related 541 * stuff. (see rrokfree in nfs_xdr.c). 542 */ 543 if (xdrs->x_public) { 544 /* LINTED pointer alignment */ 545 (**((int (**)())xdrs->x_public))(xdrs->x_public); 546 } 547 548 TRACE_1(TR_FAC_KRPC, TR_SVC_CLTS_KSEND_END, 549 "svc_clts_ksend_end:(%S)", "done"); 550 return (stat); 551 } 552 553 /* 554 * Deserialize arguments. 555 */ 556 static bool_t 557 svc_clts_kgetargs(SVCXPRT *clone_xprt, xdrproc_t xdr_args, 558 caddr_t args_ptr) 559 { 560 561 /* LINTED pointer alignment */ 562 return (SVCAUTH_UNWRAP(&clone_xprt->xp_auth, &clone_xprt->xp_xdrin, 563 xdr_args, args_ptr)); 564 565 } 566 567 static bool_t 568 svc_clts_kfreeargs(SVCXPRT *clone_xprt, xdrproc_t xdr_args, 569 caddr_t args_ptr) 570 { 571 /* LINTED pointer alignment */ 572 struct udp_data *ud = (struct udp_data *)clone_xprt->xp_p2buf; 573 XDR *xdrs = &clone_xprt->xp_xdrin; 574 bool_t retval; 575 576 if (args_ptr) { 577 xdrs->x_op = XDR_FREE; 578 retval = (*xdr_args)(xdrs, args_ptr); 579 } else 580 retval = TRUE; 581 582 if (ud->ud_inmp) { 583 freemsg(ud->ud_inmp); 584 ud->ud_inmp = NULL; 585 } 586 587 return (retval); 588 } 589 590 static int32_t * 591 svc_clts_kgetres(SVCXPRT *clone_xprt, int size) 592 { 593 /* LINTED pointer alignment */ 594 struct udp_data *ud = (struct udp_data *)clone_xprt->xp_p2buf; 595 XDR *xdrs = &clone_xprt->xp_xdrout; 596 mblk_t *mp; 597 int32_t *buf; 598 struct rpc_msg rply; 599 600 /* 601 * Allocate an initial mblk for the response data. 602 */ 603 while ((mp = allocb(UD_INITSIZE, BPRI_LO)) == NULL) { 604 if (strwaitbuf(UD_INITSIZE, BPRI_LO)) { 605 return (FALSE); 606 } 607 } 608 609 mp->b_cont = NULL; 610 611 /* 612 * Initialize the XDR decode stream. Additional mblks 613 * will be allocated if necessary. They will be UD_MAXSIZE 614 * sized. 615 */ 616 xdrmblk_init(xdrs, mp, XDR_ENCODE, UD_MAXSIZE); 617 618 /* 619 * Leave some space for protocol headers. 620 */ 621 (void) XDR_SETPOS(xdrs, 512); 622 mp->b_rptr += 512; 623 624 /* 625 * Assume a successful RPC since most of them are. 626 */ 627 rply.rm_xid = clone_xprt->xp_xid; 628 rply.rm_direction = REPLY; 629 rply.rm_reply.rp_stat = MSG_ACCEPTED; 630 rply.acpted_rply.ar_verf = clone_xprt->xp_verf; 631 rply.acpted_rply.ar_stat = SUCCESS; 632 633 if (!xdr_replymsg_hdr(xdrs, &rply)) { 634 freeb(mp); 635 return (NULL); 636 } 637 638 buf = XDR_INLINE(xdrs, size); 639 640 if (buf == NULL) 641 freeb(mp); 642 else 643 ud->ud_resp->b_cont = mp; 644 645 return (buf); 646 } 647 648 static void 649 svc_clts_kfreeres(SVCXPRT *clone_xprt) 650 { 651 /* LINTED pointer alignment */ 652 struct udp_data *ud = (struct udp_data *)clone_xprt->xp_p2buf; 653 654 if (ud->ud_resp == NULL || ud->ud_resp->b_cont == NULL) 655 return; 656 657 /* 658 * SVC_FREERES() is called whenever the server decides not to 659 * send normal reply. Thus, we expect only one mblk to be allocated, 660 * because we have not attempted any XDR encoding. 661 * If we do any XDR encoding and we get an error, then SVC_REPLY() 662 * will freemsg(ud->ud_resp); 663 */ 664 ASSERT(ud->ud_resp->b_cont->b_cont == NULL); 665 freeb(ud->ud_resp->b_cont); 666 ud->ud_resp->b_cont = NULL; 667 } 668 669 /* 670 * the dup cacheing routines below provide a cache of non-failure 671 * transaction id's. rpc service routines can use this to detect 672 * retransmissions and re-send a non-failure response. 673 */ 674 675 /* 676 * MAXDUPREQS is the number of cached items. It should be adjusted 677 * to the service load so that there is likely to be a response entry 678 * when the first retransmission comes in. 679 */ 680 #define MAXDUPREQS 1024 681 682 /* 683 * This should be appropriately scaled to MAXDUPREQS. 684 */ 685 #define DRHASHSZ 257 686 687 #if ((DRHASHSZ & (DRHASHSZ - 1)) == 0) 688 #define XIDHASH(xid) ((xid) & (DRHASHSZ - 1)) 689 #else 690 #define XIDHASH(xid) ((xid) % DRHASHSZ) 691 #endif 692 #define DRHASH(dr) XIDHASH((dr)->dr_xid) 693 #define REQTOXID(req) ((req)->rq_xprt->xp_xid) 694 695 static int ndupreqs = 0; 696 int maxdupreqs = MAXDUPREQS; 697 static kmutex_t dupreq_lock; 698 static struct dupreq *drhashtbl[DRHASHSZ]; 699 static int drhashstat[DRHASHSZ]; 700 701 static void unhash(struct dupreq *); 702 703 /* 704 * drmru points to the head of a circular linked list in lru order. 705 * drmru->dr_next == drlru 706 */ 707 struct dupreq *drmru; 708 709 /* 710 * PSARC 2003/523 Contract Private Interface 711 * svc_clts_kdup 712 * Changes must be reviewed by Solaris File Sharing 713 * Changes must be communicated to contract-2003-523@sun.com 714 * 715 * svc_clts_kdup searches the request cache and returns 0 if the 716 * request is not found in the cache. If it is found, then it 717 * returns the state of the request (in progress or done) and 718 * the status or attributes that were part of the original reply. 719 * 720 * If DUP_DONE (there is a duplicate) svc_clts_kdup copies over the 721 * value of the response. In that case, also return in *dupcachedp 722 * whether the response free routine is cached in the dupreq - in which case 723 * the caller should not be freeing it, because it will be done later 724 * in the svc_clts_kdup code when the dupreq is reused. 725 */ 726 static int 727 svc_clts_kdup(struct svc_req *req, caddr_t res, int size, struct dupreq **drpp, 728 bool_t *dupcachedp) 729 { 730 struct rpc_clts_server *stats = CLONE2STATS(req->rq_xprt); 731 struct dupreq *dr; 732 uint32_t xid; 733 uint32_t drhash; 734 int status; 735 736 xid = REQTOXID(req); 737 mutex_enter(&dupreq_lock); 738 RSSTAT_INCR(stats, rsdupchecks); 739 /* 740 * Check to see whether an entry already exists in the cache. 741 */ 742 dr = drhashtbl[XIDHASH(xid)]; 743 while (dr != NULL) { 744 if (dr->dr_xid == xid && 745 dr->dr_proc == req->rq_proc && 746 dr->dr_prog == req->rq_prog && 747 dr->dr_vers == req->rq_vers && 748 dr->dr_addr.len == req->rq_xprt->xp_rtaddr.len && 749 bcmp(dr->dr_addr.buf, req->rq_xprt->xp_rtaddr.buf, 750 dr->dr_addr.len) == 0) { 751 status = dr->dr_status; 752 if (status == DUP_DONE) { 753 bcopy(dr->dr_resp.buf, res, size); 754 if (dupcachedp != NULL) 755 *dupcachedp = (dr->dr_resfree != NULL); 756 } else { 757 dr->dr_status = DUP_INPROGRESS; 758 *drpp = dr; 759 } 760 RSSTAT_INCR(stats, rsdupreqs); 761 mutex_exit(&dupreq_lock); 762 return (status); 763 } 764 dr = dr->dr_chain; 765 } 766 767 /* 768 * There wasn't an entry, either allocate a new one or recycle 769 * an old one. 770 */ 771 if (ndupreqs < maxdupreqs) { 772 dr = kmem_alloc(sizeof (*dr), KM_NOSLEEP); 773 if (dr == NULL) { 774 mutex_exit(&dupreq_lock); 775 return (DUP_ERROR); 776 } 777 dr->dr_resp.buf = NULL; 778 dr->dr_resp.maxlen = 0; 779 dr->dr_addr.buf = NULL; 780 dr->dr_addr.maxlen = 0; 781 if (drmru) { 782 dr->dr_next = drmru->dr_next; 783 drmru->dr_next = dr; 784 } else { 785 dr->dr_next = dr; 786 } 787 ndupreqs++; 788 } else { 789 dr = drmru->dr_next; 790 while (dr->dr_status == DUP_INPROGRESS) { 791 dr = dr->dr_next; 792 if (dr == drmru->dr_next) { 793 cmn_err(CE_WARN, "svc_clts_kdup no slots free"); 794 mutex_exit(&dupreq_lock); 795 return (DUP_ERROR); 796 } 797 } 798 unhash(dr); 799 if (dr->dr_resfree) { 800 (*dr->dr_resfree)(dr->dr_resp.buf); 801 } 802 } 803 dr->dr_resfree = NULL; 804 drmru = dr; 805 806 dr->dr_xid = REQTOXID(req); 807 dr->dr_prog = req->rq_prog; 808 dr->dr_vers = req->rq_vers; 809 dr->dr_proc = req->rq_proc; 810 if (dr->dr_addr.maxlen < req->rq_xprt->xp_rtaddr.len) { 811 if (dr->dr_addr.buf != NULL) 812 kmem_free(dr->dr_addr.buf, dr->dr_addr.maxlen); 813 dr->dr_addr.maxlen = req->rq_xprt->xp_rtaddr.len; 814 dr->dr_addr.buf = kmem_alloc(dr->dr_addr.maxlen, 815 KM_NOSLEEP); 816 if (dr->dr_addr.buf == NULL) { 817 dr->dr_addr.maxlen = 0; 818 dr->dr_status = DUP_DROP; 819 mutex_exit(&dupreq_lock); 820 return (DUP_ERROR); 821 } 822 } 823 dr->dr_addr.len = req->rq_xprt->xp_rtaddr.len; 824 bcopy(req->rq_xprt->xp_rtaddr.buf, dr->dr_addr.buf, dr->dr_addr.len); 825 if (dr->dr_resp.maxlen < size) { 826 if (dr->dr_resp.buf != NULL) 827 kmem_free(dr->dr_resp.buf, dr->dr_resp.maxlen); 828 dr->dr_resp.maxlen = (unsigned int)size; 829 dr->dr_resp.buf = kmem_alloc(size, KM_NOSLEEP); 830 if (dr->dr_resp.buf == NULL) { 831 dr->dr_resp.maxlen = 0; 832 dr->dr_status = DUP_DROP; 833 mutex_exit(&dupreq_lock); 834 return (DUP_ERROR); 835 } 836 } 837 dr->dr_status = DUP_INPROGRESS; 838 839 drhash = (uint32_t)DRHASH(dr); 840 dr->dr_chain = drhashtbl[drhash]; 841 drhashtbl[drhash] = dr; 842 drhashstat[drhash]++; 843 mutex_exit(&dupreq_lock); 844 *drpp = dr; 845 return (DUP_NEW); 846 } 847 848 /* 849 * PSARC 2003/523 Contract Private Interface 850 * svc_clts_kdupdone 851 * Changes must be reviewed by Solaris File Sharing 852 * Changes must be communicated to contract-2003-523@sun.com 853 * 854 * svc_clts_kdupdone marks the request done (DUP_DONE or DUP_DROP) 855 * and stores the response. 856 */ 857 static void 858 svc_clts_kdupdone(struct dupreq *dr, caddr_t res, void (*dis_resfree)(), 859 int size, int status) 860 { 861 862 ASSERT(dr->dr_resfree == NULL); 863 if (status == DUP_DONE) { 864 bcopy(res, dr->dr_resp.buf, size); 865 dr->dr_resfree = dis_resfree; 866 } 867 dr->dr_status = status; 868 } 869 870 /* 871 * This routine expects that the mutex, dupreq_lock, is already held. 872 */ 873 static void 874 unhash(struct dupreq *dr) 875 { 876 struct dupreq *drt; 877 struct dupreq *drtprev = NULL; 878 uint32_t drhash; 879 880 ASSERT(MUTEX_HELD(&dupreq_lock)); 881 882 drhash = (uint32_t)DRHASH(dr); 883 drt = drhashtbl[drhash]; 884 while (drt != NULL) { 885 if (drt == dr) { 886 drhashstat[drhash]--; 887 if (drtprev == NULL) { 888 drhashtbl[drhash] = drt->dr_chain; 889 } else { 890 drtprev->dr_chain = drt->dr_chain; 891 } 892 return; 893 } 894 drtprev = drt; 895 drt = drt->dr_chain; 896 } 897 } 898 899 void 900 svc_clts_stats_init(zoneid_t zoneid, struct rpc_clts_server **statsp) 901 { 902 kstat_t *ksp; 903 kstat_named_t *knp; 904 905 knp = rpcstat_zone_init_common(zoneid, "unix", "rpc_clts_server", 906 (const kstat_named_t *)&clts_rsstat_tmpl, 907 sizeof (clts_rsstat_tmpl)); 908 /* 909 * Backwards compatibility for old kstat clients 910 */ 911 ksp = kstat_create_zone("unix", 0, "rpc_server", "rpc", 912 KSTAT_TYPE_NAMED, clts_rsstat_ndata, 913 KSTAT_FLAG_VIRTUAL | KSTAT_FLAG_WRITABLE, zoneid); 914 if (ksp) { 915 ksp->ks_data = knp; 916 kstat_install(ksp); 917 } 918 *statsp = (struct rpc_clts_server *)knp; 919 } 920 921 void 922 svc_clts_stats_fini(zoneid_t zoneid, struct rpc_clts_server **statsp) 923 { 924 rpcstat_zone_fini_common(zoneid, "unix", "rpc_clts_server"); 925 kstat_delete_byname_zone("unix", 0, "rpc_server", zoneid); 926 kmem_free(*statsp, sizeof (clts_rsstat_tmpl)); 927 } 928 929 void 930 svc_clts_init() 931 { 932 /* 933 * Check to make sure that the clts private data will fit into 934 * the stack buffer allocated by svc_run. The compiler should 935 * remove this check, but it's a safety net if the udp_data 936 * structure ever changes. 937 */ 938 /*CONSTANTCONDITION*/ 939 ASSERT(sizeof (struct udp_data) <= SVC_P2LEN); 940 941 mutex_init(&dupreq_lock, NULL, MUTEX_DEFAULT, NULL); 942 } 943