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 /* 36*613a2f6bSGordon 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> 47*613a2f6bSGordon Ross #include <sys/file.h> 484bff34e3Sthurlow #include <sys/socket.h> 49*613a2f6bSGordon 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 60*613a2f6bSGordon Ross static int smb_cpdatain(struct mbchain *mbp, int len, char *data, int seg); 61*613a2f6bSGordon Ross 624bff34e3Sthurlow /* 63*613a2f6bSGordon Ross * Ioctl function for SMBIOC_FLAGS2 644bff34e3Sthurlow */ 65*613a2f6bSGordon Ross int 66*613a2f6bSGordon Ross smb_usr_get_flags2(smb_dev_t *sdp, intptr_t arg, int flags) 67*613a2f6bSGordon Ross { 68*613a2f6bSGordon Ross struct smb_vc *vcp = NULL; 69*613a2f6bSGordon Ross 70*613a2f6bSGordon Ross /* This ioctl requires a session. */ 71*613a2f6bSGordon Ross if ((vcp = sdp->sd_vc) == NULL) 72*613a2f6bSGordon Ross return (ENOTCONN); 73*613a2f6bSGordon Ross 74*613a2f6bSGordon Ross /* 75*613a2f6bSGordon Ross * Return the flags2 value. 76*613a2f6bSGordon Ross */ 77*613a2f6bSGordon Ross if (ddi_copyout(&vcp->vc_hflags2, (void *)arg, 78*613a2f6bSGordon Ross sizeof (u_int16_t), flags)) 79*613a2f6bSGordon Ross return (EFAULT); 80*613a2f6bSGordon Ross 81*613a2f6bSGordon Ross return (0); 82*613a2f6bSGordon Ross } 834bff34e3Sthurlow 844bff34e3Sthurlow /* 85*613a2f6bSGordon Ross * Ioctl function for SMBIOC_GETSSNKEY 86*613a2f6bSGordon Ross * Size copied out is SMBIOC_HASH_SZ. 87*613a2f6bSGordon Ross * 88*613a2f6bSGordon Ross * The RPC library needs this for encrypting things 89*613a2f6bSGordon Ross * like "set password" requests. This is called 90*613a2f6bSGordon Ross * with an active RPC binding, so the connection 91*613a2f6bSGordon Ross * will already be active (but this checks). 924bff34e3Sthurlow */ 93*613a2f6bSGordon Ross int 94*613a2f6bSGordon Ross smb_usr_get_ssnkey(smb_dev_t *sdp, intptr_t arg, int flags) 954bff34e3Sthurlow { 96*613a2f6bSGordon Ross struct smb_vc *vcp = NULL; 97*613a2f6bSGordon Ross 98*613a2f6bSGordon Ross /* This ioctl requires an active session. */ 99*613a2f6bSGordon Ross if ((vcp = sdp->sd_vc) == NULL) 100*613a2f6bSGordon Ross return (ENOTCONN); 101*613a2f6bSGordon Ross if (vcp->vc_state != SMBIOD_ST_VCACTIVE) 102*613a2f6bSGordon Ross return (ENOTCONN); 1034bff34e3Sthurlow 1044bff34e3Sthurlow /* 105*613a2f6bSGordon Ross * Return the session key. 1064bff34e3Sthurlow */ 107*613a2f6bSGordon Ross if (ddi_copyout(vcp->vc_ssn_key, (void *)arg, 108*613a2f6bSGordon Ross SMBIOC_HASH_SZ, flags)) 109*613a2f6bSGordon Ross return (EFAULT); 110*613a2f6bSGordon Ross 111*613a2f6bSGordon Ross return (0); 112*613a2f6bSGordon Ross } 113*613a2f6bSGordon Ross 114*613a2f6bSGordon Ross /* 115*613a2f6bSGordon Ross * Ioctl function for SMBIOC_REQUEST 116*613a2f6bSGordon Ross */ 117*613a2f6bSGordon Ross int 118*613a2f6bSGordon Ross smb_usr_simplerq(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr) 119*613a2f6bSGordon Ross { 120*613a2f6bSGordon Ross struct smb_cred scred; 121*613a2f6bSGordon Ross struct smb_share *ssp; 122*613a2f6bSGordon Ross smbioc_rq_t *ioc = NULL; 123*613a2f6bSGordon Ross struct smb_rq *rqp = NULL; 124*613a2f6bSGordon Ross struct mbchain *mbp; 125*613a2f6bSGordon Ross struct mdchain *mdp; 126*613a2f6bSGordon Ross uint32_t rsz; 127*613a2f6bSGordon Ross int err, mbseg; 128*613a2f6bSGordon Ross 129*613a2f6bSGordon Ross /* This ioctl requires a share. */ 130*613a2f6bSGordon Ross if ((ssp = sdp->sd_share) == NULL) 131*613a2f6bSGordon Ross return (ENOTCONN); 132*613a2f6bSGordon Ross 133*613a2f6bSGordon Ross smb_credinit(&scred, cr); 134*613a2f6bSGordon Ross ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP); 135*613a2f6bSGordon Ross if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) { 136*613a2f6bSGordon Ross err = EFAULT; 137*613a2f6bSGordon Ross goto out; 1384bff34e3Sthurlow } 1394bff34e3Sthurlow 140*613a2f6bSGordon Ross /* See ddi_copyin, ddi_copyout */ 141*613a2f6bSGordon Ross mbseg = (flags & FKIOCTL) ? MB_MSYSTEM : MB_MUSER; 1424bff34e3Sthurlow 1434bff34e3Sthurlow /* 144*613a2f6bSGordon Ross * Lots of SMB commands could be safe, but 145*613a2f6bSGordon Ross * these are the only ones used by libsmbfs. 1464bff34e3Sthurlow */ 147*613a2f6bSGordon Ross switch (ioc->ioc_cmd) { 148*613a2f6bSGordon Ross /* These are OK */ 149*613a2f6bSGordon Ross case SMB_COM_CLOSE: 150*613a2f6bSGordon Ross case SMB_COM_FLUSH: 151*613a2f6bSGordon Ross case SMB_COM_NT_CREATE_ANDX: 152*613a2f6bSGordon Ross case SMB_COM_OPEN_PRINT_FILE: 153*613a2f6bSGordon Ross case SMB_COM_CLOSE_PRINT_FILE: 154*613a2f6bSGordon Ross break; 155*613a2f6bSGordon Ross 156*613a2f6bSGordon Ross default: 157*613a2f6bSGordon Ross err = EPERM; 158*613a2f6bSGordon Ross goto out; 1594bff34e3Sthurlow } 1604bff34e3Sthurlow 161*613a2f6bSGordon Ross err = smb_rq_alloc(SSTOCP(ssp), ioc->ioc_cmd, &scred, &rqp); 162*613a2f6bSGordon Ross if (err) 163*613a2f6bSGordon Ross goto out; 164*613a2f6bSGordon Ross 165*613a2f6bSGordon Ross mbp = &rqp->sr_rq; 166*613a2f6bSGordon Ross err = mb_put_mem(mbp, ioc->ioc_tbuf, ioc->ioc_tbufsz, mbseg); 167*613a2f6bSGordon Ross 168*613a2f6bSGordon Ross err = smb_rq_simple(rqp); 169*613a2f6bSGordon Ross if (err == 0) { 170*613a2f6bSGordon Ross /* 171*613a2f6bSGordon Ross * This may have been an open, so save the 172*613a2f6bSGordon Ross * generation ID of the share, which we 173*613a2f6bSGordon Ross * check before trying read or write. 174*613a2f6bSGordon Ross */ 175*613a2f6bSGordon Ross sdp->sd_vcgenid = ssp->ss_vcgenid; 176*613a2f6bSGordon Ross 177*613a2f6bSGordon Ross /* 178*613a2f6bSGordon Ross * Have reply data. to copyout. 179*613a2f6bSGordon Ross * SMB header already parsed. 180*613a2f6bSGordon Ross */ 181*613a2f6bSGordon Ross mdp = &rqp->sr_rp; 182*613a2f6bSGordon Ross rsz = msgdsize(mdp->md_top) - SMB_HDRLEN; 183*613a2f6bSGordon Ross if (ioc->ioc_rbufsz < rsz) { 184*613a2f6bSGordon Ross err = EOVERFLOW; 185*613a2f6bSGordon Ross goto out; 186*613a2f6bSGordon Ross } 187*613a2f6bSGordon Ross ioc->ioc_rbufsz = rsz; 188*613a2f6bSGordon Ross err = md_get_mem(mdp, ioc->ioc_rbuf, rsz, mbseg); 189*613a2f6bSGordon Ross if (err) 190*613a2f6bSGordon Ross goto out; 191*613a2f6bSGordon Ross 1924bff34e3Sthurlow } 1934bff34e3Sthurlow 194*613a2f6bSGordon Ross ioc->ioc_errclass = rqp->sr_errclass; 195*613a2f6bSGordon Ross ioc->ioc_serror = rqp->sr_serror; 196*613a2f6bSGordon Ross ioc->ioc_error = rqp->sr_error; 197*613a2f6bSGordon Ross ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags); 1984bff34e3Sthurlow 199*613a2f6bSGordon Ross out: 200*613a2f6bSGordon Ross if (rqp != NULL) 201*613a2f6bSGordon Ross smb_rq_done(rqp); /* free rqp */ 202*613a2f6bSGordon Ross if (ioc != NULL) 203*613a2f6bSGordon Ross kmem_free(ioc, sizeof (*ioc)); 204*613a2f6bSGordon Ross smb_credrele(&scred); 205*613a2f6bSGordon Ross 206*613a2f6bSGordon Ross return (err); 2074bff34e3Sthurlow 2084bff34e3Sthurlow } 2094bff34e3Sthurlow 210*613a2f6bSGordon Ross /* 211*613a2f6bSGordon Ross * Ioctl function for SMBIOC_T2RQ 212*613a2f6bSGordon Ross */ 213*613a2f6bSGordon Ross int 214*613a2f6bSGordon Ross smb_usr_t2request(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr) 2154bff34e3Sthurlow { 216*613a2f6bSGordon Ross struct smb_cred scred; 217*613a2f6bSGordon Ross struct smb_share *ssp; 218*613a2f6bSGordon Ross smbioc_t2rq_t *ioc = NULL; 219*613a2f6bSGordon Ross struct smb_t2rq *t2p = NULL; 220*613a2f6bSGordon Ross struct mdchain *mdp; 221*613a2f6bSGordon Ross int err, len, mbseg; 222*613a2f6bSGordon Ross 223*613a2f6bSGordon Ross /* This ioctl requires a share. */ 224*613a2f6bSGordon Ross if ((ssp = sdp->sd_share) == NULL) 225*613a2f6bSGordon Ross return (ENOTCONN); 2264bff34e3Sthurlow 227*613a2f6bSGordon Ross smb_credinit(&scred, cr); 228*613a2f6bSGordon Ross ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP); 229*613a2f6bSGordon Ross if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) { 230*613a2f6bSGordon Ross err = EFAULT; 231*613a2f6bSGordon Ross goto out; 2324bff34e3Sthurlow } 233*613a2f6bSGordon Ross 234*613a2f6bSGordon Ross /* See ddi_copyin, ddi_copyout */ 235*613a2f6bSGordon Ross mbseg = (flags & FKIOCTL) ? MB_MSYSTEM : MB_MUSER; 236*613a2f6bSGordon Ross 237*613a2f6bSGordon Ross if (ioc->ioc_setupcnt > SMBIOC_T2RQ_MAXSETUP) { 238*613a2f6bSGordon Ross err = EINVAL; 239*613a2f6bSGordon Ross goto out; 240*613a2f6bSGordon Ross } 241*613a2f6bSGordon Ross 242*613a2f6bSGordon Ross t2p = kmem_alloc(sizeof (*t2p), KM_SLEEP); 243*613a2f6bSGordon Ross err = smb_t2_init(t2p, SSTOCP(ssp), 244*613a2f6bSGordon Ross ioc->ioc_setup, ioc->ioc_setupcnt, &scred); 245*613a2f6bSGordon Ross if (err) 246*613a2f6bSGordon Ross goto out; 247*613a2f6bSGordon Ross len = t2p->t2_setupcount = ioc->ioc_setupcnt; 248*613a2f6bSGordon Ross if (len > 1) 249*613a2f6bSGordon Ross t2p->t2_setupdata = ioc->ioc_setup; 250*613a2f6bSGordon Ross 251*613a2f6bSGordon Ross /* This ioc member is a fixed-size array. */ 252*613a2f6bSGordon Ross if (ioc->ioc_name[0]) { 253*613a2f6bSGordon Ross /* Get the name length - carefully! */ 254*613a2f6bSGordon Ross ioc->ioc_name[SMBIOC_T2RQ_MAXNAME-1] = '\0'; 255*613a2f6bSGordon Ross t2p->t_name_len = strlen(ioc->ioc_name); 256*613a2f6bSGordon Ross t2p->t_name = ioc->ioc_name; 257*613a2f6bSGordon Ross } 258*613a2f6bSGordon Ross t2p->t2_maxscount = 0; 259*613a2f6bSGordon Ross t2p->t2_maxpcount = ioc->ioc_rparamcnt; 260*613a2f6bSGordon Ross t2p->t2_maxdcount = ioc->ioc_rdatacnt; 261*613a2f6bSGordon Ross 262*613a2f6bSGordon Ross /* Transmit parameters */ 263*613a2f6bSGordon Ross err = smb_cpdatain(&t2p->t2_tparam, 264*613a2f6bSGordon Ross ioc->ioc_tparamcnt, ioc->ioc_tparam, mbseg); 265*613a2f6bSGordon Ross if (err) 266*613a2f6bSGordon Ross goto out; 267*613a2f6bSGordon Ross 268*613a2f6bSGordon Ross /* Transmit data */ 269*613a2f6bSGordon Ross err = smb_cpdatain(&t2p->t2_tdata, 270*613a2f6bSGordon Ross ioc->ioc_tdatacnt, ioc->ioc_tdata, mbseg); 271*613a2f6bSGordon Ross if (err) 272*613a2f6bSGordon Ross goto out; 273*613a2f6bSGordon Ross 274*613a2f6bSGordon Ross err = smb_t2_request(t2p); 275*613a2f6bSGordon Ross 276*613a2f6bSGordon Ross /* Copyout returned parameters. */ 277*613a2f6bSGordon Ross mdp = &t2p->t2_rparam; 278*613a2f6bSGordon Ross if (err == 0 && mdp->md_top != NULL) { 279*613a2f6bSGordon Ross /* User's buffer large enough? */ 280*613a2f6bSGordon Ross len = m_fixhdr(mdp->md_top); 281*613a2f6bSGordon Ross if (len > ioc->ioc_rparamcnt) { 282*613a2f6bSGordon Ross err = EMSGSIZE; 283*613a2f6bSGordon Ross goto out; 284*613a2f6bSGordon Ross } 285*613a2f6bSGordon Ross ioc->ioc_rparamcnt = (ushort_t)len; 286*613a2f6bSGordon Ross err = md_get_mem(mdp, ioc->ioc_rparam, len, mbseg); 287*613a2f6bSGordon Ross if (err) 288*613a2f6bSGordon Ross goto out; 289*613a2f6bSGordon Ross } else 290*613a2f6bSGordon Ross ioc->ioc_rparamcnt = 0; 291*613a2f6bSGordon Ross 292*613a2f6bSGordon Ross /* Copyout returned data. */ 293*613a2f6bSGordon Ross mdp = &t2p->t2_rdata; 294*613a2f6bSGordon Ross if (err == 0 && mdp->md_top != NULL) { 295*613a2f6bSGordon Ross /* User's buffer large enough? */ 296*613a2f6bSGordon Ross len = m_fixhdr(mdp->md_top); 297*613a2f6bSGordon Ross if (len > ioc->ioc_rdatacnt) { 298*613a2f6bSGordon Ross err = EMSGSIZE; 299*613a2f6bSGordon Ross goto out; 300*613a2f6bSGordon Ross } 301*613a2f6bSGordon Ross ioc->ioc_rdatacnt = (ushort_t)len; 302*613a2f6bSGordon Ross err = md_get_mem(mdp, ioc->ioc_rdata, len, mbseg); 303*613a2f6bSGordon Ross if (err) 304*613a2f6bSGordon Ross goto out; 305*613a2f6bSGordon Ross } else 306*613a2f6bSGordon Ross ioc->ioc_rdatacnt = 0; 307*613a2f6bSGordon Ross 308*613a2f6bSGordon Ross ioc->ioc_errclass = t2p->t2_sr_errclass; 309*613a2f6bSGordon Ross ioc->ioc_serror = t2p->t2_sr_serror; 310*613a2f6bSGordon Ross ioc->ioc_error = t2p->t2_sr_error; 311*613a2f6bSGordon Ross ioc->ioc_rpflags2 = t2p->t2_sr_rpflags2; 312*613a2f6bSGordon Ross 313*613a2f6bSGordon Ross ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags); 314*613a2f6bSGordon Ross 315*613a2f6bSGordon Ross 316*613a2f6bSGordon Ross out: 317*613a2f6bSGordon Ross if (t2p != NULL) { 318*613a2f6bSGordon Ross /* Note: t2p->t_name no longer allocated */ 319*613a2f6bSGordon Ross smb_t2_done(t2p); 320*613a2f6bSGordon Ross kmem_free(t2p, sizeof (*t2p)); 321*613a2f6bSGordon Ross } 322*613a2f6bSGordon Ross if (ioc != NULL) 323*613a2f6bSGordon Ross kmem_free(ioc, sizeof (*ioc)); 324*613a2f6bSGordon Ross smb_credrele(&scred); 325*613a2f6bSGordon Ross 326*613a2f6bSGordon Ross return (err); 3274bff34e3Sthurlow } 3284bff34e3Sthurlow 329*613a2f6bSGordon Ross /* helper for _t2request */ 3304bff34e3Sthurlow static int 331*613a2f6bSGordon Ross smb_cpdatain(struct mbchain *mbp, int len, char *data, int mbseg) 3324bff34e3Sthurlow { 333*613a2f6bSGordon Ross int error; 334*613a2f6bSGordon Ross 335*613a2f6bSGordon Ross if (len == 0) 336*613a2f6bSGordon Ross return (0); 337*613a2f6bSGordon Ross error = mb_init(mbp); 338*613a2f6bSGordon Ross if (error) 339*613a2f6bSGordon Ross return (error); 340*613a2f6bSGordon Ross return (mb_put_mem(mbp, data, len, mbseg)); 3414bff34e3Sthurlow } 3424bff34e3Sthurlow 343*613a2f6bSGordon Ross /* 344*613a2f6bSGordon Ross * Helper for nsmb_ioctl cases 345*613a2f6bSGordon Ross * SMBIOC_READ, SMBIOC_WRITE 346*613a2f6bSGordon Ross */ 3471b34bc4aSbs int 348*613a2f6bSGordon Ross smb_usr_rw(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr) 3491b34bc4aSbs { 350*613a2f6bSGordon Ross struct smb_cred scred; 351*613a2f6bSGordon Ross struct smb_share *ssp; 352*613a2f6bSGordon Ross smbioc_rw_t *ioc = NULL; 353*613a2f6bSGordon Ross struct iovec aiov[1]; 354*613a2f6bSGordon Ross struct uio auio; 355*613a2f6bSGordon Ross u_int16_t fh; 356*613a2f6bSGordon Ross int err; 357*613a2f6bSGordon Ross uio_rw_t rw; 3581b34bc4aSbs 359*613a2f6bSGordon Ross /* This ioctl requires a share. */ 360*613a2f6bSGordon Ross if ((ssp = sdp->sd_share) == NULL) 361*613a2f6bSGordon Ross return (ENOTCONN); 362*613a2f6bSGordon Ross 363*613a2f6bSGordon Ross /* After reconnect, force close+reopen */ 364*613a2f6bSGordon Ross if (sdp->sd_vcgenid != ssp->ss_vcgenid) 365*613a2f6bSGordon Ross return (ESTALE); 366*613a2f6bSGordon Ross 367*613a2f6bSGordon Ross smb_credinit(&scred, cr); 368*613a2f6bSGordon Ross ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP); 369*613a2f6bSGordon Ross if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) { 370*613a2f6bSGordon Ross err = EFAULT; 3711b34bc4aSbs goto out; 372*613a2f6bSGordon Ross } 373*613a2f6bSGordon Ross 374*613a2f6bSGordon Ross switch (cmd) { 375*613a2f6bSGordon Ross case SMBIOC_READ: 376*613a2f6bSGordon Ross rw = UIO_READ; 377*613a2f6bSGordon Ross break; 378*613a2f6bSGordon Ross case SMBIOC_WRITE: 379*613a2f6bSGordon Ross rw = UIO_WRITE; 380*613a2f6bSGordon Ross break; 381*613a2f6bSGordon Ross default: 382*613a2f6bSGordon Ross err = ENODEV; 383*613a2f6bSGordon Ross goto out; 384*613a2f6bSGordon Ross } 385*613a2f6bSGordon Ross 386*613a2f6bSGordon Ross fh = ioc->ioc_fh; 387*613a2f6bSGordon Ross 388*613a2f6bSGordon Ross aiov[0].iov_base = ioc->ioc_base; 389*613a2f6bSGordon Ross aiov[0].iov_len = (size_t)ioc->ioc_cnt; 390*613a2f6bSGordon Ross 391*613a2f6bSGordon Ross auio.uio_iov = aiov; 392*613a2f6bSGordon Ross auio.uio_iovcnt = 1; 393*613a2f6bSGordon Ross auio.uio_loffset = ioc->ioc_offset; 394*613a2f6bSGordon Ross auio.uio_segflg = (flags & FKIOCTL) ? 395*613a2f6bSGordon Ross UIO_SYSSPACE : UIO_USERSPACE; 396*613a2f6bSGordon Ross auio.uio_fmode = 0; 397*613a2f6bSGordon Ross auio.uio_resid = (size_t)ioc->ioc_cnt; 398*613a2f6bSGordon Ross 399*613a2f6bSGordon Ross err = smb_rwuio(ssp, fh, rw, &auio, &scred, 0); 400*613a2f6bSGordon Ross 401*613a2f6bSGordon Ross /* 402*613a2f6bSGordon Ross * On return ioc_cnt holds the 403*613a2f6bSGordon Ross * number of bytes transferred. 404*613a2f6bSGordon Ross */ 405*613a2f6bSGordon Ross ioc->ioc_cnt -= auio.uio_resid; 406*613a2f6bSGordon Ross 407*613a2f6bSGordon Ross ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags); 408*613a2f6bSGordon Ross 4091b34bc4aSbs out: 410*613a2f6bSGordon Ross if (ioc != NULL) 411*613a2f6bSGordon Ross kmem_free(ioc, sizeof (*ioc)); 412*613a2f6bSGordon Ross smb_credrele(&scred); 413*613a2f6bSGordon Ross 414*613a2f6bSGordon Ross return (err); 4151b34bc4aSbs } 4161b34bc4aSbs 417*613a2f6bSGordon Ross /* 418*613a2f6bSGordon Ross * Ioctl functions: SMBIOC_SSN_FIND, SMBIOC_SSN_CREATE 419*613a2f6bSGordon Ross * Find or create a session (a.k.a. "VC" in here) 420*613a2f6bSGordon Ross */ 4214bff34e3Sthurlow int 422*613a2f6bSGordon Ross smb_usr_get_ssn(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr) 4234bff34e3Sthurlow { 424*613a2f6bSGordon Ross struct smb_cred scred; 425*613a2f6bSGordon Ross smbioc_ossn_t *ossn = NULL; 4264bff34e3Sthurlow struct smb_vc *vcp = NULL; 4274bff34e3Sthurlow int error = 0; 428*613a2f6bSGordon Ross uid_t realuid; 4294bff34e3Sthurlow 430*613a2f6bSGordon Ross /* Should be no VC */ 431*613a2f6bSGordon Ross if (sdp->sd_vc != NULL) 432*613a2f6bSGordon Ross return (EISCONN); 433*613a2f6bSGordon Ross 434*613a2f6bSGordon Ross smb_credinit(&scred, cr); 435*613a2f6bSGordon Ross ossn = kmem_alloc(sizeof (*ossn), KM_SLEEP); 436*613a2f6bSGordon Ross if (ddi_copyin((void *)arg, ossn, sizeof (*ossn), flags)) { 437*613a2f6bSGordon Ross error = EFAULT; 438*613a2f6bSGordon Ross goto out; 4394bff34e3Sthurlow } 440*613a2f6bSGordon Ross 441*613a2f6bSGordon Ross /* 442*613a2f6bSGordon Ross * Only superuser can specify a UID or GID. 443*613a2f6bSGordon Ross */ 444*613a2f6bSGordon Ross realuid = crgetruid(cr); 445*613a2f6bSGordon Ross if (ossn->ssn_owner == SMBM_ANY_OWNER) 446*613a2f6bSGordon Ross ossn->ssn_owner = realuid; 447*613a2f6bSGordon Ross else { 4484bff34e3Sthurlow /* 449*613a2f6bSGordon Ross * Do we have the privilege to create with the 450*613a2f6bSGordon Ross * specified uid? (does uid == cr->cr_uid, etc.) 4514bff34e3Sthurlow */ 452*613a2f6bSGordon Ross if (secpolicy_vnode_owner(cr, ossn->ssn_owner)) { 453*613a2f6bSGordon Ross error = EPERM; 454*613a2f6bSGordon Ross goto out; 4554bff34e3Sthurlow } 456*613a2f6bSGordon Ross /* ossn->ssn_owner is OK */ 4574bff34e3Sthurlow } 4584bff34e3Sthurlow 459*613a2f6bSGordon Ross /* 460*613a2f6bSGordon Ross * Make sure the strings are null terminated. 461*613a2f6bSGordon Ross */ 462*613a2f6bSGordon Ross ossn->ssn_srvname[SMBIOC_MAX_NAME-1] = '\0'; 463*613a2f6bSGordon Ross ossn->ssn_id.id_domain[ SMBIOC_MAX_NAME-1] = '\0'; 464*613a2f6bSGordon Ross ossn->ssn_id.id_user[ SMBIOC_MAX_NAME-1] = '\0'; 4654bff34e3Sthurlow 466*613a2f6bSGordon Ross if (cmd == SMBIOC_SSN_CREATE) 467*613a2f6bSGordon Ross ossn->ssn_vopt |= SMBVOPT_CREATE; 468*613a2f6bSGordon Ross else /* FIND */ 469*613a2f6bSGordon Ross ossn->ssn_vopt &= ~SMBVOPT_CREATE; 4704bff34e3Sthurlow 471*613a2f6bSGordon Ross error = smb_vc_findcreate(ossn, &scred, &vcp); 4724bff34e3Sthurlow if (error) 4734bff34e3Sthurlow goto out; 474*613a2f6bSGordon Ross ASSERT(vcp != NULL); 4754bff34e3Sthurlow 4764bff34e3Sthurlow /* 477*613a2f6bSGordon Ross * We have a VC, held, but not locked. 478*613a2f6bSGordon Ross * If we're creating, mark this instance as 479*613a2f6bSGordon Ross * an open from IOD so close can do cleanup. 480*613a2f6bSGordon Ross * 481*613a2f6bSGordon Ross * XXX: Would be nice to have a back pointer 482*613a2f6bSGordon Ross * from the VC to this (IOD) sdp instance. 4834bff34e3Sthurlow */ 484*613a2f6bSGordon Ross if (cmd == SMBIOC_SSN_CREATE) { 485*613a2f6bSGordon Ross if (vcp->iod_thr != NULL) { 486*613a2f6bSGordon Ross error = EEXIST; 487*613a2f6bSGordon Ross goto out; 488*613a2f6bSGordon Ross } 489*613a2f6bSGordon Ross sdp->sd_flags |= NSMBFL_IOD; 490*613a2f6bSGordon Ross } else { 491*613a2f6bSGordon Ross /* 492*613a2f6bSGordon Ross * Wait for it to finish connecting 493*613a2f6bSGordon Ross * (or reconnect) if necessary. 494*613a2f6bSGordon Ross */ 495*613a2f6bSGordon Ross if (vcp->vc_state != SMBIOD_ST_VCACTIVE) { 496*613a2f6bSGordon Ross error = smb_iod_reconnect(vcp); 497*613a2f6bSGordon Ross if (error != 0) 498*613a2f6bSGordon Ross goto out; 499*613a2f6bSGordon Ross } 500*613a2f6bSGordon Ross } 501*613a2f6bSGordon Ross 502*613a2f6bSGordon Ross /* 503*613a2f6bSGordon Ross * The VC has a hold from _findvc 504*613a2f6bSGordon Ross * which we keep until _SSN_RELE 505*613a2f6bSGordon Ross * or nsmb_close(). 506*613a2f6bSGordon Ross */ 507*613a2f6bSGordon Ross sdp->sd_level = SMBL_VC; 508*613a2f6bSGordon Ross sdp->sd_vc = vcp; 509*613a2f6bSGordon Ross vcp = NULL; 510*613a2f6bSGordon Ross (void) ddi_copyout(ossn, (void *)arg, sizeof (*ossn), flags); 5114bff34e3Sthurlow 5124bff34e3Sthurlow out: 513*613a2f6bSGordon Ross if (vcp) { 514*613a2f6bSGordon Ross /* Error path: rele hold from _findcreate */ 515*613a2f6bSGordon Ross smb_vc_rele(vcp); 516*613a2f6bSGordon Ross } 517*613a2f6bSGordon Ross if (ossn != NULL) 518*613a2f6bSGordon Ross kmem_free(ossn, sizeof (*ossn)); 519*613a2f6bSGordon Ross smb_credrele(&scred); 520*613a2f6bSGordon Ross 5214bff34e3Sthurlow return (error); 5224bff34e3Sthurlow } 5234bff34e3Sthurlow 524*613a2f6bSGordon Ross /* 525*613a2f6bSGordon Ross * Ioctl functions: SMBIOC_SSN_RELE, SMBIOC_SSN_KILL 526*613a2f6bSGordon Ross * Release or kill the current session. 527*613a2f6bSGordon Ross */ 5284bff34e3Sthurlow int 529*613a2f6bSGordon Ross smb_usr_drop_ssn(smb_dev_t *sdp, int cmd) 5304bff34e3Sthurlow { 531*613a2f6bSGordon Ross struct smb_vc *vcp = NULL; 5324bff34e3Sthurlow 533*613a2f6bSGordon Ross /* Must have a VC. */ 534*613a2f6bSGordon Ross if ((vcp = sdp->sd_vc) == NULL) 535*613a2f6bSGordon Ross return (ENOTCONN); 5364bff34e3Sthurlow 537*613a2f6bSGordon Ross /* If we have a share ref, drop it too. */ 538*613a2f6bSGordon Ross if (sdp->sd_share) { 539*613a2f6bSGordon Ross smb_share_rele(sdp->sd_share); 540*613a2f6bSGordon Ross sdp->sd_share = NULL; 541*613a2f6bSGordon Ross sdp->sd_level = SMBL_VC; 5424bff34e3Sthurlow } 5434bff34e3Sthurlow 544*613a2f6bSGordon Ross if (cmd == SMBIOC_SSN_KILL) 545*613a2f6bSGordon Ross smb_vc_kill(vcp); 5464bff34e3Sthurlow 547*613a2f6bSGordon Ross /* Drop the VC ref. */ 548*613a2f6bSGordon Ross smb_vc_rele(vcp); 549*613a2f6bSGordon Ross sdp->sd_vc = NULL; 550*613a2f6bSGordon Ross sdp->sd_level = 0; 551*613a2f6bSGordon Ross 552*613a2f6bSGordon Ross return (0); 5534bff34e3Sthurlow } 5544bff34e3Sthurlow 5554bff34e3Sthurlow /* 556*613a2f6bSGordon Ross * Find or create a tree (connected share) 5574bff34e3Sthurlow */ 5584bff34e3Sthurlow int 559*613a2f6bSGordon Ross smb_usr_get_tree(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr) 5604bff34e3Sthurlow { 561*613a2f6bSGordon Ross struct smb_cred scred; 562*613a2f6bSGordon Ross smbioc_tcon_t *tcon = NULL; 563*613a2f6bSGordon Ross struct smb_vc *vcp = NULL; 564*613a2f6bSGordon Ross struct smb_share *ssp = NULL; 565*613a2f6bSGordon Ross int error = 0; 5664bff34e3Sthurlow 567*613a2f6bSGordon Ross /* Must have a VC. */ 568*613a2f6bSGordon Ross if ((vcp = sdp->sd_vc) == NULL) 569*613a2f6bSGordon Ross return (ENOTCONN); 570*613a2f6bSGordon Ross /* Should not have a share. */ 571*613a2f6bSGordon Ross if (sdp->sd_share != NULL) 572*613a2f6bSGordon Ross return (EISCONN); 573*613a2f6bSGordon Ross 574*613a2f6bSGordon Ross smb_credinit(&scred, cr); 575*613a2f6bSGordon Ross tcon = kmem_alloc(sizeof (*tcon), KM_SLEEP); 576*613a2f6bSGordon Ross if (ddi_copyin((void *)arg, tcon, sizeof (*tcon), flags)) { 577*613a2f6bSGordon Ross error = EFAULT; 578*613a2f6bSGordon Ross goto out; 5794bff34e3Sthurlow } 580*613a2f6bSGordon Ross 581*613a2f6bSGordon Ross /* 582*613a2f6bSGordon Ross * Make sure the strings are null terminated. 583*613a2f6bSGordon Ross */ 584*613a2f6bSGordon Ross tcon->tc_sh.sh_name[SMBIOC_MAX_NAME-1] = '\0'; 585*613a2f6bSGordon Ross tcon->tc_sh.sh_pass[SMBIOC_MAX_NAME-1] = '\0'; 586*613a2f6bSGordon Ross tcon->tc_sh.sh_type_req[SMBIOC_STYPE_LEN-1] = '\0'; 587*613a2f6bSGordon Ross bzero(tcon->tc_sh.sh_type_ret, SMBIOC_STYPE_LEN); 588*613a2f6bSGordon Ross 589*613a2f6bSGordon Ross if (cmd == SMBIOC_TREE_CONNECT) 590*613a2f6bSGordon Ross tcon->tc_opt |= SMBSOPT_CREATE; 591*613a2f6bSGordon Ross else /* FIND */ 592*613a2f6bSGordon Ross tcon->tc_opt &= ~SMBSOPT_CREATE; 593*613a2f6bSGordon Ross 594*613a2f6bSGordon Ross error = smb_share_findcreate(tcon, vcp, &ssp, &scred); 5954bff34e3Sthurlow if (error) 596*613a2f6bSGordon Ross goto out; 597*613a2f6bSGordon Ross ASSERT(ssp != NULL); 598*613a2f6bSGordon Ross 599*613a2f6bSGordon Ross /* 600*613a2f6bSGordon Ross * We have a share, held, but not locked. 601*613a2f6bSGordon Ross * If we're creating, do tree connect now, 602*613a2f6bSGordon Ross * otherwise let that wait for a request. 603*613a2f6bSGordon Ross */ 604*613a2f6bSGordon Ross if (cmd == SMBIOC_TREE_CONNECT) { 605*613a2f6bSGordon Ross error = smb_share_tcon(ssp, &scred); 606*613a2f6bSGordon Ross if (error) 607*613a2f6bSGordon Ross goto out; 6084bff34e3Sthurlow } 609*613a2f6bSGordon Ross 610*613a2f6bSGordon Ross /* 611*613a2f6bSGordon Ross * Give caller the real share type from 612*613a2f6bSGordon Ross * the tree connect response, so they can 613*613a2f6bSGordon Ross * see if they got the requested type. 614*613a2f6bSGordon Ross */ 615*613a2f6bSGordon Ross memcpy(tcon->tc_sh.sh_type_ret, 616*613a2f6bSGordon Ross ssp->ss_type_ret, SMBIOC_STYPE_LEN); 617*613a2f6bSGordon Ross 618*613a2f6bSGordon Ross /* 619*613a2f6bSGordon Ross * The share has a hold from _tcon 620*613a2f6bSGordon Ross * which we keep until nsmb_close() 621*613a2f6bSGordon Ross * or the SMBIOC_TDIS below. 622*613a2f6bSGordon Ross */ 623*613a2f6bSGordon Ross sdp->sd_level = SMBL_SHARE; 624*613a2f6bSGordon Ross sdp->sd_share = ssp; 625*613a2f6bSGordon Ross ssp = NULL; 626*613a2f6bSGordon Ross (void) ddi_copyout(tcon, (void *)arg, sizeof (*tcon), flags); 627*613a2f6bSGordon Ross 628*613a2f6bSGordon Ross out: 629*613a2f6bSGordon Ross if (ssp) { 630*613a2f6bSGordon Ross /* Error path: rele hold from _findcreate */ 631*613a2f6bSGordon Ross smb_share_rele(ssp); 6324bff34e3Sthurlow } 633*613a2f6bSGordon Ross if (tcon) { 634*613a2f6bSGordon Ross /* 635*613a2f6bSGordon Ross * This structure may contain a 636*613a2f6bSGordon Ross * cleartext password, so zap it. 637*613a2f6bSGordon Ross */ 638*613a2f6bSGordon Ross bzero(tcon, sizeof (*tcon)); 639*613a2f6bSGordon Ross kmem_free(tcon, sizeof (*tcon)); 640*613a2f6bSGordon Ross } 641*613a2f6bSGordon Ross smb_credrele(&scred); 6424bff34e3Sthurlow 643*613a2f6bSGordon Ross return (error); 6444bff34e3Sthurlow } 6454bff34e3Sthurlow 646*613a2f6bSGordon Ross /* 647*613a2f6bSGordon Ross * Ioctl functions: SMBIOC_TREE_RELE, SMBIOC_TREE_KILL 648*613a2f6bSGordon Ross * Release or kill the current tree 649*613a2f6bSGordon Ross */ 650*613a2f6bSGordon Ross int 651*613a2f6bSGordon Ross smb_usr_drop_tree(smb_dev_t *sdp, int cmd) 6524bff34e3Sthurlow { 653*613a2f6bSGordon Ross struct smb_share *ssp = NULL; 6544bff34e3Sthurlow 655*613a2f6bSGordon Ross /* Must have a VC and a share. */ 656*613a2f6bSGordon Ross if (sdp->sd_vc == NULL) 657*613a2f6bSGordon Ross return (ENOTCONN); 658*613a2f6bSGordon Ross if ((ssp = sdp->sd_share) == NULL) 659*613a2f6bSGordon Ross return (ENOTCONN); 660*613a2f6bSGordon Ross 661*613a2f6bSGordon Ross if (cmd == SMBIOC_TREE_KILL) 662*613a2f6bSGordon Ross smb_share_kill(ssp); 663*613a2f6bSGordon Ross 664*613a2f6bSGordon Ross /* Drop the share ref. */ 665*613a2f6bSGordon Ross smb_share_rele(sdp->sd_share); 666*613a2f6bSGordon Ross sdp->sd_share = NULL; 667*613a2f6bSGordon Ross sdp->sd_level = SMBL_VC; 668*613a2f6bSGordon Ross 669*613a2f6bSGordon Ross return (0); 6704bff34e3Sthurlow } 6714bff34e3Sthurlow 672*613a2f6bSGordon Ross 673*613a2f6bSGordon Ross /* 674*613a2f6bSGordon Ross * Ioctl function: SMBIOC_IOD_WORK 675*613a2f6bSGordon Ross * 676*613a2f6bSGordon Ross * Become the reader (IOD) thread, until either the connection is 677*613a2f6bSGordon Ross * reset by the server, or until the connection is idle longer than 678*613a2f6bSGordon Ross * some max time. (max idle time not yet implemented) 679*613a2f6bSGordon Ross */ 6804bff34e3Sthurlow int 681*613a2f6bSGordon Ross smb_usr_iod_work(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr) 6824bff34e3Sthurlow { 683*613a2f6bSGordon Ross struct smb_vc *vcp = NULL; 684*613a2f6bSGordon Ross int err = 0; 6854bff34e3Sthurlow 686*613a2f6bSGordon Ross /* Must have a valid session. */ 687*613a2f6bSGordon Ross if ((vcp = sdp->sd_vc) == NULL) 6884bff34e3Sthurlow return (EINVAL); 689*613a2f6bSGordon Ross if (vcp->vc_flags & SMBV_GONE) 690*613a2f6bSGordon Ross return (EINVAL); 691*613a2f6bSGordon Ross 692*613a2f6bSGordon Ross /* 693*613a2f6bSGordon Ross * Is there already an IOD for this VC? 694*613a2f6bSGordon Ross * (Should never happen.) 695*613a2f6bSGordon Ross */ 696*613a2f6bSGordon Ross SMB_VC_LOCK(vcp); 697*613a2f6bSGordon Ross if (vcp->iod_thr == NULL) 698*613a2f6bSGordon Ross vcp->iod_thr = curthread; 699*613a2f6bSGordon Ross else 700*613a2f6bSGordon Ross err = EEXIST; 701*613a2f6bSGordon Ross SMB_VC_UNLOCK(vcp); 702*613a2f6bSGordon Ross if (err) 703*613a2f6bSGordon Ross return (err); 704*613a2f6bSGordon Ross 705*613a2f6bSGordon Ross /* 706*613a2f6bSGordon Ross * Copy the "work" state, etc. into the VC 707*613a2f6bSGordon Ross * The MAC key is copied separately. 708*613a2f6bSGordon Ross */ 709*613a2f6bSGordon Ross if (ddi_copyin((void *)arg, &vcp->vc_work, 710*613a2f6bSGordon Ross sizeof (smbioc_ssn_work_t), flags)) { 711*613a2f6bSGordon Ross err = EFAULT; 712*613a2f6bSGordon Ross goto out; 7134bff34e3Sthurlow } 714*613a2f6bSGordon Ross if (vcp->vc_u_maclen) { 715*613a2f6bSGordon Ross vcp->vc_mackeylen = vcp->vc_u_maclen; 716*613a2f6bSGordon Ross vcp->vc_mackey = kmem_alloc(vcp->vc_mackeylen, KM_SLEEP); 717*613a2f6bSGordon Ross if (ddi_copyin(vcp->vc_u_mackey.lp_ptr, vcp->vc_mackey, 718*613a2f6bSGordon Ross vcp->vc_mackeylen, flags)) { 719*613a2f6bSGordon Ross err = EFAULT; 720*613a2f6bSGordon Ross goto out; 7214bff34e3Sthurlow } 7229c9af259SGordon Ross } 723*613a2f6bSGordon Ross 724*613a2f6bSGordon Ross err = smb_iod_vc_work(vcp, cr); 725*613a2f6bSGordon Ross 726*613a2f6bSGordon Ross /* Caller wants state here. */ 727*613a2f6bSGordon Ross vcp->vc_work.wk_out_state = vcp->vc_state; 728*613a2f6bSGordon Ross 729*613a2f6bSGordon Ross (void) ddi_copyout(&vcp->vc_work, (void *)arg, 730*613a2f6bSGordon Ross sizeof (smbioc_ssn_work_t), flags); 731*613a2f6bSGordon Ross 732*613a2f6bSGordon Ross out: 733*613a2f6bSGordon Ross if (vcp->vc_mackey) { 734*613a2f6bSGordon Ross kmem_free(vcp->vc_mackey, vcp->vc_mackeylen); 735*613a2f6bSGordon Ross vcp->vc_mackey = NULL; 736*613a2f6bSGordon Ross vcp->vc_mackeylen = 0; 737*613a2f6bSGordon Ross } 738*613a2f6bSGordon Ross 739*613a2f6bSGordon Ross /* 740*613a2f6bSGordon Ross * The IOD thread is leaving the driver. Clear iod_thr, 741*613a2f6bSGordon Ross * and wake up anybody waiting for us to quit. 742*613a2f6bSGordon Ross */ 743*613a2f6bSGordon Ross SMB_VC_LOCK(vcp); 744*613a2f6bSGordon Ross vcp->iod_thr = NULL; 745*613a2f6bSGordon Ross cv_broadcast(&vcp->vc_statechg); 746*613a2f6bSGordon Ross SMB_VC_UNLOCK(vcp); 747*613a2f6bSGordon Ross 748*613a2f6bSGordon Ross return (err); 7494bff34e3Sthurlow } 7504bff34e3Sthurlow 7514bff34e3Sthurlow /* 752*613a2f6bSGordon Ross * Ioctl functions: SMBIOC_IOD_IDLE, SMBIOC_IOD_RCFAIL 753*613a2f6bSGordon Ross * 754*613a2f6bSGordon Ross * Wait for user-level requests to be enqueued on this session, 755*613a2f6bSGordon Ross * and then return to the user-space helper, which will then 756*613a2f6bSGordon Ross * initiate a reconnect, etc. 7574bff34e3Sthurlow */ 7584bff34e3Sthurlow int 759*613a2f6bSGordon Ross smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags) 7604bff34e3Sthurlow { 761*613a2f6bSGordon Ross struct smb_vc *vcp = NULL; 762*613a2f6bSGordon Ross int err = 0; 763*613a2f6bSGordon Ross 764*613a2f6bSGordon Ross /* Must have a valid session. */ 765*613a2f6bSGordon Ross if ((vcp = sdp->sd_vc) == NULL) 766*613a2f6bSGordon Ross return (EINVAL); 767*613a2f6bSGordon Ross if (vcp->vc_flags & SMBV_GONE) 768*613a2f6bSGordon Ross return (EINVAL); 769*613a2f6bSGordon Ross 770*613a2f6bSGordon Ross /* 771*613a2f6bSGordon Ross * Is there already an IOD for this VC? 772*613a2f6bSGordon Ross * (Should never happen.) 773*613a2f6bSGordon Ross */ 774*613a2f6bSGordon Ross SMB_VC_LOCK(vcp); 775*613a2f6bSGordon Ross if (vcp->iod_thr == NULL) 776*613a2f6bSGordon Ross vcp->iod_thr = curthread; 777*613a2f6bSGordon Ross else 778*613a2f6bSGordon Ross err = EEXIST; 779*613a2f6bSGordon Ross SMB_VC_UNLOCK(vcp); 780*613a2f6bSGordon Ross if (err) 781*613a2f6bSGordon Ross return (err); 782*613a2f6bSGordon Ross 783*613a2f6bSGordon Ross /* nothing to copyin */ 7844bff34e3Sthurlow 7854bff34e3Sthurlow switch (cmd) { 786*613a2f6bSGordon Ross case SMBIOC_IOD_IDLE: 787*613a2f6bSGordon Ross err = smb_iod_vc_idle(vcp); 7884bff34e3Sthurlow break; 789*613a2f6bSGordon Ross 790*613a2f6bSGordon Ross case SMBIOC_IOD_RCFAIL: 791*613a2f6bSGordon Ross err = smb_iod_vc_rcfail(vcp); 7924bff34e3Sthurlow break; 793*613a2f6bSGordon Ross 7944bff34e3Sthurlow default: 795*613a2f6bSGordon Ross err = ENOTTY; 796*613a2f6bSGordon Ross goto out; 7974bff34e3Sthurlow } 7984bff34e3Sthurlow 799*613a2f6bSGordon Ross /* Both of these ioctls copy out the new state. */ 800*613a2f6bSGordon Ross (void) ddi_copyout(&vcp->vc_state, (void *)arg, 801*613a2f6bSGordon Ross sizeof (int), flags); 8024bff34e3Sthurlow 803*613a2f6bSGordon Ross out: 8044bff34e3Sthurlow /* 805*613a2f6bSGordon Ross * The IOD thread is leaving the driver. Clear iod_thr, 806*613a2f6bSGordon Ross * and wake up anybody waiting for us to quit. 8074bff34e3Sthurlow */ 808*613a2f6bSGordon Ross SMB_VC_LOCK(vcp); 809*613a2f6bSGordon Ross vcp->iod_thr = NULL; 810*613a2f6bSGordon Ross cv_broadcast(&vcp->vc_statechg); 811*613a2f6bSGordon Ross SMB_VC_UNLOCK(vcp); 8124bff34e3Sthurlow 813*613a2f6bSGordon Ross return (err); 8144bff34e3Sthurlow } 815