1 /* $NetBSD: smb_dev.c,v 1.32 2009/09/12 12:52:21 pooka 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.32 2009/09/12 12:52:21 pooka 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: count <= 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");
181 #endif /* __NetBSD__ */
184 nsmb_dev_open(dev_t dev
, int oflags
, int devtype
,
190 sdp
= SMB_GETDEV(dev
);
191 if (sdp
&& (sdp
->sd_flags
& NSMBFL_OPEN
))
194 sdp
= malloc(sizeof(*sdp
), M_NSMBDEV
, M_WAITOK
);
195 smb_devtbl
[minor(dev
)] = (void*)sdp
;
200 * XXX: this is just crazy - make a device for an already passed device...
201 * someone should take care of it.
203 if ((dev
->si_flags
& SI_NAMED
) == 0)
204 make_dev(&nsmb_cdevsw
, minor(dev
), cred
->cr_uid
, cred
->cr_gid
, 0700,
205 NSMB_NAME
"%d", dev2unit(dev
));
206 #endif /* !__NetBSD__ */
208 memset(sdp
, 0, sizeof(*sdp
));
210 STAILQ_INIT(&sdp->sd_rqlist);
211 STAILQ_INIT(&sdp->sd_rplist);
212 selinit(&sdp->sd_pollinfo);
216 sdp
->sd_flags
|= NSMBFL_OPEN
;
222 nsmb_dev_close(dev_t dev
, int flag
, int fmt
, struct lwp
*l
)
226 struct smb_share
*ssp
;
227 struct smb_cred scred
;
230 sdp
= SMB_GETDEV(dev
);
235 if ((sdp
->sd_flags
& NSMBFL_OPEN
) == 0) {
239 smb_makescred(&scred
, l
, NULL
);
243 smb_share_rele(ssp
, &scred
);
248 smb_vc_rele(vcp
, &scred
);
251 smb_flushq(&sdp->sd_rqlist);
252 smb_flushq(&sdp->sd_rplist);
253 seldestroy(&sdp->sd_pollinfo);
255 smb_devtbl
[minor(dev
)] = NULL
;
256 free(sdp
, M_NSMBDEV
);
266 nsmb_dev_ioctl(dev_t dev
, u_long cmd
, void *data
, int flag
,
271 struct smb_share
*ssp
;
272 struct smb_cred scred
;
275 sdp
= SMB_GETDEV(dev
);
278 if ((sdp
->sd_flags
& NSMBFL_OPEN
) == 0)
281 smb_makescred(&scred
, l
, NULL
);
283 case SMBIOC_OPENSESSION
:
286 error
= smb_usr_opensession((struct smbioc_ossn
*)data
,
292 sdp
->sd_level
= SMBL_VC
;
294 case SMBIOC_OPENSHARE
:
297 if (sdp
->sd_vc
== NULL
)
299 error
= smb_usr_openshare(sdp
->sd_vc
,
300 (struct smbioc_oshare
*)data
, &scred
, &ssp
);
304 smb_share_unlock(ssp
);
305 sdp
->sd_level
= SMBL_SHARE
;
308 if (sdp
->sd_share
== NULL
)
310 error
= smb_usr_simplerequest(sdp
->sd_share
,
311 (struct smbioc_rq
*)data
, &scred
);
314 if (sdp
->sd_share
== NULL
)
316 error
= smb_usr_t2request(sdp
->sd_share
,
317 (struct smbioc_t2rq
*)data
, &scred
);
319 case SMBIOC_SETFLAGS
: {
320 struct smbioc_flags
*fl
= (struct smbioc_flags
*)data
;
323 if (fl
->ioc_level
== SMBL_VC
) {
324 if (fl
->ioc_mask
& SMBV_PERMANENT
) {
325 on
= fl
->ioc_flags
& SMBV_PERMANENT
;
326 if ((vcp
= sdp
->sd_vc
) == NULL
)
328 error
= smb_vc_get(vcp
, &scred
);
331 if (on
&& (vcp
->obj
.co_flags
& SMBV_PERMANENT
) == 0) {
332 vcp
->obj
.co_flags
|= SMBV_PERMANENT
;
334 } else if (!on
&& (vcp
->obj
.co_flags
& SMBV_PERMANENT
)) {
335 vcp
->obj
.co_flags
&= ~SMBV_PERMANENT
;
336 smb_vc_rele(vcp
, &scred
);
338 smb_vc_put(vcp
, &scred
);
341 } else if (fl
->ioc_level
== SMBL_SHARE
) {
342 if (fl
->ioc_mask
& SMBS_PERMANENT
) {
343 on
= fl
->ioc_flags
& SMBS_PERMANENT
;
344 if ((ssp
= sdp
->sd_share
) == NULL
)
346 error
= smb_share_get(ssp
, &scred
);
349 if (on
&& (ssp
->obj
.co_flags
& SMBS_PERMANENT
) == 0) {
350 ssp
->obj
.co_flags
|= SMBS_PERMANENT
;
352 } else if (!on
&& (ssp
->obj
.co_flags
& SMBS_PERMANENT
)) {
353 ssp
->obj
.co_flags
&= ~SMBS_PERMANENT
;
354 smb_share_rele(ssp
, &scred
);
356 smb_share_put(ssp
, &scred
);
365 if (sdp
->sd_vc
|| sdp
->sd_share
)
369 error
= smb_usr_lookup((struct smbioc_lookup
*)data
, &scred
, &vcp
, &ssp
);
375 sdp
->sd_level
= SMBL_VC
;
379 smb_share_unlock(ssp
);
380 sdp
->sd_level
= SMBL_SHARE
;
383 case SMBIOC_READ
: case SMBIOC_WRITE
: {
384 struct smbioc_rw
*rwrq
= (struct smbioc_rw
*)data
;
388 if ((ssp
= sdp
->sd_share
) == NULL
)
390 iov
.iov_base
= rwrq
->ioc_base
;
391 iov
.iov_len
= rwrq
->ioc_cnt
;
394 auio
.uio_offset
= rwrq
->ioc_offset
;
395 auio
.uio_resid
= rwrq
->ioc_cnt
;
396 auio
.uio_rw
= (cmd
== SMBIOC_READ
) ? UIO_READ
: UIO_WRITE
;
397 auio
.uio_vmspace
= l
->l_proc
->p_vmspace
;
398 if (cmd
== SMBIOC_READ
)
399 error
= smb_read(ssp
, rwrq
->ioc_fh
, &auio
, &scred
);
401 error
= smb_write(ssp
, rwrq
->ioc_fh
, &auio
, &scred
);
402 rwrq
->ioc_cnt
-= auio
.uio_resid
;
413 nsmb_dev_read(dev_t dev
, struct uio
*uio
, int flag
)
419 nsmb_dev_write(dev_t dev
, struct uio
*uio
, int flag
)
425 nsmb_dev_poll(dev_t dev
, int events
, struct proc
*p
)
431 nsmb_dev_load(module_t mod
, int cmd
, void *arg
)
437 error
= smb_sm_init();
440 error
= smb_iod_init();
445 cdevsw_add(&nsmb_cdevsw
);
446 nsmb_dev_tag
= EVENTHANDLER_REGISTER(dev_clone
, nsmb_dev_clone
, 0, 1000);
447 printf("netsmb_dev: loaded\n");
451 error
= smb_sm_done();
453 EVENTHANDLER_DEREGISTER(dev_clone
, nsmb_dev_tag
);
454 cdevsw_remove(&nsmb_cdevsw
);
455 printf("netsmb_dev: unloaded\n");
464 DEV_MODULE (dev_netsmb
, nsmb_dev_load
, 0);
465 #endif /* !__NetBSD__ */
468 * Convert a file descriptor to appropriate smb_share pointer
471 smb_dev2share(int fd
, int mode
, struct smb_cred
*scred
,
472 struct smb_share
**sspp
)
477 struct smb_share
*ssp
;
481 if ((fp
= fd_getfile(fd
)) == NULL
)
485 if (fp
->f_type
!= DTYPE_VNODE
486 || (fp
->f_flag
& (FREAD
|FWRITE
)) == 0
487 || vp
->v_type
!= VCHR
488 || vp
->v_rdev
== NODEV
) {
497 sdp
= SMB_GETDEV(dev
);
504 error
= smb_share_get(ssp
, scred
);