17052Samw /* 27052Samw * CDDL HEADER START 37052Samw * 47052Samw * The contents of this file are subject to the terms of the 57052Samw * Common Development and Distribution License (the "License"). 67052Samw * You may not use this file except in compliance with the License. 77052Samw * 87052Samw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97052Samw * or http://www.opensolaris.org/os/licensing. 107052Samw * See the License for the specific language governing permissions 117052Samw * and limitations under the License. 127052Samw * 137052Samw * When distributing Covered Code, include this CDDL HEADER in each 147052Samw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157052Samw * If applicable, add the following below this CDDL HEADER, with the 167052Samw * fields enclosed by brackets "[]" replaced with your own identifying 177052Samw * information: Portions Copyright [yyyy] [name of copyright owner] 187052Samw * 197052Samw * CDDL HEADER END 207052Samw */ 217052Samw /* 229231SAfshin.Ardakani@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 237052Samw * Use is subject to license terms. 247052Samw */ 257052Samw 267052Samw /* 277052Samw * This module provides the interface to NDR RPC. 287052Samw */ 297052Samw 307052Samw #include <sys/stat.h> 317052Samw #include <sys/door.h> 327052Samw #include <sys/door_data.h> 337052Samw #include <sys/uio.h> 347052Samw #include <sys/ksynch.h> 35*10966SJordan.Brown@Sun.COM #include <smbsrv/smb_kproto.h> 367052Samw #include <smbsrv/smb_xdr.h> 377052Samw 387052Samw #define SMB_OPIPE_ISOPEN(OPIPE) \ 397052Samw (((OPIPE)->p_hdr.oh_magic == SMB_OPIPE_HDR_MAGIC) && \ 407052Samw ((OPIPE)->p_hdr.oh_fid)) 417052Samw 427052Samw extern volatile uint32_t smb_fids; 437052Samw 447052Samw static int smb_opipe_do_open(smb_request_t *, smb_opipe_t *); 457052Samw static char *smb_opipe_lookup(const char *path); 467052Samw static uint32_t smb_opipe_fid(void); 477052Samw static int smb_opipe_set_hdr(smb_opipe_t *opipe, uint32_t, uint32_t); 487052Samw static void smb_opipe_enter(smb_opipe_t *); 497052Samw static void smb_opipe_exit(smb_opipe_t *); 507052Samw 517052Samw static door_handle_t smb_opipe_door_hd = NULL; 527052Samw static int smb_opipe_door_id = -1; 537052Samw static uint64_t smb_opipe_door_ncall = 0; 547052Samw static kmutex_t smb_opipe_door_mutex; 557052Samw static kcondvar_t smb_opipe_door_cv; 567052Samw 577052Samw static int smb_opipe_door_call(smb_opipe_t *); 587052Samw static int smb_opipe_door_upcall(smb_opipe_t *); 597052Samw 607052Samw /* 617052Samw * smb_opipe_open 627052Samw * 637052Samw * Open a well-known RPC named pipe. This routine should be called if 647052Samw * a file open is requested on a share of type STYPE_IPC. 657052Samw * If we recognize the pipe, we setup a new ofile. 667052Samw * 677052Samw * Returns 0 on success, Otherwise an NT status is returned to indicate 687052Samw * an error. 697052Samw */ 707052Samw int 717052Samw smb_opipe_open(smb_request_t *sr) 727052Samw { 739231SAfshin.Ardakani@Sun.COM open_param_t *op = &sr->arg.open; 747052Samw smb_ofile_t *of; 757052Samw smb_opipe_t *opipe; 767052Samw smb_opipe_hdr_t hdr; 777052Samw smb_error_t err; 787052Samw char *pipe_name; 797052Samw 809343SAfshin.Ardakani@Sun.COM if ((pipe_name = smb_opipe_lookup(op->fqi.fq_path.pn_path)) == NULL) 817052Samw return (NT_STATUS_OBJECT_NAME_NOT_FOUND); 827052Samw 837348SJose.Borrego@Sun.COM op->create_options = 0; 847348SJose.Borrego@Sun.COM 857348SJose.Borrego@Sun.COM of = smb_ofile_open(sr->tid_tree, NULL, sr->smb_pid, op, 867052Samw SMB_FTYPE_MESG_PIPE, SMB_UNIQ_FID(), &err); 879231SAfshin.Ardakani@Sun.COM 887052Samw if (of == NULL) 897052Samw return (err.status); 907052Samw 919231SAfshin.Ardakani@Sun.COM if (!smb_tree_is_connected(sr->tid_tree)) { 929231SAfshin.Ardakani@Sun.COM smb_ofile_close(of, 0); 939231SAfshin.Ardakani@Sun.COM smb_ofile_release(of); 949231SAfshin.Ardakani@Sun.COM return (NT_STATUS_OBJECT_NAME_NOT_FOUND); 959231SAfshin.Ardakani@Sun.COM } 969231SAfshin.Ardakani@Sun.COM 977052Samw op->dsize = 0x01000; 987052Samw op->dattr = FILE_ATTRIBUTE_NORMAL; 997052Samw op->ftype = SMB_FTYPE_MESG_PIPE; 1007052Samw op->action_taken = SMB_OACT_LOCK | SMB_OACT_OPENED; /* 0x8001 */ 1017052Samw op->devstate = SMB_PIPE_READMODE_MESSAGE 1027052Samw | SMB_PIPE_TYPE_MESSAGE 1037052Samw | SMB_PIPE_UNLIMITED_INSTANCES; /* 0x05ff */ 1047052Samw op->fileid = of->f_fid; 1057052Samw 1067052Samw sr->smb_fid = of->f_fid; 1077052Samw sr->fid_ofile = of; 1087052Samw 1097052Samw opipe = of->f_pipe; 1107052Samw mutex_init(&opipe->p_mutex, NULL, MUTEX_DEFAULT, NULL); 1117052Samw cv_init(&opipe->p_cv, NULL, CV_DEFAULT, NULL); 1127052Samw smb_opipe_enter(opipe); 1137052Samw 1147052Samw opipe->p_name = pipe_name; 1157052Samw opipe->p_doorbuf = kmem_zalloc(SMB_OPIPE_DOOR_BUFSIZE, KM_SLEEP); 1167052Samw 1177052Samw /* 1187052Samw * p_data points to the offset within p_doorbuf at which 1197052Samw * data will be written or read. 1207052Samw */ 1217052Samw opipe->p_data = opipe->p_doorbuf + xdr_sizeof(smb_opipe_hdr_xdr, &hdr); 1227052Samw 1237052Samw if (smb_opipe_do_open(sr, opipe) != 0) { 1247052Samw /* 1257052Samw * On error, reset the header to clear the fid, 1267052Samw * which avoids confusion when smb_opipe_close() is 1277052Samw * called by smb_ofile_close(). 1287052Samw */ 1297052Samw bzero(&opipe->p_hdr, sizeof (smb_opipe_hdr_t)); 1307052Samw kmem_free(opipe->p_doorbuf, SMB_OPIPE_DOOR_BUFSIZE); 1317052Samw smb_opipe_exit(opipe); 1327348SJose.Borrego@Sun.COM smb_ofile_close(of, 0); 1337052Samw return (NT_STATUS_NO_MEMORY); 1347052Samw } 1357052Samw smb_opipe_exit(opipe); 1367052Samw return (NT_STATUS_SUCCESS); 1377052Samw } 1387052Samw 1397052Samw /* 1407052Samw * smb_opipe_lookup 1417052Samw * 1427052Samw * Lookup a path to see if it's a well-known RPC named pipe that we support. 1437052Samw * The full pipe path will be in the form \\PIPE\\SERVICE. The first part 1447052Samw * can be assumed, so all we need here are the service names. 1457052Samw * 14610122SJordan.Brown@Sun.COM * Returns a pointer to the pipe name (without any leading \'s) on success. 1477052Samw * Otherwise returns a null pointer. 1487052Samw */ 1497052Samw static char * 1507052Samw smb_opipe_lookup(const char *path) 1517052Samw { 1527052Samw static char *named_pipes[] = { 15310122SJordan.Brown@Sun.COM "lsass", 1547052Samw "LSARPC", 1557052Samw "NETLOGON", 1567052Samw "SAMR", 1577052Samw "SPOOLSS", 1587052Samw "SRVSVC", 1597052Samw "SVCCTL", 1607052Samw "WINREG", 1617052Samw "WKSSVC", 1627052Samw "EVENTLOG" 1637052Samw }; 1647052Samw 1657052Samw const char *name; 1667052Samw int i; 1677052Samw 1687052Samw if (path == NULL) 1697052Samw return (NULL); 1707052Samw 1717052Samw name = path; 1727052Samw name += strspn(name, "\\"); 173*10966SJordan.Brown@Sun.COM if (smb_strcasecmp(name, "PIPE", 4) == 0) { 1747052Samw path += 4; 1757052Samw name += strspn(name, "\\"); 1767052Samw } 1777052Samw 1787052Samw for (i = 0; i < sizeof (named_pipes) / sizeof (named_pipes[0]); ++i) { 179*10966SJordan.Brown@Sun.COM if (smb_strcasecmp(name, named_pipes[i], 0) == 0) 1807052Samw return (named_pipes[i]); 1817052Samw } 1827052Samw 1837052Samw return (NULL); 1847052Samw } 1857052Samw 1867052Samw /* 1877052Samw * Initialize the opipe header and context, and make the door call. 1887052Samw */ 1897052Samw static int 1907052Samw smb_opipe_do_open(smb_request_t *sr, smb_opipe_t *opipe) 1917052Samw { 19210122SJordan.Brown@Sun.COM smb_netuserinfo_t *userinfo = &opipe->p_user; 1937052Samw smb_user_t *user = sr->uid_user; 1947052Samw uint8_t *buf = opipe->p_doorbuf; 1957052Samw uint32_t buflen = SMB_OPIPE_DOOR_BUFSIZE; 1967052Samw uint32_t len; 1977052Samw 19810122SJordan.Brown@Sun.COM smb_user_netinfo_init(user, userinfo); 19910122SJordan.Brown@Sun.COM len = xdr_sizeof(smb_netuserinfo_xdr, userinfo); 2007052Samw 2017052Samw bzero(&opipe->p_hdr, sizeof (smb_opipe_hdr_t)); 2027052Samw opipe->p_hdr.oh_magic = SMB_OPIPE_HDR_MAGIC; 2037052Samw opipe->p_hdr.oh_fid = smb_opipe_fid(); 2047052Samw 2057052Samw if (smb_opipe_set_hdr(opipe, SMB_OPIPE_OPEN, len) == -1) 2067052Samw return (-1); 2077052Samw 2087052Samw len = xdr_sizeof(smb_opipe_hdr_xdr, &opipe->p_hdr); 2097052Samw buf += len; 2107052Samw buflen -= len; 2117052Samw 21210122SJordan.Brown@Sun.COM if (smb_netuserinfo_encode(userinfo, buf, buflen, NULL) == -1) 2137052Samw return (-1); 2147052Samw 2157052Samw return (smb_opipe_door_call(opipe)); 2167052Samw } 2177052Samw 2187052Samw /* 2197052Samw * smb_opipe_fid 2207052Samw * 2217052Samw * The opipe_fid is an arbitrary id used to associate RPC requests 2227052Samw * with a binding handle. A new fid is returned on each call. 2237052Samw * 0 or -1 are not assigned: 0 is used to indicate an invalid fid 2247052Samw * and SMB sometimes uses -1 to indicate all open fid's. 2257052Samw */ 2267052Samw static uint32_t 2277052Samw smb_opipe_fid(void) 2287052Samw { 2297052Samw static uint32_t opipe_fid; 2307052Samw static kmutex_t smb_opipe_fid_mutex; 2317052Samw 2327052Samw mutex_enter(&smb_opipe_fid_mutex); 2337052Samw 2347052Samw if (opipe_fid == 0) 2357052Samw opipe_fid = lbolt << 11; 2367052Samw 2377052Samw do { 2387052Samw ++opipe_fid; 2397052Samw } while (opipe_fid == 0 || opipe_fid == (uint32_t)-1); 2407052Samw 2417052Samw mutex_exit(&smb_opipe_fid_mutex); 2427052Samw 2437052Samw return (opipe_fid); 2447052Samw } 2457052Samw 2467052Samw /* 2477052Samw * smb_opipe_close 2487052Samw * 2497052Samw * Called whenever an IPC file/pipe is closed. 2507052Samw */ 2517052Samw void 2527052Samw smb_opipe_close(smb_ofile_t *of) 2537052Samw { 2547052Samw smb_opipe_t *opipe; 2557052Samw 2567052Samw ASSERT(of); 2577052Samw ASSERT(of->f_ftype == SMB_FTYPE_MESG_PIPE); 2587052Samw ASSERT(of->f_pipe != NULL); 2597052Samw 2607052Samw opipe = of->f_pipe; 2617052Samw smb_opipe_enter(opipe); 2627052Samw 2637052Samw if (SMB_OPIPE_ISOPEN(opipe)) { 2647052Samw (void) smb_opipe_set_hdr(opipe, SMB_OPIPE_CLOSE, 0); 2657052Samw (void) smb_opipe_door_call(opipe); 2667052Samw bzero(&opipe->p_hdr, sizeof (smb_opipe_hdr_t)); 2677052Samw kmem_free(opipe->p_doorbuf, SMB_OPIPE_DOOR_BUFSIZE); 2687052Samw } 2697052Samw 27010122SJordan.Brown@Sun.COM smb_user_netinfo_fini(&opipe->p_user); 2717052Samw smb_opipe_exit(opipe); 2727052Samw cv_destroy(&opipe->p_cv); 2737052Samw mutex_destroy(&opipe->p_mutex); 2747052Samw } 2757052Samw 2767052Samw static int 2777052Samw smb_opipe_set_hdr(smb_opipe_t *opipe, uint32_t cmd, uint32_t datalen) 2787052Samw { 2797052Samw opipe->p_hdr.oh_op = cmd; 2807052Samw opipe->p_hdr.oh_datalen = datalen; 2817052Samw opipe->p_hdr.oh_resid = 0; 2827052Samw opipe->p_hdr.oh_status = 0; 2837052Samw 2847052Samw return (smb_opipe_hdr_encode(&opipe->p_hdr, opipe->p_doorbuf, 2857052Samw SMB_OPIPE_DOOR_BUFSIZE)); 2867052Samw } 2877052Samw 2887052Samw /* 2897052Samw * smb_opipe_transact 2907052Samw * 2917052Samw * This is the entry point for RPC bind and request transactions. 2927052Samw * The fid is an arbitrary id used to associate RPC requests with a 2937052Samw * particular binding handle. 2947052Samw * 2957052Samw * If the data to be returned is larger than the client expects, we 2967052Samw * return as much as the client can handle and report a buffer overflow 2977052Samw * warning, which informs the client that we have more data to return. 2987052Samw * The residual data remains in the pipe until the client claims it or 2997052Samw * closes the pipe. 3007052Samw */ 3017052Samw smb_sdrc_t 3027052Samw smb_opipe_transact(smb_request_t *sr, struct uio *uio) 3037052Samw { 3047052Samw smb_xa_t *xa; 3057052Samw smb_opipe_t *opipe; 3067052Samw struct mbuf *mhead; 3077052Samw int mdrcnt; 3087052Samw int nbytes; 3097052Samw int rc; 3107052Samw 3117052Samw if ((rc = smb_opipe_write(sr, uio)) != 0) { 3127052Samw if (rc == EBADF) 3137052Samw smbsr_error(sr, NT_STATUS_INVALID_HANDLE, 3147052Samw ERRDOS, ERROR_INVALID_HANDLE); 3157052Samw else 3167052Samw smbsr_error(sr, NT_STATUS_INTERNAL_ERROR, 3177052Samw ERRDOS, ERROR_INTERNAL_ERROR); 3187052Samw return (SDRC_ERROR); 3197052Samw } 3207052Samw 3217052Samw xa = sr->r_xa; 3227052Samw mdrcnt = xa->smb_mdrcnt; 3237052Samw opipe = sr->fid_ofile->f_pipe; 3247052Samw smb_opipe_enter(opipe); 3257052Samw 3267052Samw if (smb_opipe_set_hdr(opipe, SMB_OPIPE_READ, mdrcnt) == -1) { 3277052Samw smb_opipe_exit(opipe); 3287052Samw smbsr_error(sr, NT_STATUS_INTERNAL_ERROR, 3297052Samw ERRDOS, ERROR_INTERNAL_ERROR); 3307052Samw return (SDRC_ERROR); 3317052Samw } 3327052Samw 3337052Samw rc = smb_opipe_door_call(opipe); 3347052Samw nbytes = opipe->p_hdr.oh_datalen; 3357052Samw 3367052Samw if (rc != 0) { 3377052Samw smb_opipe_exit(opipe); 3387052Samw smbsr_error(sr, NT_STATUS_INTERNAL_ERROR, 3397052Samw ERRDOS, ERROR_INTERNAL_ERROR); 3407052Samw return (SDRC_ERROR); 3417052Samw } 3427052Samw 3437052Samw if (nbytes) { 3447052Samw mhead = smb_mbuf_get(opipe->p_data, nbytes); 3457052Samw xa->rep_data_mb.max_bytes = nbytes; 3467052Samw MBC_ATTACH_MBUF(&xa->rep_data_mb, mhead); 3477052Samw } 3487052Samw 3497052Samw if (opipe->p_hdr.oh_resid) { 3507052Samw /* 3517052Samw * The pipe contains more data than mdrcnt, warn the 3527052Samw * client that there is more data in the pipe. 3537052Samw * Typically, the client will call SmbReadX, which 3547052Samw * will call smb_opipe_read, to get the data. 3557052Samw */ 3567052Samw smbsr_warn(sr, NT_STATUS_BUFFER_OVERFLOW, 3577052Samw ERRDOS, ERROR_MORE_DATA); 3587052Samw } 3597052Samw 3607052Samw smb_opipe_exit(opipe); 3617052Samw return (SDRC_SUCCESS); 3627052Samw } 3637052Samw 3647052Samw /* 3657052Samw * smb_opipe_write 3667052Samw * 3677052Samw * Write RPC request data to the pipe. The client should call smb_opipe_read 3687052Samw * to complete the exchange and obtain the RPC response. 3697052Samw * 3707052Samw * Returns 0 on success or an errno on failure. 3717052Samw */ 3727052Samw int 3737052Samw smb_opipe_write(smb_request_t *sr, struct uio *uio) 3747052Samw { 3757052Samw smb_opipe_t *opipe; 3767052Samw uint32_t buflen; 3777052Samw uint32_t len; 3787052Samw int rc; 3797052Samw 3807052Samw ASSERT(sr->fid_ofile); 3817052Samw ASSERT(sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE); 3827052Samw ASSERT(sr->fid_ofile->f_pipe != NULL); 3837052Samw 3847052Samw opipe = sr->fid_ofile->f_pipe; 3857052Samw smb_opipe_enter(opipe); 3867052Samw 3877052Samw if (!SMB_OPIPE_ISOPEN(opipe)) { 3887052Samw smb_opipe_exit(opipe); 3897052Samw return (EBADF); 3907052Samw } 3917052Samw 3927052Samw rc = smb_opipe_set_hdr(opipe, SMB_OPIPE_WRITE, uio->uio_resid); 3937052Samw len = xdr_sizeof(smb_opipe_hdr_xdr, &opipe->p_hdr); 3947052Samw if (rc == -1 || len == 0) { 3957052Samw smb_opipe_exit(opipe); 3967052Samw return (ENOMEM); 3977052Samw } 3987052Samw 3997052Samw buflen = SMB_OPIPE_DOOR_BUFSIZE - len; 4007052Samw (void) uiomove((caddr_t)opipe->p_data, buflen, UIO_WRITE, uio); 4017052Samw 4027052Samw rc = smb_opipe_door_call(opipe); 4037052Samw 4047052Samw smb_opipe_exit(opipe); 4057052Samw return ((rc == 0) ? 0 : EIO); 4067052Samw } 4077052Samw 4087052Samw /* 4097052Samw * smb_opipe_read 4107052Samw * 4117052Samw * This interface may be called because smb_opipe_transact could not return 4127052Samw * all of the data in the original transaction or to form the second half 4137052Samw * of a transaction set up using smb_opipe_write. Either way, we just need 4147052Samw * to read data from the pipe and return it. 4157052Samw * 4167052Samw * The response data is encoded into raw_data as required by the smb_read 4177052Samw * functions. The uio_resid value indicates the number of bytes read. 4187052Samw */ 4197052Samw int 4207052Samw smb_opipe_read(smb_request_t *sr, struct uio *uio) 4217052Samw { 4227052Samw smb_opipe_t *opipe; 4237052Samw struct mbuf *mhead; 4247052Samw uint32_t nbytes; 4257052Samw int rc; 4267052Samw 4277052Samw ASSERT(sr->fid_ofile); 4287052Samw ASSERT(sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE); 4297052Samw ASSERT(sr->fid_ofile->f_pipe != NULL); 4307052Samw 4317052Samw opipe = sr->fid_ofile->f_pipe; 4327052Samw smb_opipe_enter(opipe); 4337052Samw 4347052Samw if (!SMB_OPIPE_ISOPEN(opipe)) { 4357052Samw smb_opipe_exit(opipe); 4367052Samw return (EBADF); 4377052Samw } 4387052Samw 4397052Samw if (smb_opipe_set_hdr(opipe, SMB_OPIPE_READ, uio->uio_resid) == -1) { 4407052Samw smb_opipe_exit(opipe); 4417052Samw return (ENOMEM); 4427052Samw } 4437052Samw 4447052Samw rc = smb_opipe_door_call(opipe); 4457052Samw nbytes = opipe->p_hdr.oh_datalen; 4467052Samw 4477052Samw if (rc != 0 || nbytes > uio->uio_resid) { 4487052Samw smb_opipe_exit(opipe); 4497052Samw return (EIO); 4507052Samw } 4517052Samw 4527052Samw if (nbytes) { 4537052Samw mhead = smb_mbuf_get(opipe->p_data, nbytes); 4547052Samw MBC_SETUP(&sr->raw_data, nbytes); 4557052Samw MBC_ATTACH_MBUF(&sr->raw_data, mhead); 4567052Samw uio->uio_resid -= nbytes; 4577052Samw } 4587052Samw 4597052Samw smb_opipe_exit(opipe); 4607052Samw return (rc); 4617052Samw } 4627052Samw 4637052Samw /* 4647052Samw * Named pipe I/O is serialized per fid to ensure that each request 4657052Samw * has exclusive opipe access for the duration of the request. 4667052Samw */ 4677052Samw static void 4687052Samw smb_opipe_enter(smb_opipe_t *opipe) 4697052Samw { 4707052Samw mutex_enter(&opipe->p_mutex); 4717052Samw 4727052Samw while (opipe->p_busy) 4737052Samw cv_wait(&opipe->p_cv, &opipe->p_mutex); 4747052Samw 4757052Samw opipe->p_busy = 1; 4767052Samw mutex_exit(&opipe->p_mutex); 4777052Samw } 4787052Samw 4797052Samw static void 4807052Samw smb_opipe_exit(smb_opipe_t *opipe) 4817052Samw { 4827052Samw mutex_enter(&opipe->p_mutex); 4837052Samw opipe->p_busy = 0; 4847052Samw cv_signal(&opipe->p_cv); 4857052Samw mutex_exit(&opipe->p_mutex); 4867052Samw } 4877052Samw 4887052Samw /* 4897052Samw * opipe door client (to user space door server). 4907052Samw */ 4917052Samw void 4927052Samw smb_opipe_door_init(void) 4937052Samw { 4947052Samw mutex_init(&smb_opipe_door_mutex, NULL, MUTEX_DEFAULT, NULL); 4957052Samw cv_init(&smb_opipe_door_cv, NULL, CV_DEFAULT, NULL); 4967052Samw } 4977052Samw 4987052Samw void 4997052Samw smb_opipe_door_fini(void) 5007052Samw { 5017052Samw smb_opipe_door_close(); 5027052Samw cv_destroy(&smb_opipe_door_cv); 5037052Samw mutex_destroy(&smb_opipe_door_mutex); 5047052Samw } 5057052Samw 5067052Samw /* 5077052Samw * Open the (user space) door. If the door is already open, 5087052Samw * close it first because the door-id has probably changed. 5097052Samw */ 5107052Samw int 5117052Samw smb_opipe_door_open(int door_id) 5127052Samw { 5137052Samw smb_opipe_door_close(); 5147052Samw 5157052Samw mutex_enter(&smb_opipe_door_mutex); 5167052Samw smb_opipe_door_ncall = 0; 5177052Samw 5187052Samw if (smb_opipe_door_hd == NULL) { 5197052Samw smb_opipe_door_id = door_id; 5207052Samw smb_opipe_door_hd = door_ki_lookup(door_id); 5217052Samw } 5227052Samw 5237052Samw mutex_exit(&smb_opipe_door_mutex); 5247052Samw return ((smb_opipe_door_hd == NULL) ? -1 : 0); 5257052Samw } 5267052Samw 5277052Samw /* 5287052Samw * Close the (user space) door. 5297052Samw */ 5307052Samw void 5317052Samw smb_opipe_door_close(void) 5327052Samw { 5337052Samw mutex_enter(&smb_opipe_door_mutex); 5347052Samw 5357052Samw if (smb_opipe_door_hd != NULL) { 5367052Samw while (smb_opipe_door_ncall > 0) 5377052Samw cv_wait(&smb_opipe_door_cv, &smb_opipe_door_mutex); 5387052Samw 5397052Samw door_ki_rele(smb_opipe_door_hd); 5407052Samw smb_opipe_door_hd = NULL; 5417052Samw } 5427052Samw 5437052Samw mutex_exit(&smb_opipe_door_mutex); 5447052Samw } 5457052Samw 5467052Samw /* 5477052Samw * opipe door call interface. 5487052Samw * Door serialization and call reference accounting is handled here. 5497052Samw */ 5507052Samw static int 5517052Samw smb_opipe_door_call(smb_opipe_t *opipe) 5527052Samw { 5537052Samw int rc; 5547052Samw 5557052Samw mutex_enter(&smb_opipe_door_mutex); 5567052Samw 5577052Samw if (smb_opipe_door_hd == NULL) { 5587052Samw mutex_exit(&smb_opipe_door_mutex); 5597052Samw 5607052Samw if (smb_opipe_door_open(smb_opipe_door_id) != 0) 5617052Samw return (-1); 5627052Samw 5637052Samw mutex_enter(&smb_opipe_door_mutex); 5647052Samw } 5657052Samw 5667052Samw ++smb_opipe_door_ncall; 5677052Samw mutex_exit(&smb_opipe_door_mutex); 5687052Samw 5697052Samw rc = smb_opipe_door_upcall(opipe); 5707052Samw 5717052Samw mutex_enter(&smb_opipe_door_mutex); 5727052Samw --smb_opipe_door_ncall; 5737052Samw cv_signal(&smb_opipe_door_cv); 5747052Samw mutex_exit(&smb_opipe_door_mutex); 5757052Samw return (rc); 5767052Samw } 5777052Samw 5787052Samw /* 5797052Samw * Door upcall wrapper - handles data marshalling. 5807052Samw * This function should only be called by smb_opipe_door_call. 5817052Samw */ 5827052Samw static int 5837052Samw smb_opipe_door_upcall(smb_opipe_t *opipe) 5847052Samw { 5857052Samw door_arg_t da; 5867052Samw smb_opipe_hdr_t hdr; 5877052Samw int i; 5887052Samw int rc; 5897052Samw 5907052Samw da.data_ptr = (char *)opipe->p_doorbuf; 5917052Samw da.data_size = SMB_OPIPE_DOOR_BUFSIZE; 5927052Samw da.desc_ptr = NULL; 5937052Samw da.desc_num = 0; 5947052Samw da.rbuf = (char *)opipe->p_doorbuf; 5957052Samw da.rsize = SMB_OPIPE_DOOR_BUFSIZE; 5967052Samw 5977052Samw for (i = 0; i < 3; ++i) { 5987052Samw if ((rc = door_ki_upcall_limited(smb_opipe_door_hd, &da, 5997052Samw NULL, SIZE_MAX, 0)) == 0) 6007052Samw break; 6017052Samw 6027052Samw if (rc != EAGAIN && rc != EINTR) 6037052Samw return (-1); 6047052Samw } 6057052Samw 6067052Samw if (rc != 0) 6077052Samw return (-1); 6087052Samw 6097052Samw if (smb_opipe_hdr_decode(&hdr, (uint8_t *)da.rbuf, da.rsize) == -1) 6107052Samw return (-1); 6117052Samw 6127052Samw if ((hdr.oh_magic != SMB_OPIPE_HDR_MAGIC) || 6137052Samw (hdr.oh_fid != opipe->p_hdr.oh_fid) || 6147052Samw (hdr.oh_op != opipe->p_hdr.oh_op) || 6157052Samw (hdr.oh_status != 0) || 6167052Samw (hdr.oh_datalen > SMB_OPIPE_DOOR_BUFSIZE)) { 6177052Samw return (-1); 6187052Samw } 6197052Samw 6207052Samw opipe->p_hdr.oh_datalen = hdr.oh_datalen; 6217052Samw opipe->p_hdr.oh_resid = hdr.oh_resid; 6227052Samw return (0); 6237052Samw } 624