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