14bff34e3Sthurlow /* 24bff34e3Sthurlow * Copyright (c) 2000-2001 Boris Popov 34bff34e3Sthurlow * All rights reserved. 44bff34e3Sthurlow * 54bff34e3Sthurlow * Redistribution and use in source and binary forms, with or without 64bff34e3Sthurlow * modification, are permitted provided that the following conditions 74bff34e3Sthurlow * are met: 84bff34e3Sthurlow * 1. Redistributions of source code must retain the above copyright 94bff34e3Sthurlow * notice, this list of conditions and the following disclaimer. 104bff34e3Sthurlow * 2. Redistributions in binary form must reproduce the above copyright 114bff34e3Sthurlow * notice, this list of conditions and the following disclaimer in the 124bff34e3Sthurlow * documentation and/or other materials provided with the distribution. 134bff34e3Sthurlow * 3. All advertising materials mentioning features or use of this software 144bff34e3Sthurlow * must display the following acknowledgement: 154bff34e3Sthurlow * This product includes software developed by Boris Popov. 164bff34e3Sthurlow * 4. Neither the name of the author nor the names of any co-contributors 174bff34e3Sthurlow * may be used to endorse or promote products derived from this software 184bff34e3Sthurlow * without specific prior written permission. 194bff34e3Sthurlow * 204bff34e3Sthurlow * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 214bff34e3Sthurlow * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 224bff34e3Sthurlow * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 234bff34e3Sthurlow * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 244bff34e3Sthurlow * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 254bff34e3Sthurlow * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 264bff34e3Sthurlow * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 274bff34e3Sthurlow * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 284bff34e3Sthurlow * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 294bff34e3Sthurlow * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 304bff34e3Sthurlow * SUCH DAMAGE. 314bff34e3Sthurlow * 324bff34e3Sthurlow * $Id: smb_usr.c,v 1.15 2004/12/13 00:25:18 lindak Exp $ 334bff34e3Sthurlow */ 344bff34e3Sthurlow 359c9af259SGordon Ross /* 36613a2f6bSGordon Ross * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 379c9af259SGordon Ross * Use is subject to license terms. 389c9af259SGordon Ross */ 394bff34e3Sthurlow 404bff34e3Sthurlow #include <sys/param.h> 414bff34e3Sthurlow #include <sys/kmem.h> 424bff34e3Sthurlow #include <sys/systm.h> 434bff34e3Sthurlow #include <sys/policy.h> 444bff34e3Sthurlow #include <sys/conf.h> 454bff34e3Sthurlow #include <sys/proc.h> 464bff34e3Sthurlow #include <sys/fcntl.h> 47613a2f6bSGordon Ross #include <sys/file.h> 484bff34e3Sthurlow #include <sys/socket.h> 49613a2f6bSGordon Ross #include <sys/sunddi.h> 504bff34e3Sthurlow #include <sys/cmn_err.h> 514bff34e3Sthurlow 524bff34e3Sthurlow #include <netsmb/smb_osdep.h> 534bff34e3Sthurlow 544bff34e3Sthurlow #include <netsmb/smb.h> 554bff34e3Sthurlow #include <netsmb/smb_conn.h> 564bff34e3Sthurlow #include <netsmb/smb_rq.h> 574bff34e3Sthurlow #include <netsmb/smb_subr.h> 584bff34e3Sthurlow #include <netsmb/smb_dev.h> 594bff34e3Sthurlow 60613a2f6bSGordon Ross static int smb_cpdatain(struct mbchain *mbp, int len, char *data, int seg); 61613a2f6bSGordon Ross 624bff34e3Sthurlow /* 63613a2f6bSGordon Ross * Ioctl function for SMBIOC_FLAGS2 644bff34e3Sthurlow */ 65613a2f6bSGordon Ross int 66613a2f6bSGordon Ross smb_usr_get_flags2(smb_dev_t *sdp, intptr_t arg, int flags) 67613a2f6bSGordon Ross { 68613a2f6bSGordon Ross struct smb_vc *vcp = NULL; 69613a2f6bSGordon Ross 70613a2f6bSGordon Ross /* This ioctl requires a session. */ 71613a2f6bSGordon Ross if ((vcp = sdp->sd_vc) == NULL) 72613a2f6bSGordon Ross return (ENOTCONN); 73613a2f6bSGordon Ross 74613a2f6bSGordon Ross /* 75613a2f6bSGordon Ross * Return the flags2 value. 76613a2f6bSGordon Ross */ 77613a2f6bSGordon Ross if (ddi_copyout(&vcp->vc_hflags2, (void *)arg, 78613a2f6bSGordon Ross sizeof (u_int16_t), flags)) 79613a2f6bSGordon Ross return (EFAULT); 80613a2f6bSGordon Ross 81613a2f6bSGordon Ross return (0); 82613a2f6bSGordon Ross } 834bff34e3Sthurlow 844bff34e3Sthurlow /* 85613a2f6bSGordon Ross * Ioctl function for SMBIOC_GETSSNKEY 86613a2f6bSGordon Ross * Size copied out is SMBIOC_HASH_SZ. 87613a2f6bSGordon Ross * 88613a2f6bSGordon Ross * The RPC library needs this for encrypting things 89613a2f6bSGordon Ross * like "set password" requests. This is called 90613a2f6bSGordon Ross * with an active RPC binding, so the connection 91613a2f6bSGordon Ross * will already be active (but this checks). 924bff34e3Sthurlow */ 93613a2f6bSGordon Ross int 94613a2f6bSGordon Ross smb_usr_get_ssnkey(smb_dev_t *sdp, intptr_t arg, int flags) 954bff34e3Sthurlow { 96613a2f6bSGordon Ross struct smb_vc *vcp = NULL; 97613a2f6bSGordon Ross 98613a2f6bSGordon Ross /* This ioctl requires an active session. */ 99613a2f6bSGordon Ross if ((vcp = sdp->sd_vc) == NULL) 100613a2f6bSGordon Ross return (ENOTCONN); 101613a2f6bSGordon Ross if (vcp->vc_state != SMBIOD_ST_VCACTIVE) 102613a2f6bSGordon Ross return (ENOTCONN); 1034bff34e3Sthurlow 1044bff34e3Sthurlow /* 105613a2f6bSGordon Ross * Return the session key. 1064bff34e3Sthurlow */ 107613a2f6bSGordon Ross if (ddi_copyout(vcp->vc_ssn_key, (void *)arg, 108613a2f6bSGordon Ross SMBIOC_HASH_SZ, flags)) 109613a2f6bSGordon Ross return (EFAULT); 110613a2f6bSGordon Ross 111613a2f6bSGordon Ross return (0); 112613a2f6bSGordon Ross } 113613a2f6bSGordon Ross 114613a2f6bSGordon Ross /* 115613a2f6bSGordon Ross * Ioctl function for SMBIOC_REQUEST 116613a2f6bSGordon Ross */ 117613a2f6bSGordon Ross int 118613a2f6bSGordon Ross smb_usr_simplerq(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr) 119613a2f6bSGordon Ross { 120613a2f6bSGordon Ross struct smb_cred scred; 121613a2f6bSGordon Ross struct smb_share *ssp; 122613a2f6bSGordon Ross smbioc_rq_t *ioc = NULL; 123613a2f6bSGordon Ross struct smb_rq *rqp = NULL; 124613a2f6bSGordon Ross struct mbchain *mbp; 125613a2f6bSGordon Ross struct mdchain *mdp; 126613a2f6bSGordon Ross uint32_t rsz; 127613a2f6bSGordon Ross int err, mbseg; 128613a2f6bSGordon Ross 129613a2f6bSGordon Ross /* This ioctl requires a share. */ 130613a2f6bSGordon Ross if ((ssp = sdp->sd_share) == NULL) 131613a2f6bSGordon Ross return (ENOTCONN); 132613a2f6bSGordon Ross 133613a2f6bSGordon Ross smb_credinit(&scred, cr); 134613a2f6bSGordon Ross ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP); 135613a2f6bSGordon Ross if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) { 136613a2f6bSGordon Ross err = EFAULT; 137613a2f6bSGordon Ross goto out; 1384bff34e3Sthurlow } 1394bff34e3Sthurlow 140613a2f6bSGordon Ross /* See ddi_copyin, ddi_copyout */ 141613a2f6bSGordon Ross mbseg = (flags & FKIOCTL) ? MB_MSYSTEM : MB_MUSER; 1424bff34e3Sthurlow 1434bff34e3Sthurlow /* 144613a2f6bSGordon Ross * Lots of SMB commands could be safe, but 145613a2f6bSGordon Ross * these are the only ones used by libsmbfs. 1464bff34e3Sthurlow */ 147613a2f6bSGordon Ross switch (ioc->ioc_cmd) { 148613a2f6bSGordon Ross /* These are OK */ 149613a2f6bSGordon Ross case SMB_COM_CLOSE: 150613a2f6bSGordon Ross case SMB_COM_FLUSH: 151613a2f6bSGordon Ross case SMB_COM_NT_CREATE_ANDX: 152613a2f6bSGordon Ross case SMB_COM_OPEN_PRINT_FILE: 153613a2f6bSGordon Ross case SMB_COM_CLOSE_PRINT_FILE: 154613a2f6bSGordon Ross break; 155613a2f6bSGordon Ross 156613a2f6bSGordon Ross default: 157613a2f6bSGordon Ross err = EPERM; 158613a2f6bSGordon Ross goto out; 1594bff34e3Sthurlow } 1604bff34e3Sthurlow 161613a2f6bSGordon Ross err = smb_rq_alloc(SSTOCP(ssp), ioc->ioc_cmd, &scred, &rqp); 162613a2f6bSGordon Ross if (err) 163613a2f6bSGordon Ross goto out; 164613a2f6bSGordon Ross 165613a2f6bSGordon Ross mbp = &rqp->sr_rq; 166613a2f6bSGordon Ross err = mb_put_mem(mbp, ioc->ioc_tbuf, ioc->ioc_tbufsz, mbseg); 167613a2f6bSGordon Ross 168613a2f6bSGordon Ross err = smb_rq_simple(rqp); 169613a2f6bSGordon Ross if (err == 0) { 170613a2f6bSGordon Ross /* 171613a2f6bSGordon Ross * This may have been an open, so save the 172613a2f6bSGordon Ross * generation ID of the share, which we 173613a2f6bSGordon Ross * check before trying read or write. 174613a2f6bSGordon Ross */ 175613a2f6bSGordon Ross sdp->sd_vcgenid = ssp->ss_vcgenid; 176613a2f6bSGordon Ross 177613a2f6bSGordon Ross /* 178613a2f6bSGordon Ross * Have reply data. to copyout. 179613a2f6bSGordon Ross * SMB header already parsed. 180613a2f6bSGordon Ross */ 181613a2f6bSGordon Ross mdp = &rqp->sr_rp; 182613a2f6bSGordon Ross rsz = msgdsize(mdp->md_top) - SMB_HDRLEN; 183613a2f6bSGordon Ross if (ioc->ioc_rbufsz < rsz) { 184613a2f6bSGordon Ross err = EOVERFLOW; 185613a2f6bSGordon Ross goto out; 186613a2f6bSGordon Ross } 187613a2f6bSGordon Ross ioc->ioc_rbufsz = rsz; 188613a2f6bSGordon Ross err = md_get_mem(mdp, ioc->ioc_rbuf, rsz, mbseg); 189613a2f6bSGordon Ross if (err) 190613a2f6bSGordon Ross goto out; 191613a2f6bSGordon Ross 1924bff34e3Sthurlow } 1934bff34e3Sthurlow 194613a2f6bSGordon Ross ioc->ioc_errclass = rqp->sr_errclass; 195613a2f6bSGordon Ross ioc->ioc_serror = rqp->sr_serror; 196613a2f6bSGordon Ross ioc->ioc_error = rqp->sr_error; 197*02d09e03SGordon Ross (void) ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags); 1984bff34e3Sthurlow 199613a2f6bSGordon Ross out: 200613a2f6bSGordon Ross if (rqp != NULL) 201613a2f6bSGordon Ross smb_rq_done(rqp); /* free rqp */ 202613a2f6bSGordon Ross if (ioc != NULL) 203613a2f6bSGordon Ross kmem_free(ioc, sizeof (*ioc)); 204613a2f6bSGordon Ross smb_credrele(&scred); 205613a2f6bSGordon Ross 206613a2f6bSGordon Ross return (err); 2074bff34e3Sthurlow 2084bff34e3Sthurlow } 2094bff34e3Sthurlow 210613a2f6bSGordon Ross /* 211613a2f6bSGordon Ross * Ioctl function for SMBIOC_T2RQ 212613a2f6bSGordon Ross */ 213613a2f6bSGordon Ross int 214613a2f6bSGordon Ross smb_usr_t2request(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr) 2154bff34e3Sthurlow { 216613a2f6bSGordon Ross struct smb_cred scred; 217613a2f6bSGordon Ross struct smb_share *ssp; 218613a2f6bSGordon Ross smbioc_t2rq_t *ioc = NULL; 219613a2f6bSGordon Ross struct smb_t2rq *t2p = NULL; 220613a2f6bSGordon Ross struct mdchain *mdp; 221613a2f6bSGordon Ross int err, len, mbseg; 222613a2f6bSGordon Ross 223613a2f6bSGordon Ross /* This ioctl requires a share. */ 224613a2f6bSGordon Ross if ((ssp = sdp->sd_share) == NULL) 225613a2f6bSGordon Ross return (ENOTCONN); 2264bff34e3Sthurlow 227613a2f6bSGordon Ross smb_credinit(&scred, cr); 228613a2f6bSGordon Ross ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP); 229613a2f6bSGordon Ross if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) { 230613a2f6bSGordon Ross err = EFAULT; 231613a2f6bSGordon Ross goto out; 2324bff34e3Sthurlow } 233613a2f6bSGordon Ross 234613a2f6bSGordon Ross /* See ddi_copyin, ddi_copyout */ 235613a2f6bSGordon Ross mbseg = (flags & FKIOCTL) ? MB_MSYSTEM : MB_MUSER; 236613a2f6bSGordon Ross 237613a2f6bSGordon Ross if (ioc->ioc_setupcnt > SMBIOC_T2RQ_MAXSETUP) { 238613a2f6bSGordon Ross err = EINVAL; 239613a2f6bSGordon Ross goto out; 240613a2f6bSGordon Ross } 241613a2f6bSGordon Ross 242613a2f6bSGordon Ross t2p = kmem_alloc(sizeof (*t2p), KM_SLEEP); 243613a2f6bSGordon Ross err = smb_t2_init(t2p, SSTOCP(ssp), 244613a2f6bSGordon Ross ioc->ioc_setup, ioc->ioc_setupcnt, &scred); 245613a2f6bSGordon Ross if (err) 246613a2f6bSGordon Ross goto out; 247613a2f6bSGordon Ross len = t2p->t2_setupcount = ioc->ioc_setupcnt; 248613a2f6bSGordon Ross if (len > 1) 249613a2f6bSGordon Ross t2p->t2_setupdata = ioc->ioc_setup; 250613a2f6bSGordon Ross 251613a2f6bSGordon Ross /* This ioc member is a fixed-size array. */ 252613a2f6bSGordon Ross if (ioc->ioc_name[0]) { 253613a2f6bSGordon Ross /* Get the name length - carefully! */ 254613a2f6bSGordon Ross ioc->ioc_name[SMBIOC_T2RQ_MAXNAME-1] = '\0'; 255613a2f6bSGordon Ross t2p->t_name_len = strlen(ioc->ioc_name); 256613a2f6bSGordon Ross t2p->t_name = ioc->ioc_name; 257613a2f6bSGordon Ross } 258613a2f6bSGordon Ross t2p->t2_maxscount = 0; 259613a2f6bSGordon Ross t2p->t2_maxpcount = ioc->ioc_rparamcnt; 260613a2f6bSGordon Ross t2p->t2_maxdcount = ioc->ioc_rdatacnt; 261613a2f6bSGordon Ross 262613a2f6bSGordon Ross /* Transmit parameters */ 263613a2f6bSGordon Ross err = smb_cpdatain(&t2p->t2_tparam, 264613a2f6bSGordon Ross ioc->ioc_tparamcnt, ioc->ioc_tparam, mbseg); 265613a2f6bSGordon Ross if (err) 266613a2f6bSGordon Ross goto out; 267613a2f6bSGordon Ross 268613a2f6bSGordon Ross /* Transmit data */ 269613a2f6bSGordon Ross err = smb_cpdatain(&t2p->t2_tdata, 270613a2f6bSGordon Ross ioc->ioc_tdatacnt, ioc->ioc_tdata, mbseg); 271613a2f6bSGordon Ross if (err) 272613a2f6bSGordon Ross goto out; 273613a2f6bSGordon Ross 274613a2f6bSGordon Ross err = smb_t2_request(t2p); 275613a2f6bSGordon Ross 276613a2f6bSGordon Ross /* Copyout returned parameters. */ 277613a2f6bSGordon Ross mdp = &t2p->t2_rparam; 278613a2f6bSGordon Ross if (err == 0 && mdp->md_top != NULL) { 279613a2f6bSGordon Ross /* User's buffer large enough? */ 280613a2f6bSGordon Ross len = m_fixhdr(mdp->md_top); 281613a2f6bSGordon Ross if (len > ioc->ioc_rparamcnt) { 282613a2f6bSGordon Ross err = EMSGSIZE; 283613a2f6bSGordon Ross goto out; 284613a2f6bSGordon Ross } 285613a2f6bSGordon Ross ioc->ioc_rparamcnt = (ushort_t)len; 286613a2f6bSGordon Ross err = md_get_mem(mdp, ioc->ioc_rparam, len, mbseg); 287613a2f6bSGordon Ross if (err) 288613a2f6bSGordon Ross goto out; 289613a2f6bSGordon Ross } else 290613a2f6bSGordon Ross ioc->ioc_rparamcnt = 0; 291613a2f6bSGordon Ross 292613a2f6bSGordon Ross /* Copyout returned data. */ 293613a2f6bSGordon Ross mdp = &t2p->t2_rdata; 294613a2f6bSGordon Ross if (err == 0 && mdp->md_top != NULL) { 295613a2f6bSGordon Ross /* User's buffer large enough? */ 296613a2f6bSGordon Ross len = m_fixhdr(mdp->md_top); 297613a2f6bSGordon Ross if (len > ioc->ioc_rdatacnt) { 298613a2f6bSGordon Ross err = EMSGSIZE; 299613a2f6bSGordon Ross goto out; 300613a2f6bSGordon Ross } 301613a2f6bSGordon Ross ioc->ioc_rdatacnt = (ushort_t)len; 302613a2f6bSGordon Ross err = md_get_mem(mdp, ioc->ioc_rdata, len, mbseg); 303613a2f6bSGordon Ross if (err) 304613a2f6bSGordon Ross goto out; 305613a2f6bSGordon Ross } else 306613a2f6bSGordon Ross ioc->ioc_rdatacnt = 0; 307613a2f6bSGordon Ross 308613a2f6bSGordon Ross ioc->ioc_errclass = t2p->t2_sr_errclass; 309613a2f6bSGordon Ross ioc->ioc_serror = t2p->t2_sr_serror; 310613a2f6bSGordon Ross ioc->ioc_error = t2p->t2_sr_error; 311613a2f6bSGordon Ross ioc->ioc_rpflags2 = t2p->t2_sr_rpflags2; 312613a2f6bSGordon Ross 313*02d09e03SGordon Ross (void) ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags); 314613a2f6bSGordon Ross 315613a2f6bSGordon Ross 316613a2f6bSGordon Ross out: 317613a2f6bSGordon Ross if (t2p != NULL) { 318613a2f6bSGordon Ross /* Note: t2p->t_name no longer allocated */ 319613a2f6bSGordon Ross smb_t2_done(t2p); 320613a2f6bSGordon Ross kmem_free(t2p, sizeof (*t2p)); 321613a2f6bSGordon Ross } 322613a2f6bSGordon Ross if (ioc != NULL) 323613a2f6bSGordon Ross kmem_free(ioc, sizeof (*ioc)); 324613a2f6bSGordon Ross smb_credrele(&scred); 325613a2f6bSGordon Ross 326613a2f6bSGordon Ross return (err); 3274bff34e3Sthurlow } 3284bff34e3Sthurlow 329613a2f6bSGordon Ross /* helper for _t2request */ 3304bff34e3Sthurlow static int 331613a2f6bSGordon Ross smb_cpdatain(struct mbchain *mbp, int len, char *data, int mbseg) 3324bff34e3Sthurlow { 333613a2f6bSGordon Ross int error; 334613a2f6bSGordon Ross 335613a2f6bSGordon Ross if (len == 0) 336613a2f6bSGordon Ross return (0); 337613a2f6bSGordon Ross error = mb_init(mbp); 338613a2f6bSGordon Ross if (error) 339613a2f6bSGordon Ross return (error); 340613a2f6bSGordon Ross return (mb_put_mem(mbp, data, len, mbseg)); 3414bff34e3Sthurlow } 3424bff34e3Sthurlow 343613a2f6bSGordon Ross /* 344613a2f6bSGordon Ross * Helper for nsmb_ioctl cases 345613a2f6bSGordon Ross * SMBIOC_READ, SMBIOC_WRITE 346613a2f6bSGordon Ross */ 3471b34bc4aSbs int 348613a2f6bSGordon Ross smb_usr_rw(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr) 3491b34bc4aSbs { 350613a2f6bSGordon Ross struct smb_cred scred; 351613a2f6bSGordon Ross struct smb_share *ssp; 352613a2f6bSGordon Ross smbioc_rw_t *ioc = NULL; 353613a2f6bSGordon Ross struct iovec aiov[1]; 354613a2f6bSGordon Ross struct uio auio; 355613a2f6bSGordon Ross u_int16_t fh; 356613a2f6bSGordon Ross int err; 357613a2f6bSGordon Ross uio_rw_t rw; 3581b34bc4aSbs 359613a2f6bSGordon Ross /* This ioctl requires a share. */ 360613a2f6bSGordon Ross if ((ssp = sdp->sd_share) == NULL) 361613a2f6bSGordon Ross return (ENOTCONN); 362613a2f6bSGordon Ross 363613a2f6bSGordon Ross /* After reconnect, force close+reopen */ 364613a2f6bSGordon Ross if (sdp->sd_vcgenid != ssp->ss_vcgenid) 365613a2f6bSGordon Ross return (ESTALE); 366613a2f6bSGordon Ross 367613a2f6bSGordon Ross smb_credinit(&scred, cr); 368613a2f6bSGordon Ross ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP); 369613a2f6bSGordon Ross if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) { 370613a2f6bSGordon Ross err = EFAULT; 3711b34bc4aSbs goto out; 372613a2f6bSGordon Ross } 373613a2f6bSGordon Ross 374613a2f6bSGordon Ross switch (cmd) { 375613a2f6bSGordon Ross case SMBIOC_READ: 376613a2f6bSGordon Ross rw = UIO_READ; 377613a2f6bSGordon Ross break; 378613a2f6bSGordon Ross case SMBIOC_WRITE: 379613a2f6bSGordon Ross rw = UIO_WRITE; 380613a2f6bSGordon Ross break; 381613a2f6bSGordon Ross default: 382613a2f6bSGordon Ross err = ENODEV; 383613a2f6bSGordon Ross goto out; 384613a2f6bSGordon Ross } 385613a2f6bSGordon Ross 386613a2f6bSGordon Ross fh = ioc->ioc_fh; 387613a2f6bSGordon Ross 388613a2f6bSGordon Ross aiov[0].iov_base = ioc->ioc_base; 389613a2f6bSGordon Ross aiov[0].iov_len = (size_t)ioc->ioc_cnt; 390613a2f6bSGordon Ross 391613a2f6bSGordon Ross auio.uio_iov = aiov; 392613a2f6bSGordon Ross auio.uio_iovcnt = 1; 393613a2f6bSGordon Ross auio.uio_loffset = ioc->ioc_offset; 394613a2f6bSGordon Ross auio.uio_segflg = (flags & FKIOCTL) ? 395613a2f6bSGordon Ross UIO_SYSSPACE : UIO_USERSPACE; 396613a2f6bSGordon Ross auio.uio_fmode = 0; 397613a2f6bSGordon Ross auio.uio_resid = (size_t)ioc->ioc_cnt; 398613a2f6bSGordon Ross 399613a2f6bSGordon Ross err = smb_rwuio(ssp, fh, rw, &auio, &scred, 0); 400613a2f6bSGordon Ross 401613a2f6bSGordon Ross /* 402613a2f6bSGordon Ross * On return ioc_cnt holds the 403613a2f6bSGordon Ross * number of bytes transferred. 404613a2f6bSGordon Ross */ 405613a2f6bSGordon Ross ioc->ioc_cnt -= auio.uio_resid; 406613a2f6bSGordon Ross 407*02d09e03SGordon Ross (void) ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags); 408613a2f6bSGordon Ross 4091b34bc4aSbs out: 410613a2f6bSGordon Ross if (ioc != NULL) 411613a2f6bSGordon Ross kmem_free(ioc, sizeof (*ioc)); 412613a2f6bSGordon Ross smb_credrele(&scred); 413613a2f6bSGordon Ross 414613a2f6bSGordon Ross return (err); 4151b34bc4aSbs } 4161b34bc4aSbs 417613a2f6bSGordon Ross /* 418613a2f6bSGordon Ross * Ioctl functions: SMBIOC_SSN_FIND, SMBIOC_SSN_CREATE 419613a2f6bSGordon Ross * Find or create a session (a.k.a. "VC" in here) 420613a2f6bSGordon Ross */ 4214bff34e3Sthurlow int 422613a2f6bSGordon Ross smb_usr_get_ssn(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr) 4234bff34e3Sthurlow { 424613a2f6bSGordon Ross struct smb_cred scred; 425613a2f6bSGordon Ross smbioc_ossn_t *ossn = NULL; 4264bff34e3Sthurlow struct smb_vc *vcp = NULL; 4274bff34e3Sthurlow int error = 0; 428613a2f6bSGordon Ross uid_t realuid; 4294bff34e3Sthurlow 430613a2f6bSGordon Ross /* Should be no VC */ 431613a2f6bSGordon Ross if (sdp->sd_vc != NULL) 432613a2f6bSGordon Ross return (EISCONN); 433613a2f6bSGordon Ross 434613a2f6bSGordon Ross smb_credinit(&scred, cr); 435613a2f6bSGordon Ross ossn = kmem_alloc(sizeof (*ossn), KM_SLEEP); 436613a2f6bSGordon Ross if (ddi_copyin((void *)arg, ossn, sizeof (*ossn), flags)) { 437613a2f6bSGordon Ross error = EFAULT; 438613a2f6bSGordon Ross goto out; 4394bff34e3Sthurlow } 440613a2f6bSGordon Ross 441613a2f6bSGordon Ross /* 442613a2f6bSGordon Ross * Only superuser can specify a UID or GID. 443613a2f6bSGordon Ross */ 444613a2f6bSGordon Ross realuid = crgetruid(cr); 445613a2f6bSGordon Ross if (ossn->ssn_owner == SMBM_ANY_OWNER) 446613a2f6bSGordon Ross ossn->ssn_owner = realuid; 447613a2f6bSGordon Ross else { 4484bff34e3Sthurlow /* 449613a2f6bSGordon Ross * Do we have the privilege to create with the 450613a2f6bSGordon Ross * specified uid? (does uid == cr->cr_uid, etc.) 4514bff34e3Sthurlow */ 452613a2f6bSGordon Ross if (secpolicy_vnode_owner(cr, ossn->ssn_owner)) { 453613a2f6bSGordon Ross error = EPERM; 454613a2f6bSGordon Ross goto out; 4554bff34e3Sthurlow } 456613a2f6bSGordon Ross /* ossn->ssn_owner is OK */ 4574bff34e3Sthurlow } 4584bff34e3Sthurlow 459613a2f6bSGordon Ross /* 460613a2f6bSGordon Ross * Make sure the strings are null terminated. 461613a2f6bSGordon Ross */ 462613a2f6bSGordon Ross ossn->ssn_srvname[SMBIOC_MAX_NAME-1] = '\0'; 463613a2f6bSGordon Ross ossn->ssn_id.id_domain[ SMBIOC_MAX_NAME-1] = '\0'; 464613a2f6bSGordon Ross ossn->ssn_id.id_user[ SMBIOC_MAX_NAME-1] = '\0'; 4654bff34e3Sthurlow 466613a2f6bSGordon Ross if (cmd == SMBIOC_SSN_CREATE) 467613a2f6bSGordon Ross ossn->ssn_vopt |= SMBVOPT_CREATE; 468613a2f6bSGordon Ross else /* FIND */ 469613a2f6bSGordon Ross ossn->ssn_vopt &= ~SMBVOPT_CREATE; 4704bff34e3Sthurlow 471613a2f6bSGordon Ross error = smb_vc_findcreate(ossn, &scred, &vcp); 4724bff34e3Sthurlow if (error) 4734bff34e3Sthurlow goto out; 474613a2f6bSGordon Ross ASSERT(vcp != NULL); 4754bff34e3Sthurlow 4764bff34e3Sthurlow /* 477613a2f6bSGordon Ross * We have a VC, held, but not locked. 478613a2f6bSGordon Ross * If we're creating, mark this instance as 479613a2f6bSGordon Ross * an open from IOD so close can do cleanup. 480613a2f6bSGordon Ross * 481613a2f6bSGordon Ross * XXX: Would be nice to have a back pointer 482613a2f6bSGordon Ross * from the VC to this (IOD) sdp instance. 4834bff34e3Sthurlow */ 484613a2f6bSGordon Ross if (cmd == SMBIOC_SSN_CREATE) { 485613a2f6bSGordon Ross if (vcp->iod_thr != NULL) { 486613a2f6bSGordon Ross error = EEXIST; 487613a2f6bSGordon Ross goto out; 488613a2f6bSGordon Ross } 489613a2f6bSGordon Ross sdp->sd_flags |= NSMBFL_IOD; 490613a2f6bSGordon Ross } else { 491613a2f6bSGordon Ross /* 492613a2f6bSGordon Ross * Wait for it to finish connecting 493613a2f6bSGordon Ross * (or reconnect) if necessary. 494613a2f6bSGordon Ross */ 495613a2f6bSGordon Ross if (vcp->vc_state != SMBIOD_ST_VCACTIVE) { 496613a2f6bSGordon Ross error = smb_iod_reconnect(vcp); 497613a2f6bSGordon Ross if (error != 0) 498613a2f6bSGordon Ross goto out; 499613a2f6bSGordon Ross } 500613a2f6bSGordon Ross } 501613a2f6bSGordon Ross 502613a2f6bSGordon Ross /* 503613a2f6bSGordon Ross * The VC has a hold from _findvc 504613a2f6bSGordon Ross * which we keep until _SSN_RELE 505613a2f6bSGordon Ross * or nsmb_close(). 506613a2f6bSGordon Ross */ 507613a2f6bSGordon Ross sdp->sd_level = SMBL_VC; 508613a2f6bSGordon Ross sdp->sd_vc = vcp; 509613a2f6bSGordon Ross vcp = NULL; 510613a2f6bSGordon Ross (void) ddi_copyout(ossn, (void *)arg, sizeof (*ossn), flags); 5114bff34e3Sthurlow 5124bff34e3Sthurlow out: 513613a2f6bSGordon Ross if (vcp) { 514613a2f6bSGordon Ross /* Error path: rele hold from _findcreate */ 515613a2f6bSGordon Ross smb_vc_rele(vcp); 516613a2f6bSGordon Ross } 517613a2f6bSGordon Ross if (ossn != NULL) 518613a2f6bSGordon Ross kmem_free(ossn, sizeof (*ossn)); 519613a2f6bSGordon Ross smb_credrele(&scred); 520613a2f6bSGordon Ross 5214bff34e3Sthurlow return (error); 5224bff34e3Sthurlow } 5234bff34e3Sthurlow 524613a2f6bSGordon Ross /* 525613a2f6bSGordon Ross * Ioctl functions: SMBIOC_SSN_RELE, SMBIOC_SSN_KILL 526613a2f6bSGordon Ross * Release or kill the current session. 527613a2f6bSGordon Ross */ 5284bff34e3Sthurlow int 529613a2f6bSGordon Ross smb_usr_drop_ssn(smb_dev_t *sdp, int cmd) 5304bff34e3Sthurlow { 531613a2f6bSGordon Ross struct smb_vc *vcp = NULL; 5324bff34e3Sthurlow 533613a2f6bSGordon Ross /* Must have a VC. */ 534613a2f6bSGordon Ross if ((vcp = sdp->sd_vc) == NULL) 535613a2f6bSGordon Ross return (ENOTCONN); 5364bff34e3Sthurlow 537613a2f6bSGordon Ross /* If we have a share ref, drop it too. */ 538613a2f6bSGordon Ross if (sdp->sd_share) { 539613a2f6bSGordon Ross smb_share_rele(sdp->sd_share); 540613a2f6bSGordon Ross sdp->sd_share = NULL; 541613a2f6bSGordon Ross sdp->sd_level = SMBL_VC; 5424bff34e3Sthurlow } 5434bff34e3Sthurlow 544613a2f6bSGordon Ross if (cmd == SMBIOC_SSN_KILL) 545613a2f6bSGordon Ross smb_vc_kill(vcp); 5464bff34e3Sthurlow 547613a2f6bSGordon Ross /* Drop the VC ref. */ 548613a2f6bSGordon Ross smb_vc_rele(vcp); 549613a2f6bSGordon Ross sdp->sd_vc = NULL; 550613a2f6bSGordon Ross sdp->sd_level = 0; 551613a2f6bSGordon Ross 552613a2f6bSGordon Ross return (0); 5534bff34e3Sthurlow } 5544bff34e3Sthurlow 5554bff34e3Sthurlow /* 556613a2f6bSGordon Ross * Find or create a tree (connected share) 5574bff34e3Sthurlow */ 5584bff34e3Sthurlow int 559613a2f6bSGordon Ross smb_usr_get_tree(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr) 5604bff34e3Sthurlow { 561613a2f6bSGordon Ross struct smb_cred scred; 562613a2f6bSGordon Ross smbioc_tcon_t *tcon = NULL; 563613a2f6bSGordon Ross struct smb_vc *vcp = NULL; 564613a2f6bSGordon Ross struct smb_share *ssp = NULL; 565613a2f6bSGordon Ross int error = 0; 5664bff34e3Sthurlow 567613a2f6bSGordon Ross /* Must have a VC. */ 568613a2f6bSGordon Ross if ((vcp = sdp->sd_vc) == NULL) 569613a2f6bSGordon Ross return (ENOTCONN); 570613a2f6bSGordon Ross /* Should not have a share. */ 571613a2f6bSGordon Ross if (sdp->sd_share != NULL) 572613a2f6bSGordon Ross return (EISCONN); 573613a2f6bSGordon Ross 574613a2f6bSGordon Ross smb_credinit(&scred, cr); 575613a2f6bSGordon Ross tcon = kmem_alloc(sizeof (*tcon), KM_SLEEP); 576613a2f6bSGordon Ross if (ddi_copyin((void *)arg, tcon, sizeof (*tcon), flags)) { 577613a2f6bSGordon Ross error = EFAULT; 578613a2f6bSGordon Ross goto out; 5794bff34e3Sthurlow } 580613a2f6bSGordon Ross 581613a2f6bSGordon Ross /* 582613a2f6bSGordon Ross * Make sure the strings are null terminated. 583613a2f6bSGordon Ross */ 584613a2f6bSGordon Ross tcon->tc_sh.sh_name[SMBIOC_MAX_NAME-1] = '\0'; 585613a2f6bSGordon Ross tcon->tc_sh.sh_pass[SMBIOC_MAX_NAME-1] = '\0'; 586613a2f6bSGordon Ross tcon->tc_sh.sh_type_req[SMBIOC_STYPE_LEN-1] = '\0'; 587613a2f6bSGordon Ross bzero(tcon->tc_sh.sh_type_ret, SMBIOC_STYPE_LEN); 588613a2f6bSGordon Ross 589613a2f6bSGordon Ross if (cmd == SMBIOC_TREE_CONNECT) 590613a2f6bSGordon Ross tcon->tc_opt |= SMBSOPT_CREATE; 591613a2f6bSGordon Ross else /* FIND */ 592613a2f6bSGordon Ross tcon->tc_opt &= ~SMBSOPT_CREATE; 593613a2f6bSGordon Ross 594613a2f6bSGordon Ross error = smb_share_findcreate(tcon, vcp, &ssp, &scred); 5954bff34e3Sthurlow if (error) 596613a2f6bSGordon Ross goto out; 597613a2f6bSGordon Ross ASSERT(ssp != NULL); 598613a2f6bSGordon Ross 599613a2f6bSGordon Ross /* 600613a2f6bSGordon Ross * We have a share, held, but not locked. 601613a2f6bSGordon Ross * If we're creating, do tree connect now, 602613a2f6bSGordon Ross * otherwise let that wait for a request. 603613a2f6bSGordon Ross */ 604613a2f6bSGordon Ross if (cmd == SMBIOC_TREE_CONNECT) { 605613a2f6bSGordon Ross error = smb_share_tcon(ssp, &scred); 606613a2f6bSGordon Ross if (error) 607613a2f6bSGordon Ross goto out; 6084bff34e3Sthurlow } 609613a2f6bSGordon Ross 610613a2f6bSGordon Ross /* 611613a2f6bSGordon Ross * Give caller the real share type from 612613a2f6bSGordon Ross * the tree connect response, so they can 613613a2f6bSGordon Ross * see if they got the requested type. 614613a2f6bSGordon Ross */ 615*02d09e03SGordon Ross (void) memcpy(tcon->tc_sh.sh_type_ret, 616613a2f6bSGordon Ross ssp->ss_type_ret, SMBIOC_STYPE_LEN); 617613a2f6bSGordon Ross 618613a2f6bSGordon Ross /* 619613a2f6bSGordon Ross * The share has a hold from _tcon 620613a2f6bSGordon Ross * which we keep until nsmb_close() 621613a2f6bSGordon Ross * or the SMBIOC_TDIS below. 622613a2f6bSGordon Ross */ 623613a2f6bSGordon Ross sdp->sd_level = SMBL_SHARE; 624613a2f6bSGordon Ross sdp->sd_share = ssp; 625613a2f6bSGordon Ross ssp = NULL; 626613a2f6bSGordon Ross (void) ddi_copyout(tcon, (void *)arg, sizeof (*tcon), flags); 627613a2f6bSGordon Ross 628613a2f6bSGordon Ross out: 629613a2f6bSGordon Ross if (ssp) { 630613a2f6bSGordon Ross /* Error path: rele hold from _findcreate */ 631613a2f6bSGordon Ross smb_share_rele(ssp); 6324bff34e3Sthurlow } 633613a2f6bSGordon Ross if (tcon) { 634613a2f6bSGordon Ross /* 635613a2f6bSGordon Ross * This structure may contain a 636613a2f6bSGordon Ross * cleartext password, so zap it. 637613a2f6bSGordon Ross */ 638613a2f6bSGordon Ross bzero(tcon, sizeof (*tcon)); 639613a2f6bSGordon Ross kmem_free(tcon, sizeof (*tcon)); 640613a2f6bSGordon Ross } 641613a2f6bSGordon Ross smb_credrele(&scred); 6424bff34e3Sthurlow 643613a2f6bSGordon Ross return (error); 6444bff34e3Sthurlow } 6454bff34e3Sthurlow 646613a2f6bSGordon Ross /* 647613a2f6bSGordon Ross * Ioctl functions: SMBIOC_TREE_RELE, SMBIOC_TREE_KILL 648613a2f6bSGordon Ross * Release or kill the current tree 649613a2f6bSGordon Ross */ 650613a2f6bSGordon Ross int 651613a2f6bSGordon Ross smb_usr_drop_tree(smb_dev_t *sdp, int cmd) 6524bff34e3Sthurlow { 653613a2f6bSGordon Ross struct smb_share *ssp = NULL; 6544bff34e3Sthurlow 655613a2f6bSGordon Ross /* Must have a VC and a share. */ 656613a2f6bSGordon Ross if (sdp->sd_vc == NULL) 657613a2f6bSGordon Ross return (ENOTCONN); 658613a2f6bSGordon Ross if ((ssp = sdp->sd_share) == NULL) 659613a2f6bSGordon Ross return (ENOTCONN); 660613a2f6bSGordon Ross 661613a2f6bSGordon Ross if (cmd == SMBIOC_TREE_KILL) 662613a2f6bSGordon Ross smb_share_kill(ssp); 663613a2f6bSGordon Ross 664613a2f6bSGordon Ross /* Drop the share ref. */ 665613a2f6bSGordon Ross smb_share_rele(sdp->sd_share); 666613a2f6bSGordon Ross sdp->sd_share = NULL; 667613a2f6bSGordon Ross sdp->sd_level = SMBL_VC; 668613a2f6bSGordon Ross 669613a2f6bSGordon Ross return (0); 6704bff34e3Sthurlow } 6714bff34e3Sthurlow 672613a2f6bSGordon Ross 673613a2f6bSGordon Ross /* 674613a2f6bSGordon Ross * Ioctl function: SMBIOC_IOD_WORK 675613a2f6bSGordon Ross * 676613a2f6bSGordon Ross * Become the reader (IOD) thread, until either the connection is 677613a2f6bSGordon Ross * reset by the server, or until the connection is idle longer than 678613a2f6bSGordon Ross * some max time. (max idle time not yet implemented) 679613a2f6bSGordon Ross */ 6804bff34e3Sthurlow int 681613a2f6bSGordon Ross smb_usr_iod_work(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr) 6824bff34e3Sthurlow { 683613a2f6bSGordon Ross struct smb_vc *vcp = NULL; 684613a2f6bSGordon Ross int err = 0; 6854bff34e3Sthurlow 686613a2f6bSGordon Ross /* Must have a valid session. */ 687613a2f6bSGordon Ross if ((vcp = sdp->sd_vc) == NULL) 6884bff34e3Sthurlow return (EINVAL); 689613a2f6bSGordon Ross if (vcp->vc_flags & SMBV_GONE) 690613a2f6bSGordon Ross return (EINVAL); 691613a2f6bSGordon Ross 692613a2f6bSGordon Ross /* 693613a2f6bSGordon Ross * Is there already an IOD for this VC? 694613a2f6bSGordon Ross * (Should never happen.) 695613a2f6bSGordon Ross */ 696613a2f6bSGordon Ross SMB_VC_LOCK(vcp); 697613a2f6bSGordon Ross if (vcp->iod_thr == NULL) 698613a2f6bSGordon Ross vcp->iod_thr = curthread; 699613a2f6bSGordon Ross else 700613a2f6bSGordon Ross err = EEXIST; 701613a2f6bSGordon Ross SMB_VC_UNLOCK(vcp); 702613a2f6bSGordon Ross if (err) 703613a2f6bSGordon Ross return (err); 704613a2f6bSGordon Ross 705613a2f6bSGordon Ross /* 706613a2f6bSGordon Ross * Copy the "work" state, etc. into the VC 707613a2f6bSGordon Ross * The MAC key is copied separately. 708613a2f6bSGordon Ross */ 709613a2f6bSGordon Ross if (ddi_copyin((void *)arg, &vcp->vc_work, 710613a2f6bSGordon Ross sizeof (smbioc_ssn_work_t), flags)) { 711613a2f6bSGordon Ross err = EFAULT; 712613a2f6bSGordon Ross goto out; 7134bff34e3Sthurlow } 714613a2f6bSGordon Ross if (vcp->vc_u_maclen) { 715613a2f6bSGordon Ross vcp->vc_mackeylen = vcp->vc_u_maclen; 716613a2f6bSGordon Ross vcp->vc_mackey = kmem_alloc(vcp->vc_mackeylen, KM_SLEEP); 717613a2f6bSGordon Ross if (ddi_copyin(vcp->vc_u_mackey.lp_ptr, vcp->vc_mackey, 718613a2f6bSGordon Ross vcp->vc_mackeylen, flags)) { 719613a2f6bSGordon Ross err = EFAULT; 720613a2f6bSGordon Ross goto out; 7214bff34e3Sthurlow } 7229c9af259SGordon Ross } 723613a2f6bSGordon Ross 724613a2f6bSGordon Ross err = smb_iod_vc_work(vcp, cr); 725613a2f6bSGordon Ross 726613a2f6bSGordon Ross /* Caller wants state here. */ 727613a2f6bSGordon Ross vcp->vc_work.wk_out_state = vcp->vc_state; 728613a2f6bSGordon Ross 729613a2f6bSGordon Ross (void) ddi_copyout(&vcp->vc_work, (void *)arg, 730613a2f6bSGordon Ross sizeof (smbioc_ssn_work_t), flags); 731613a2f6bSGordon Ross 732613a2f6bSGordon Ross out: 733613a2f6bSGordon Ross if (vcp->vc_mackey) { 734613a2f6bSGordon Ross kmem_free(vcp->vc_mackey, vcp->vc_mackeylen); 735613a2f6bSGordon Ross vcp->vc_mackey = NULL; 736613a2f6bSGordon Ross vcp->vc_mackeylen = 0; 737613a2f6bSGordon Ross } 738613a2f6bSGordon Ross 739613a2f6bSGordon Ross /* 740613a2f6bSGordon Ross * The IOD thread is leaving the driver. Clear iod_thr, 741613a2f6bSGordon Ross * and wake up anybody waiting for us to quit. 742613a2f6bSGordon Ross */ 743613a2f6bSGordon Ross SMB_VC_LOCK(vcp); 744613a2f6bSGordon Ross vcp->iod_thr = NULL; 745613a2f6bSGordon Ross cv_broadcast(&vcp->vc_statechg); 746613a2f6bSGordon Ross SMB_VC_UNLOCK(vcp); 747613a2f6bSGordon Ross 748613a2f6bSGordon Ross return (err); 7494bff34e3Sthurlow } 7504bff34e3Sthurlow 7514bff34e3Sthurlow /* 752613a2f6bSGordon Ross * Ioctl functions: SMBIOC_IOD_IDLE, SMBIOC_IOD_RCFAIL 753613a2f6bSGordon Ross * 754613a2f6bSGordon Ross * Wait for user-level requests to be enqueued on this session, 755613a2f6bSGordon Ross * and then return to the user-space helper, which will then 756613a2f6bSGordon Ross * initiate a reconnect, etc. 7574bff34e3Sthurlow */ 7584bff34e3Sthurlow int 759613a2f6bSGordon Ross smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags) 7604bff34e3Sthurlow { 761613a2f6bSGordon Ross struct smb_vc *vcp = NULL; 762613a2f6bSGordon Ross int err = 0; 763613a2f6bSGordon Ross 764613a2f6bSGordon Ross /* Must have a valid session. */ 765613a2f6bSGordon Ross if ((vcp = sdp->sd_vc) == NULL) 766613a2f6bSGordon Ross return (EINVAL); 767613a2f6bSGordon Ross if (vcp->vc_flags & SMBV_GONE) 768613a2f6bSGordon Ross return (EINVAL); 769613a2f6bSGordon Ross 770613a2f6bSGordon Ross /* 771613a2f6bSGordon Ross * Is there already an IOD for this VC? 772613a2f6bSGordon Ross * (Should never happen.) 773613a2f6bSGordon Ross */ 774613a2f6bSGordon Ross SMB_VC_LOCK(vcp); 775613a2f6bSGordon Ross if (vcp->iod_thr == NULL) 776613a2f6bSGordon Ross vcp->iod_thr = curthread; 777613a2f6bSGordon Ross else 778613a2f6bSGordon Ross err = EEXIST; 779613a2f6bSGordon Ross SMB_VC_UNLOCK(vcp); 780613a2f6bSGordon Ross if (err) 781613a2f6bSGordon Ross return (err); 782613a2f6bSGordon Ross 783613a2f6bSGordon Ross /* nothing to copyin */ 7844bff34e3Sthurlow 7854bff34e3Sthurlow switch (cmd) { 786613a2f6bSGordon Ross case SMBIOC_IOD_IDLE: 787613a2f6bSGordon Ross err = smb_iod_vc_idle(vcp); 7884bff34e3Sthurlow break; 789613a2f6bSGordon Ross 790613a2f6bSGordon Ross case SMBIOC_IOD_RCFAIL: 791613a2f6bSGordon Ross err = smb_iod_vc_rcfail(vcp); 7924bff34e3Sthurlow break; 793613a2f6bSGordon Ross 7944bff34e3Sthurlow default: 795613a2f6bSGordon Ross err = ENOTTY; 796613a2f6bSGordon Ross goto out; 7974bff34e3Sthurlow } 7984bff34e3Sthurlow 799613a2f6bSGordon Ross /* Both of these ioctls copy out the new state. */ 800613a2f6bSGordon Ross (void) ddi_copyout(&vcp->vc_state, (void *)arg, 801613a2f6bSGordon Ross sizeof (int), flags); 8024bff34e3Sthurlow 803613a2f6bSGordon Ross out: 8044bff34e3Sthurlow /* 805613a2f6bSGordon Ross * The IOD thread is leaving the driver. Clear iod_thr, 806613a2f6bSGordon Ross * and wake up anybody waiting for us to quit. 8074bff34e3Sthurlow */ 808613a2f6bSGordon Ross SMB_VC_LOCK(vcp); 809613a2f6bSGordon Ross vcp->iod_thr = NULL; 810613a2f6bSGordon Ross cv_broadcast(&vcp->vc_statechg); 811613a2f6bSGordon Ross SMB_VC_UNLOCK(vcp); 8124bff34e3Sthurlow 813613a2f6bSGordon Ross return (err); 8144bff34e3Sthurlow } 815