1139823Simp/*- 275374Sbp * Copyright (c) 2000-2001 Boris Popov 375374Sbp * All rights reserved. 475374Sbp * 575374Sbp * Redistribution and use in source and binary forms, with or without 675374Sbp * modification, are permitted provided that the following conditions 775374Sbp * are met: 875374Sbp * 1. Redistributions of source code must retain the above copyright 975374Sbp * notice, this list of conditions and the following disclaimer. 1075374Sbp * 2. Redistributions in binary form must reproduce the above copyright 1175374Sbp * notice, this list of conditions and the following disclaimer in the 1275374Sbp * documentation and/or other materials provided with the distribution. 1375374Sbp * 1475374Sbp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1575374Sbp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1675374Sbp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1775374Sbp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1875374Sbp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1975374Sbp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2075374Sbp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2175374Sbp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2275374Sbp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2375374Sbp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2475374Sbp * SUCH DAMAGE. 2575374Sbp */ 26116189Sobrien 27116189Sobrien#include <sys/cdefs.h> 28116189Sobrien__FBSDID("$FreeBSD$"); 29116189Sobrien 3075374Sbp#include <sys/param.h> 3175374Sbp#include <sys/kernel.h> 32129880Sphk#include <sys/module.h> 3375374Sbp#include <sys/systm.h> 3476166Smarkm#include <sys/conf.h> 3576166Smarkm#include <sys/fcntl.h> 3675374Sbp#include <sys/ioccom.h> 3776166Smarkm#include <sys/lock.h> 3875374Sbp#include <sys/malloc.h> 3976166Smarkm#include <sys/file.h> /* Must come after sys/malloc.h */ 40108524Salfred#include <sys/filedesc.h> 4175374Sbp#include <sys/mbuf.h> 4276166Smarkm#include <sys/poll.h> 4375374Sbp#include <sys/proc.h> 4476166Smarkm#include <sys/select.h> 4575374Sbp#include <sys/socket.h> 4675374Sbp#include <sys/socketvar.h> 4775374Sbp#include <sys/sysctl.h> 4876166Smarkm#include <sys/uio.h> 4975374Sbp#include <sys/vnode.h> 5075374Sbp 5175374Sbp#include <net/if.h> 5275374Sbp 5375374Sbp#include <netsmb/smb.h> 5475374Sbp#include <netsmb/smb_conn.h> 5575374Sbp#include <netsmb/smb_subr.h> 5675374Sbp#include <netsmb/smb_dev.h> 5775374Sbp 5875374Sbp#define SMB_GETDEV(dev) ((struct smb_dev*)(dev)->si_drv1) 5975374Sbp#define SMB_CHECKMINOR(dev) do { \ 6075374Sbp sdp = SMB_GETDEV(dev); \ 6175374Sbp if (sdp == NULL) return ENXIO; \ 6275374Sbp } while(0) 6375374Sbp 6475374Sbpstatic d_open_t nsmb_dev_open; 6575374Sbpstatic d_close_t nsmb_dev_close; 6675374Sbpstatic d_ioctl_t nsmb_dev_ioctl; 6775374Sbp 68120492SfjoeMODULE_DEPEND(netsmb, libiconv, 1, 1, 2); 6975374SbpMODULE_VERSION(netsmb, NSMB_VERSION); 7075374Sbp 7175374Sbpstatic int smb_version = NSMB_VERSION; 7275374Sbp 7375374Sbp 7475374SbpSYSCTL_DECL(_net_smb); 7575374SbpSYSCTL_INT(_net_smb, OID_AUTO, version, CTLFLAG_RD, &smb_version, 0, ""); 7675374Sbp 7775374Sbpstatic MALLOC_DEFINE(M_NSMBDEV, "NETSMBDEV", "NET/SMB device"); 7875374Sbp 7975374Sbp 8075374Sbp/* 8175374Sbpint smb_dev_queue(struct smb_dev *ndp, struct smb_rq *rqp, int prio); 8275374Sbp*/ 8375374Sbp 8475374Sbpstatic struct cdevsw nsmb_cdevsw = { 85126080Sphk .d_version = D_VERSION, 86184592Srwatson .d_flags = D_NEEDGIANT | D_NEEDMINOR, 87111815Sphk .d_open = nsmb_dev_open, 88111815Sphk .d_close = nsmb_dev_close, 89111815Sphk .d_ioctl = nsmb_dev_ioctl, 90125706Stjr .d_name = NSMB_NAME 9175374Sbp}; 9275374Sbp 93184592Srwatsonstatic eventhandler_tag nsmb_dev_tag; 94184592Srwatsonstatic struct clonedevs *nsmb_clones; 9575374Sbp 9675374Sbpstatic void 97148868Srwatsonnsmb_dev_clone(void *arg, struct ucred *cred, char *name, int namelen, 98148868Srwatson struct cdev **dev) 9975374Sbp{ 100184592Srwatson int i, u; 10175374Sbp 102130640Sphk if (*dev != NULL) 10375374Sbp return; 104184592Srwatson 105184592Srwatson if (strcmp(name, NSMB_NAME) == 0) 106184592Srwatson u = -1; 107184592Srwatson else if (dev_stdclone(name, NULL, NSMB_NAME, &u) != 1) 10875374Sbp return; 109184592Srwatson i = clone_create(&nsmb_clones, &nsmb_cdevsw, &u, dev, 0); 110184592Srwatson if (i) { 111184592Srwatson *dev = make_dev(&nsmb_cdevsw, u, UID_ROOT, GID_WHEEL, 0600, 112184592Srwatson "%s%d", NSMB_NAME, u); 113184592Srwatson if (*dev != NULL) { 114184592Srwatson dev_ref(*dev); 115184592Srwatson (*dev)->si_flags |= SI_CHEAPCLONE; 116184592Srwatson } 117184592Srwatson } 11875374Sbp} 11975374Sbp 12075374Sbpstatic int 121130585Sphknsmb_dev_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 12275374Sbp{ 12375374Sbp struct smb_dev *sdp; 12491406Sjhb struct ucred *cred = td->td_ucred; 12575374Sbp int s; 12675374Sbp 12775374Sbp sdp = SMB_GETDEV(dev); 12875374Sbp if (sdp && (sdp->sd_flags & NSMBFL_OPEN)) 12975374Sbp return EBUSY; 13075374Sbp if (sdp == NULL) { 131111119Simp sdp = malloc(sizeof(*sdp), M_NSMBDEV, M_WAITOK); 13275374Sbp dev->si_drv1 = (void*)sdp; 13375374Sbp } 13475374Sbp /* 13575374Sbp * XXX: this is just crazy - make a device for an already passed device... 13675374Sbp * someone should take care of it. 13775374Sbp */ 13875374Sbp if ((dev->si_flags & SI_NAMED) == 0) 139183397Sed make_dev(&nsmb_cdevsw, dev2unit(dev), cred->cr_uid, 140183397Sed cred->cr_gid, 0700, NSMB_NAME"%d", dev2unit(dev)); 14175374Sbp bzero(sdp, sizeof(*sdp)); 14275374Sbp/* 14375374Sbp STAILQ_INIT(&sdp->sd_rqlist); 14475374Sbp STAILQ_INIT(&sdp->sd_rplist); 14575374Sbp bzero(&sdp->sd_pollinfo, sizeof(struct selinfo)); 14675374Sbp*/ 14775374Sbp s = splimp(); 14875374Sbp sdp->sd_level = -1; 14975374Sbp sdp->sd_flags |= NSMBFL_OPEN; 15075374Sbp splx(s); 15175374Sbp return 0; 15275374Sbp} 15375374Sbp 15475374Sbpstatic int 155130585Sphknsmb_dev_close(struct cdev *dev, int flag, int fmt, struct thread *td) 15675374Sbp{ 15775374Sbp struct smb_dev *sdp; 15875374Sbp struct smb_vc *vcp; 15975374Sbp struct smb_share *ssp; 16075374Sbp struct smb_cred scred; 16175374Sbp int s; 16275374Sbp 16375374Sbp SMB_CHECKMINOR(dev); 16475374Sbp s = splimp(); 16575374Sbp if ((sdp->sd_flags & NSMBFL_OPEN) == 0) { 16675374Sbp splx(s); 16775374Sbp return EBADF; 16875374Sbp } 16987192Sbp smb_makescred(&scred, td, NULL); 17075374Sbp ssp = sdp->sd_share; 17175374Sbp if (ssp != NULL) 17275374Sbp smb_share_rele(ssp, &scred); 17375374Sbp vcp = sdp->sd_vc; 17475374Sbp if (vcp != NULL) 17575374Sbp smb_vc_rele(vcp, &scred); 17675374Sbp/* 17775374Sbp smb_flushq(&sdp->sd_rqlist); 17875374Sbp smb_flushq(&sdp->sd_rplist); 17975374Sbp*/ 18075374Sbp dev->si_drv1 = NULL; 18175374Sbp free(sdp, M_NSMBDEV); 182171338Savatar destroy_dev_sched(dev); 18375374Sbp splx(s); 18475374Sbp return 0; 18575374Sbp} 18675374Sbp 18775374Sbp 18875374Sbpstatic int 189130585Sphknsmb_dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) 19075374Sbp{ 19175374Sbp struct smb_dev *sdp; 19275374Sbp struct smb_vc *vcp; 19375374Sbp struct smb_share *ssp; 19475374Sbp struct smb_cred scred; 19575374Sbp int error = 0; 19675374Sbp 19775374Sbp SMB_CHECKMINOR(dev); 19875374Sbp if ((sdp->sd_flags & NSMBFL_OPEN) == 0) 19975374Sbp return EBADF; 20075374Sbp 20187192Sbp smb_makescred(&scred, td, NULL); 20275374Sbp switch (cmd) { 20375374Sbp case SMBIOC_OPENSESSION: 20475374Sbp if (sdp->sd_vc) 20575374Sbp return EISCONN; 20675374Sbp error = smb_usr_opensession((struct smbioc_ossn*)data, 20775374Sbp &scred, &vcp); 20875374Sbp if (error) 20975374Sbp break; 21075374Sbp sdp->sd_vc = vcp; 211184572Srwatson smb_vc_unlock(vcp, 0); 21275374Sbp sdp->sd_level = SMBL_VC; 21375374Sbp break; 21475374Sbp case SMBIOC_OPENSHARE: 21575374Sbp if (sdp->sd_share) 21675374Sbp return EISCONN; 21775374Sbp if (sdp->sd_vc == NULL) 21875374Sbp return ENOTCONN; 21975374Sbp error = smb_usr_openshare(sdp->sd_vc, 22075374Sbp (struct smbioc_oshare*)data, &scred, &ssp); 22175374Sbp if (error) 22275374Sbp break; 22375374Sbp sdp->sd_share = ssp; 224184572Srwatson smb_share_unlock(ssp, 0); 22575374Sbp sdp->sd_level = SMBL_SHARE; 22675374Sbp break; 22775374Sbp case SMBIOC_REQUEST: 22875374Sbp if (sdp->sd_share == NULL) 22975374Sbp return ENOTCONN; 23075374Sbp error = smb_usr_simplerequest(sdp->sd_share, 23175374Sbp (struct smbioc_rq*)data, &scred); 23275374Sbp break; 23375374Sbp case SMBIOC_T2RQ: 23475374Sbp if (sdp->sd_share == NULL) 23575374Sbp return ENOTCONN; 23675374Sbp error = smb_usr_t2request(sdp->sd_share, 23775374Sbp (struct smbioc_t2rq*)data, &scred); 23875374Sbp break; 23975374Sbp case SMBIOC_SETFLAGS: { 24075374Sbp struct smbioc_flags *fl = (struct smbioc_flags*)data; 24175374Sbp int on; 24275374Sbp 24375374Sbp if (fl->ioc_level == SMBL_VC) { 24475374Sbp if (fl->ioc_mask & SMBV_PERMANENT) { 24575374Sbp on = fl->ioc_flags & SMBV_PERMANENT; 24675374Sbp if ((vcp = sdp->sd_vc) == NULL) 24775374Sbp return ENOTCONN; 24875374Sbp error = smb_vc_get(vcp, LK_EXCLUSIVE, &scred); 24975374Sbp if (error) 25075374Sbp break; 25175374Sbp if (on && (vcp->obj.co_flags & SMBV_PERMANENT) == 0) { 25275374Sbp vcp->obj.co_flags |= SMBV_PERMANENT; 25387192Sbp smb_vc_ref(vcp); 25475374Sbp } else if (!on && (vcp->obj.co_flags & SMBV_PERMANENT)) { 25575374Sbp vcp->obj.co_flags &= ~SMBV_PERMANENT; 25675374Sbp smb_vc_rele(vcp, &scred); 25775374Sbp } 25875374Sbp smb_vc_put(vcp, &scred); 25975374Sbp } else 26075374Sbp error = EINVAL; 26175374Sbp } else if (fl->ioc_level == SMBL_SHARE) { 26275374Sbp if (fl->ioc_mask & SMBS_PERMANENT) { 26375374Sbp on = fl->ioc_flags & SMBS_PERMANENT; 26475374Sbp if ((ssp = sdp->sd_share) == NULL) 26575374Sbp return ENOTCONN; 26675374Sbp error = smb_share_get(ssp, LK_EXCLUSIVE, &scred); 26775374Sbp if (error) 26875374Sbp break; 26975374Sbp if (on && (ssp->obj.co_flags & SMBS_PERMANENT) == 0) { 27075374Sbp ssp->obj.co_flags |= SMBS_PERMANENT; 27187192Sbp smb_share_ref(ssp); 27275374Sbp } else if (!on && (ssp->obj.co_flags & SMBS_PERMANENT)) { 27375374Sbp ssp->obj.co_flags &= ~SMBS_PERMANENT; 27475374Sbp smb_share_rele(ssp, &scred); 27575374Sbp } 27675374Sbp smb_share_put(ssp, &scred); 27775374Sbp } else 27875374Sbp error = EINVAL; 27975374Sbp break; 28075374Sbp } else 28175374Sbp error = EINVAL; 28275374Sbp break; 28375374Sbp } 28475374Sbp case SMBIOC_LOOKUP: 28575374Sbp if (sdp->sd_vc || sdp->sd_share) 28675374Sbp return EISCONN; 28775374Sbp vcp = NULL; 28875374Sbp ssp = NULL; 28975374Sbp error = smb_usr_lookup((struct smbioc_lookup*)data, &scred, &vcp, &ssp); 29075374Sbp if (error) 29175374Sbp break; 29275374Sbp if (vcp) { 29375374Sbp sdp->sd_vc = vcp; 294184572Srwatson smb_vc_unlock(vcp, 0); 29575374Sbp sdp->sd_level = SMBL_VC; 29675374Sbp } 29775374Sbp if (ssp) { 29875374Sbp sdp->sd_share = ssp; 299184572Srwatson smb_share_unlock(ssp, 0); 30075374Sbp sdp->sd_level = SMBL_SHARE; 30175374Sbp } 30275374Sbp break; 30375374Sbp case SMBIOC_READ: case SMBIOC_WRITE: { 30475374Sbp struct smbioc_rw *rwrq = (struct smbioc_rw*)data; 30575374Sbp struct uio auio; 30675374Sbp struct iovec iov; 30775374Sbp 30875374Sbp if ((ssp = sdp->sd_share) == NULL) 30975374Sbp return ENOTCONN; 31075374Sbp iov.iov_base = rwrq->ioc_base; 31175374Sbp iov.iov_len = rwrq->ioc_cnt; 31275374Sbp auio.uio_iov = &iov; 31375374Sbp auio.uio_iovcnt = 1; 31475374Sbp auio.uio_offset = rwrq->ioc_offset; 31575374Sbp auio.uio_resid = rwrq->ioc_cnt; 31675374Sbp auio.uio_segflg = UIO_USERSPACE; 31775374Sbp auio.uio_rw = (cmd == SMBIOC_READ) ? UIO_READ : UIO_WRITE; 31887192Sbp auio.uio_td = td; 31975374Sbp if (cmd == SMBIOC_READ) 32075374Sbp error = smb_read(ssp, rwrq->ioc_fh, &auio, &scred); 32175374Sbp else 32275374Sbp error = smb_write(ssp, rwrq->ioc_fh, &auio, &scred); 32375374Sbp rwrq->ioc_cnt -= auio.uio_resid; 32475374Sbp break; 32575374Sbp } 32675374Sbp default: 32775374Sbp error = ENODEV; 32875374Sbp } 32975374Sbp return error; 33075374Sbp} 33175374Sbp 33275374Sbpstatic int 33375374Sbpnsmb_dev_load(module_t mod, int cmd, void *arg) 33475374Sbp{ 33575374Sbp int error = 0; 33675374Sbp 33775374Sbp switch (cmd) { 33875374Sbp case MOD_LOAD: 33975374Sbp error = smb_sm_init(); 34075374Sbp if (error) 34175374Sbp break; 34275374Sbp error = smb_iod_init(); 34375374Sbp if (error) { 34475374Sbp smb_sm_done(); 34575374Sbp break; 34675374Sbp } 347184592Srwatson clone_setup(&nsmb_clones); 34875374Sbp nsmb_dev_tag = EVENTHANDLER_REGISTER(dev_clone, nsmb_dev_clone, 0, 1000); 34975374Sbp break; 35075374Sbp case MOD_UNLOAD: 35175374Sbp smb_iod_done(); 35275374Sbp error = smb_sm_done(); 353152676Sbp if (error) 354152676Sbp break; 35575374Sbp EVENTHANDLER_DEREGISTER(dev_clone, nsmb_dev_tag); 356171338Savatar drain_dev_clone_events(); 357184592Srwatson clone_cleanup(&nsmb_clones); 358171338Savatar destroy_dev_drain(&nsmb_cdevsw); 35975374Sbp break; 36075374Sbp default: 36175374Sbp error = EINVAL; 36275374Sbp break; 36375374Sbp } 36475374Sbp return error; 36575374Sbp} 36675374Sbp 36775374SbpDEV_MODULE (dev_netsmb, nsmb_dev_load, 0); 36875374Sbp 36975374Sbp/* 37075374Sbp * Convert a file descriptor to appropriate smb_share pointer 37175374Sbp */ 37275374Sbpstatic struct file* 37375374Sbpnsmb_getfp(struct filedesc* fdp, int fd, int flag) 37475374Sbp{ 37575374Sbp struct file* fp; 37675374Sbp 377168355Srwatson FILEDESC_SLOCK(fdp); 37875374Sbp if (((u_int)fd) >= fdp->fd_nfiles || 37975374Sbp (fp = fdp->fd_ofiles[fd]) == NULL || 38089306Salfred (fp->f_flag & flag) == 0) { 381168355Srwatson FILEDESC_SUNLOCK(fdp); 38275374Sbp return (NULL); 38389306Salfred } 38489306Salfred fhold(fp); 385168355Srwatson FILEDESC_SUNLOCK(fdp); 38675374Sbp return (fp); 38775374Sbp} 38875374Sbp 38975374Sbpint 39075374Sbpsmb_dev2share(int fd, int mode, struct smb_cred *scred, 39175374Sbp struct smb_share **sspp) 39275374Sbp{ 39375374Sbp struct file *fp; 39475374Sbp struct vnode *vp; 39575374Sbp struct smb_dev *sdp; 39675374Sbp struct smb_share *ssp; 397130585Sphk struct cdev *dev; 39875374Sbp int error; 39975374Sbp 40087192Sbp fp = nsmb_getfp(scred->scr_td->td_proc->p_fd, fd, FREAD | FWRITE); 40187192Sbp if (fp == NULL) 40275374Sbp return EBADF; 403116678Sphk vp = fp->f_vnode; 40489306Salfred if (vp == NULL) { 40589306Salfred fdrop(fp, curthread); 40675374Sbp return EBADF; 40789306Salfred } 408137505Sphk if (vp->v_type != VCHR) { 40989306Salfred fdrop(fp, curthread); 41075374Sbp return EBADF; 41189306Salfred } 412137505Sphk dev = vp->v_rdev; 41375374Sbp SMB_CHECKMINOR(dev); 41475374Sbp ssp = sdp->sd_share; 41589306Salfred if (ssp == NULL) { 41689306Salfred fdrop(fp, curthread); 41775374Sbp return ENOTCONN; 41889306Salfred } 41975374Sbp error = smb_share_get(ssp, LK_EXCLUSIVE, scred); 42089306Salfred if (error == 0) 42189306Salfred *sspp = ssp; 42289306Salfred fdrop(fp, curthread); 42389306Salfred return error; 42475374Sbp} 42575374Sbp 426