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