2 * Copyright (c) 2000-2001 Boris Popov
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Boris Popov.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * $FreeBSD: src/sys/netsmb/smb_dev.c,v 1.2.2.1 2001/05/22 08:32:33 bp Exp $
33 * $DragonFly: src/sys/netproto/smb/smb_dev.c,v 1.18 2007/05/08 02:31:42 dillon Exp $
35 #include <sys/param.h>
36 #include <sys/kernel.h>
37 #include <sys/systm.h>
39 #include <sys/device.h>
40 #include <sys/fcntl.h>
41 #include <sys/ioccom.h>
42 #include <sys/malloc.h>
43 #include <sys/file.h> /* Must come after sys/malloc.h */
46 #include <sys/select.h>
47 #include <sys/socket.h>
48 #include <sys/socketvar.h>
49 #include <sys/sysctl.h>
51 #include <sys/vnode.h>
52 #include <sys/thread2.h>
61 #define SMB_GETDEV(dev) ((struct smb_dev*)(dev)->si_drv1)
62 #define SMB_CHECKMINOR(dev) do { \
63 sdp = SMB_GETDEV(dev); \
64 if (sdp == NULL) return ENXIO; \
67 static d_open_t nsmb_dev_open
;
68 static d_close_t nsmb_dev_close
;
69 static d_read_t nsmb_dev_read
;
70 static d_write_t nsmb_dev_write
;
71 static d_ioctl_t nsmb_dev_ioctl
;
72 static d_poll_t nsmb_dev_poll
;
74 MODULE_VERSION(netsmb
, NSMB_VERSION
);
78 static int smb_version
= NSMB_VERSION
;
81 SYSCTL_DECL(_net_smb
);
82 SYSCTL_INT(_net_smb
, OID_AUTO
, version
, CTLFLAG_RD
, &smb_version
, 0, "");
84 static MALLOC_DEFINE(M_NSMBDEV
, "NETSMBDEV", "NET/SMB device");
88 int smb_dev_queue(struct smb_dev *ndp, struct smb_rq *rqp, int prio);
91 static struct dev_ops nsmb_ops
= {
92 { NSMB_NAME
, NSMB_MAJOR
, 0 },
93 .d_open
= nsmb_dev_open
,
94 .d_close
= nsmb_dev_close
,
95 .d_read
= nsmb_dev_read
,
96 .d_write
= nsmb_dev_write
,
97 .d_ioctl
= nsmb_dev_ioctl
,
98 .d_poll
= nsmb_dev_poll
,
103 nsmb_dev_open(struct dev_open_args
*ap
)
105 cdev_t dev
= ap
->a_head
.a_dev
;
108 sdp
= SMB_GETDEV(dev
);
109 if (sdp
&& (sdp
->sd_flags
& NSMBFL_OPEN
))
112 sdp
= kmalloc(sizeof(*sdp
), M_NSMBDEV
, M_WAITOK
);
113 dev
->si_drv1
= (void*)sdp
;
116 * XXX: this is just crazy - make a device for an already passed
117 * device... someone should take care of it.
119 if ((dev
->si_flags
& SI_NAMED
) == 0) {
120 make_dev(&nsmb_ops
, minor(dev
),
121 ap
->a_cred
->cr_uid
, ap
->a_cred
->cr_gid
,
122 0700, NSMB_NAME
"%d", lminor(dev
));
124 bzero(sdp
, sizeof(*sdp
));
126 STAILQ_INIT(&sdp->sd_rqlist);
127 STAILQ_INIT(&sdp->sd_rplist);
128 bzero(&sdp->sd_pollinfo, sizeof(struct selinfo));
132 sdp
->sd_flags
|= NSMBFL_OPEN
;
138 nsmb_dev_close(struct dev_close_args
*ap
)
140 cdev_t dev
= ap
->a_head
.a_dev
;
143 struct smb_share
*ssp
;
144 struct smb_cred scred
;
148 if ((sdp
->sd_flags
& NSMBFL_OPEN
) == 0) {
152 smb_makescred(&scred
, curthread
, NULL
);
155 smb_share_rele(ssp
, &scred
);
158 smb_vc_rele(vcp
, &scred
);
160 smb_flushq(&sdp->sd_rqlist);
161 smb_flushq(&sdp->sd_rplist);
164 kfree(sdp
, M_NSMBDEV
);
171 nsmb_dev_ioctl(struct dev_ioctl_args
*ap
)
173 cdev_t dev
= ap
->a_head
.a_dev
;
174 caddr_t data
= ap
->a_data
;
177 struct smb_share
*ssp
;
178 struct smb_cred scred
;
182 if ((sdp
->sd_flags
& NSMBFL_OPEN
) == 0)
185 smb_makescred(&scred
, NULL
, ap
->a_cred
);
187 case SMBIOC_OPENSESSION
:
190 error
= smb_usr_opensession((struct smbioc_ossn
*)data
,
195 smb_vc_unlock(vcp
, 0);
196 sdp
->sd_level
= SMBL_VC
;
198 case SMBIOC_OPENSHARE
:
201 if (sdp
->sd_vc
== NULL
)
203 error
= smb_usr_openshare(sdp
->sd_vc
,
204 (struct smbioc_oshare
*)data
, &scred
, &ssp
);
208 smb_share_unlock(ssp
, 0);
209 sdp
->sd_level
= SMBL_SHARE
;
212 if (sdp
->sd_share
== NULL
)
214 error
= smb_usr_simplerequest(sdp
->sd_share
,
215 (struct smbioc_rq
*)data
, &scred
);
218 if (sdp
->sd_share
== NULL
)
220 error
= smb_usr_t2request(sdp
->sd_share
,
221 (struct smbioc_t2rq
*)data
, &scred
);
223 case SMBIOC_SETFLAGS
: {
224 struct smbioc_flags
*fl
= (struct smbioc_flags
*)data
;
227 if (fl
->ioc_level
== SMBL_VC
) {
228 if (fl
->ioc_mask
& SMBV_PERMANENT
) {
229 on
= fl
->ioc_flags
& SMBV_PERMANENT
;
230 if ((vcp
= sdp
->sd_vc
) == NULL
)
232 error
= smb_vc_get(vcp
, LK_EXCLUSIVE
, &scred
);
235 if (on
&& (vcp
->obj
.co_flags
& SMBV_PERMANENT
) == 0) {
236 vcp
->obj
.co_flags
|= SMBV_PERMANENT
;
238 } else if (!on
&& (vcp
->obj
.co_flags
& SMBV_PERMANENT
)) {
239 vcp
->obj
.co_flags
&= ~SMBV_PERMANENT
;
240 smb_vc_rele(vcp
, &scred
);
242 smb_vc_put(vcp
, &scred
);
245 } else if (fl
->ioc_level
== SMBL_SHARE
) {
246 if (fl
->ioc_mask
& SMBS_PERMANENT
) {
247 on
= fl
->ioc_flags
& SMBS_PERMANENT
;
248 if ((ssp
= sdp
->sd_share
) == NULL
)
250 error
= smb_share_get(ssp
, LK_EXCLUSIVE
, &scred
);
253 if (on
&& (ssp
->obj
.co_flags
& SMBS_PERMANENT
) == 0) {
254 ssp
->obj
.co_flags
|= SMBS_PERMANENT
;
256 } else if (!on
&& (ssp
->obj
.co_flags
& SMBS_PERMANENT
)) {
257 ssp
->obj
.co_flags
&= ~SMBS_PERMANENT
;
258 smb_share_rele(ssp
, &scred
);
260 smb_share_put(ssp
, &scred
);
269 if (sdp
->sd_vc
|| sdp
->sd_share
)
273 error
= smb_usr_lookup((struct smbioc_lookup
*)data
, &scred
, &vcp
, &ssp
);
278 smb_vc_unlock(vcp
, 0);
279 sdp
->sd_level
= SMBL_VC
;
283 smb_share_unlock(ssp
, 0);
284 sdp
->sd_level
= SMBL_SHARE
;
287 case SMBIOC_READ
: case SMBIOC_WRITE
: {
288 struct smbioc_rw
*rwrq
= (struct smbioc_rw
*)data
;
292 if ((ssp
= sdp
->sd_share
) == NULL
)
294 iov
.iov_base
= rwrq
->ioc_base
;
295 iov
.iov_len
= rwrq
->ioc_cnt
;
298 auio
.uio_offset
= rwrq
->ioc_offset
;
299 auio
.uio_resid
= rwrq
->ioc_cnt
;
300 auio
.uio_segflg
= UIO_USERSPACE
;
301 auio
.uio_rw
= (ap
->a_cmd
== SMBIOC_READ
) ? UIO_READ
: UIO_WRITE
;
302 auio
.uio_td
= curthread
;
303 if (ap
->a_cmd
== SMBIOC_READ
)
304 error
= smb_read(ssp
, rwrq
->ioc_fh
, &auio
, &scred
);
306 error
= smb_write(ssp
, rwrq
->ioc_fh
, &auio
, &scred
);
307 rwrq
->ioc_cnt
-= auio
.uio_resid
;
317 nsmb_dev_read(struct dev_read_args
*ap
)
323 nsmb_dev_write(struct dev_write_args
*ap
)
329 nsmb_dev_poll(struct dev_poll_args
*ap
)
335 nsmb_dev_load(module_t mod
, int cmd
, void *arg
)
341 error
= smb_sm_init();
344 error
= smb_iod_init();
349 dev_ops_add(&nsmb_ops
, 0, 0);
350 kprintf("netsmb_dev: loaded\n");
354 error
= smb_sm_done();
356 dev_ops_remove(&nsmb_ops
, 0, 0);
357 kprintf("netsmb_dev: unloaded\n");
366 DEV_MODULE (dev_netsmb
, nsmb_dev_load
, 0);
369 smb_dev2share(int fd
, int mode
, struct smb_cred
*scred
,
370 struct smb_share
**sspp
)
375 struct smb_share
*ssp
;
379 KKASSERT(scred
->scr_td
->td_proc
);
381 fp
= holdfp(scred
->scr_td
->td_proc
->p_fd
, fd
, FREAD
|FWRITE
);
385 vp
= (struct vnode
*)fp
->f_data
;
401 error
= smb_share_get(ssp
, LK_EXCLUSIVE
, scred
);