1 /* $NetBSD: smb_dev.c,v 1.25 2006/11/16 01:33:51 christos Exp $ */
4 * Copyright (c) 2000-2001 Boris Popov
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Boris Popov.
18 * 4. Neither the name of the author nor the names of any co-contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * FreeBSD: src/sys/netsmb/smb_dev.c,v 1.4 2001/12/02 08:47:29 bp Exp
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: smb_dev.c,v 1.25 2006/11/16 01:33:51 christos Exp $");
40 #include <sys/param.h>
41 #include <sys/kernel.h>
42 #include <sys/systm.h>
44 #include <sys/fcntl.h>
45 #include <sys/filedesc.h>
46 #include <sys/ioccom.h>
48 #include <sys/malloc.h>
49 #include <sys/file.h> /* Must come after sys/malloc.h */
53 #include <sys/select.h>
54 #include <sys/socket.h>
55 #include <sys/socketvar.h>
56 #include <sys/sysctl.h>
58 #include <sys/vnode.h>
60 #include <miscfs/specfs/specdev.h> /* XXX */
64 #include <netsmb/smb.h>
65 #include <netsmb/smb_conn.h>
66 #include <netsmb/smb_subr.h>
67 #include <netsmb/smb_dev.h>
68 #include <netsmb/smb_rq.h>
71 static struct smb_dev
**smb_devtbl
; /* indexed by minor */
72 #define SMB_GETDEV(dev) (smb_devtbl[minor(dev)])
77 #define SMB_GETDEV(dev) ((struct smb_dev*)(dev)->si_drv1)
79 static d_open_t nsmb_dev_open
;
80 static d_close_t nsmb_dev_close
;
81 static d_read_t nsmb_dev_read
;
82 static d_write_t nsmb_dev_write
;
83 static d_ioctl_t nsmb_dev_ioctl
;
84 static d_poll_t nsmb_dev_poll
;
86 MODULE_DEPEND(netsmb
, libiconv
, 1, 1, 1);
87 MODULE_VERSION(netsmb
, NSMB_VERSION
);
89 static int smb_version
= NSMB_VERSION
;
92 SYSCTL_DECL(_net_smb
);
93 SYSCTL_INT(_net_smb
, OID_AUTO
, version
, CTLFLAG_RD
, &smb_version
, 0, "");
96 static MALLOC_DEFINE(M_NSMBDEV
, "NETSMBDEV", "NET/SMB device");
100 int smb_dev_queue(struct smb_dev *ndp, struct smb_rq *rqp, int prio);
104 dev_type_open(nsmb_dev_open
);
105 dev_type_close(nsmb_dev_close
);
106 dev_type_ioctl(nsmb_dev_ioctl
);
108 const struct cdevsw nsmb_cdevsw
= {
109 nsmb_dev_open
, nsmb_dev_close
, noread
, nowrite
,
110 nsmb_dev_ioctl
, nostop
, notty
, nopoll
, nommap
, nokqfilter
, D_OTHER
,
113 static struct cdevsw nsmb_cdevsw
= {
114 /* open */ nsmb_dev_open
,
115 /* close */ nsmb_dev_close
,
116 /* read */ nsmb_dev_read
,
117 /* write */ nsmb_dev_write
,
118 /* ioctl */ nsmb_dev_ioctl
,
119 /* poll */ nsmb_dev_poll
,
121 /* strategy */ nostrategy
,
122 /* name */ NSMB_NAME
,
123 /* maj */ NSMB_MAJOR
,
128 #endif /* !__NetBSD__ */
131 static eventhandler_tag nsmb_dev_tag
;
134 nsmb_dev_clone(void *arg
, char *name
, int namelen
, dev_t
*dev
)
140 if (dev_stdclone(name
, NULL
, NSMB_NAME
, &min
) != 1)
142 *dev
= make_dev(&nsmb_cdevsw
, min
, 0, 0, 0600, NSMB_NAME
"%d", min
);
145 #else /* __NetBSD__ */
147 void nsmbattach(int);
155 panic("nsmbattach: cound <= 0");
163 smb_devtbl
= malloc(num
* sizeof(void *), M_NSMBDEV
, M_WAITOK
|M_ZERO
);
167 panic("netsmbattach: smb_sm_init failed");
172 if (smb_iod_init()) {
174 panic("netsmbattach: smb_iod_init failed");
180 #endif /* __NetBSD__ */
183 nsmb_dev_open(dev_t dev
, int oflags
, int devtype
,
189 sdp
= SMB_GETDEV(dev
);
190 if (sdp
&& (sdp
->sd_flags
& NSMBFL_OPEN
))
193 sdp
= malloc(sizeof(*sdp
), M_NSMBDEV
, M_WAITOK
);
194 smb_devtbl
[minor(dev
)] = (void*)sdp
;
199 * XXX: this is just crazy - make a device for an already passed device...
200 * someone should take care of it.
202 if ((dev
->si_flags
& SI_NAMED
) == 0)
203 make_dev(&nsmb_cdevsw
, minor(dev
), cred
->cr_uid
, cred
->cr_gid
, 0700,
204 NSMB_NAME
"%d", dev2unit(dev
));
205 #endif /* !__NetBSD__ */
207 bzero(sdp
, sizeof(*sdp
));
209 STAILQ_INIT(&sdp->sd_rqlist);
210 STAILQ_INIT(&sdp->sd_rplist);
211 bzero(&sdp->sd_pollinfo, sizeof(struct selinfo));
215 sdp
->sd_flags
|= NSMBFL_OPEN
;
221 nsmb_dev_close(dev_t dev
, int flag
, int fmt
, struct lwp
*l
)
225 struct smb_share
*ssp
;
226 struct smb_cred scred
;
229 sdp
= SMB_GETDEV(dev
);
234 if ((sdp
->sd_flags
& NSMBFL_OPEN
) == 0) {
238 smb_makescred(&scred
, l
, NULL
);
241 smb_share_lock(ssp
, 0);
242 smb_share_rele(ssp
, &scred
);
247 smb_vc_rele(vcp
, &scred
);
250 smb_flushq(&sdp->sd_rqlist);
251 smb_flushq(&sdp->sd_rplist);
253 smb_devtbl
[minor(dev
)] = NULL
;
254 free(sdp
, M_NSMBDEV
);
264 nsmb_dev_ioctl(dev_t dev
, u_long cmd
, void *data
, int flag
,
269 struct smb_share
*ssp
;
270 struct smb_cred scred
;
273 sdp
= SMB_GETDEV(dev
);
276 if ((sdp
->sd_flags
& NSMBFL_OPEN
) == 0)
279 smb_makescred(&scred
, l
, NULL
);
281 case SMBIOC_OPENSESSION
:
284 error
= smb_usr_opensession((struct smbioc_ossn
*)data
,
289 smb_vc_unlock(vcp
, 0);
290 sdp
->sd_level
= SMBL_VC
;
292 case SMBIOC_OPENSHARE
:
295 if (sdp
->sd_vc
== NULL
)
297 error
= smb_usr_openshare(sdp
->sd_vc
,
298 (struct smbioc_oshare
*)data
, &scred
, &ssp
);
302 smb_share_unlock(ssp
, 0);
303 sdp
->sd_level
= SMBL_SHARE
;
306 if (sdp
->sd_share
== NULL
)
308 error
= smb_usr_simplerequest(sdp
->sd_share
,
309 (struct smbioc_rq
*)data
, &scred
);
312 if (sdp
->sd_share
== NULL
)
314 error
= smb_usr_t2request(sdp
->sd_share
,
315 (struct smbioc_t2rq
*)data
, &scred
);
317 case SMBIOC_SETFLAGS
: {
318 struct smbioc_flags
*fl
= (struct smbioc_flags
*)data
;
321 if (fl
->ioc_level
== SMBL_VC
) {
322 if (fl
->ioc_mask
& SMBV_PERMANENT
) {
323 on
= fl
->ioc_flags
& SMBV_PERMANENT
;
324 if ((vcp
= sdp
->sd_vc
) == NULL
)
326 error
= smb_vc_get(vcp
, LK_EXCLUSIVE
, &scred
);
329 if (on
&& (vcp
->obj
.co_flags
& SMBV_PERMANENT
) == 0) {
330 vcp
->obj
.co_flags
|= SMBV_PERMANENT
;
332 } else if (!on
&& (vcp
->obj
.co_flags
& SMBV_PERMANENT
)) {
333 vcp
->obj
.co_flags
&= ~SMBV_PERMANENT
;
334 smb_vc_rele(vcp
, &scred
);
336 smb_vc_put(vcp
, &scred
);
339 } else if (fl
->ioc_level
== SMBL_SHARE
) {
340 if (fl
->ioc_mask
& SMBS_PERMANENT
) {
341 on
= fl
->ioc_flags
& SMBS_PERMANENT
;
342 if ((ssp
= sdp
->sd_share
) == NULL
)
344 error
= smb_share_get(ssp
, LK_EXCLUSIVE
, &scred
);
347 if (on
&& (ssp
->obj
.co_flags
& SMBS_PERMANENT
) == 0) {
348 ssp
->obj
.co_flags
|= SMBS_PERMANENT
;
350 } else if (!on
&& (ssp
->obj
.co_flags
& SMBS_PERMANENT
)) {
351 ssp
->obj
.co_flags
&= ~SMBS_PERMANENT
;
352 smb_share_rele(ssp
, &scred
);
354 smb_share_put(ssp
, &scred
);
363 if (sdp
->sd_vc
|| sdp
->sd_share
)
367 error
= smb_usr_lookup((struct smbioc_lookup
*)data
, &scred
, &vcp
, &ssp
);
372 smb_vc_unlock(vcp
, 0);
373 sdp
->sd_level
= SMBL_VC
;
377 smb_share_unlock(ssp
, 0);
378 sdp
->sd_level
= SMBL_SHARE
;
381 case SMBIOC_READ
: case SMBIOC_WRITE
: {
382 struct smbioc_rw
*rwrq
= (struct smbioc_rw
*)data
;
386 if ((ssp
= sdp
->sd_share
) == NULL
)
388 iov
.iov_base
= rwrq
->ioc_base
;
389 iov
.iov_len
= rwrq
->ioc_cnt
;
392 auio
.uio_offset
= rwrq
->ioc_offset
;
393 auio
.uio_resid
= rwrq
->ioc_cnt
;
394 auio
.uio_rw
= (cmd
== SMBIOC_READ
) ? UIO_READ
: UIO_WRITE
;
395 auio
.uio_vmspace
= l
->l_proc
->p_vmspace
;
396 if (cmd
== SMBIOC_READ
)
397 error
= smb_read(ssp
, rwrq
->ioc_fh
, &auio
, &scred
);
399 error
= smb_write(ssp
, rwrq
->ioc_fh
, &auio
, &scred
);
400 rwrq
->ioc_cnt
-= auio
.uio_resid
;
411 nsmb_dev_read(dev_t dev
, struct uio
*uio
, int flag
)
417 nsmb_dev_write(dev_t dev
, struct uio
*uio
, int flag
)
423 nsmb_dev_poll(dev_t dev
, int events
, struct proc
*p
)
429 nsmb_dev_load(module_t mod
, int cmd
, void *arg
)
435 error
= smb_sm_init();
438 error
= smb_iod_init();
443 cdevsw_add(&nsmb_cdevsw
);
444 nsmb_dev_tag
= EVENTHANDLER_REGISTER(dev_clone
, nsmb_dev_clone
, 0, 1000);
445 printf("netsmb_dev: loaded\n");
449 error
= smb_sm_done();
451 EVENTHANDLER_DEREGISTER(dev_clone
, nsmb_dev_tag
);
452 cdevsw_remove(&nsmb_cdevsw
);
453 printf("netsmb_dev: unloaded\n");
462 DEV_MODULE (dev_netsmb
, nsmb_dev_load
, 0);
463 #endif /* !__NetBSD__ */
466 * Convert a file descriptor to appropriate smb_share pointer
469 smb_dev2share(int fd
, int mode
, struct smb_cred
*scred
,
470 struct smb_share
**sspp
)
472 struct lwp
*l
= scred
->scr_l
;
476 struct smb_share
*ssp
;
480 if ((fp
= fd_getfile(l
->l_proc
->p_fd
, fd
)) == NULL
)
485 vp
= (struct vnode
*) fp
->f_data
;
486 if (fp
->f_type
!= DTYPE_VNODE
487 || (fp
->f_flag
& (FREAD
|FWRITE
)) == 0
488 || vp
->v_type
!= VCHR
489 || vp
->v_rdev
== NODEV
) {
498 sdp
= SMB_GETDEV(dev
);
505 error
= smb_share_get(ssp
, LK_EXCLUSIVE
, scred
);