No empty .Rs/.Re
[netbsd-mini2440.git] / sys / netsmb / smb_dev.c
blob9ddbc0c42fcee0481a5f6dde6f52f12cb245abf5
1 /* $NetBSD: smb_dev.c,v 1.32 2009/09/12 12:52:21 pooka Exp $ */
3 /*
4 * Copyright (c) 2000-2001 Boris Popov
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
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
32 * SUCH DAMAGE.
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>
43 #include <sys/conf.h>
44 #include <sys/fcntl.h>
45 #include <sys/filedesc.h>
46 #include <sys/ioccom.h>
47 #include <sys/lock.h>
48 #include <sys/malloc.h>
49 #include <sys/file.h> /* Must come after sys/malloc.h */
50 #include <sys/mbuf.h>
51 #include <sys/poll.h>
52 #include <sys/proc.h>
53 #include <sys/select.h>
54 #include <sys/socket.h>
55 #include <sys/socketvar.h>
56 #include <sys/sysctl.h>
57 #include <sys/uio.h>
58 #include <sys/vnode.h>
60 #include <miscfs/specfs/specdev.h> /* XXX */
62 #include <net/if.h>
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>
70 #ifdef __NetBSD__
71 static struct smb_dev **smb_devtbl; /* indexed by minor */
72 #define SMB_GETDEV(dev) (smb_devtbl[minor(dev)])
73 #define NSMB_DEFNUM 4
75 #else /* !NetBSD */
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, "");
94 #endif /* NetBSD */
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);
103 #ifdef __NetBSD__
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,
112 #else
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,
120 /* mmap */ nommap,
121 /* strategy */ nostrategy,
122 /* name */ NSMB_NAME,
123 /* maj */ NSMB_MAJOR,
124 /* dump */ nodump,
125 /* psize */ nopsize,
126 /* flags */ 0,
128 #endif /* !__NetBSD__ */
130 #ifndef __NetBSD__
131 static eventhandler_tag nsmb_dev_tag;
133 static void
134 nsmb_dev_clone(void *arg, char *name, int namelen, dev_t *dev)
136 int min;
138 if (*dev != NODEV)
139 return;
140 if (dev_stdclone(name, NULL, NSMB_NAME, &min) != 1)
141 return;
142 *dev = make_dev(&nsmb_cdevsw, min, 0, 0, 0600, NSMB_NAME"%d", min);
145 #else /* __NetBSD__ */
147 void nsmbattach(int);
149 void
150 nsmbattach(int num)
153 if (num <= 0) {
154 #ifdef DIAGNOSTIC
155 panic("nsmbattach: count <= 0");
156 #endif
157 return;
160 if (num == 1)
161 num = NSMB_DEFNUM;
163 smb_devtbl = malloc(num * sizeof(void *), M_NSMBDEV, M_WAITOK|M_ZERO);
165 if (smb_sm_init()) {
166 #ifdef DIAGNOSTIC
167 panic("netsmbattach: smb_sm_init failed");
168 #endif
169 return;
172 if (smb_iod_init()) {
173 #ifdef DIAGNOSTIC
174 panic("netsmbattach: smb_iod_init failed");
175 #endif
176 smb_sm_done();
177 return;
179 smb_rqpool_init();
181 #endif /* __NetBSD__ */
184 nsmb_dev_open(dev_t dev, int oflags, int devtype,
185 struct lwp *l)
187 struct smb_dev *sdp;
188 int s;
190 sdp = SMB_GETDEV(dev);
191 if (sdp && (sdp->sd_flags & NSMBFL_OPEN))
192 return EBUSY;
193 if (sdp == NULL) {
194 sdp = malloc(sizeof(*sdp), M_NSMBDEV, M_WAITOK);
195 smb_devtbl[minor(dev)] = (void*)sdp;
198 #ifndef __NetBSD__
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);
214 s = splnet();
215 sdp->sd_level = -1;
216 sdp->sd_flags |= NSMBFL_OPEN;
217 splx(s);
218 return 0;
222 nsmb_dev_close(dev_t dev, int flag, int fmt, struct lwp *l)
224 struct smb_dev *sdp;
225 struct smb_vc *vcp;
226 struct smb_share *ssp;
227 struct smb_cred scred;
228 int s;
230 sdp = SMB_GETDEV(dev);
231 if (!sdp)
232 return (ENXIO);
234 s = splnet();
235 if ((sdp->sd_flags & NSMBFL_OPEN) == 0) {
236 splx(s);
237 return EBADF;
239 smb_makescred(&scred, l, NULL);
240 ssp = sdp->sd_share;
241 if (ssp != NULL) {
242 smb_share_lock(ssp);
243 smb_share_rele(ssp, &scred);
245 vcp = sdp->sd_vc;
246 if (vcp != NULL) {
247 smb_vc_lock(vcp);
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);
257 #ifndef __NetBSD__
258 destroy_dev(dev);
259 #endif
260 splx(s);
261 return 0;
266 nsmb_dev_ioctl(dev_t dev, u_long cmd, void *data, int flag,
267 struct lwp *l)
269 struct smb_dev *sdp;
270 struct smb_vc *vcp;
271 struct smb_share *ssp;
272 struct smb_cred scred;
273 int error = 0;
275 sdp = SMB_GETDEV(dev);
276 if (!sdp)
277 return (ENXIO);
278 if ((sdp->sd_flags & NSMBFL_OPEN) == 0)
279 return EBADF;
281 smb_makescred(&scred, l, NULL);
282 switch (cmd) {
283 case SMBIOC_OPENSESSION:
284 if (sdp->sd_vc)
285 return EISCONN;
286 error = smb_usr_opensession((struct smbioc_ossn*)data,
287 &scred, &vcp);
288 if (error)
289 break;
290 sdp->sd_vc = vcp;
291 smb_vc_unlock(vcp);
292 sdp->sd_level = SMBL_VC;
293 break;
294 case SMBIOC_OPENSHARE:
295 if (sdp->sd_share)
296 return EISCONN;
297 if (sdp->sd_vc == NULL)
298 return ENOTCONN;
299 error = smb_usr_openshare(sdp->sd_vc,
300 (struct smbioc_oshare*)data, &scred, &ssp);
301 if (error)
302 break;
303 sdp->sd_share = ssp;
304 smb_share_unlock(ssp);
305 sdp->sd_level = SMBL_SHARE;
306 break;
307 case SMBIOC_REQUEST:
308 if (sdp->sd_share == NULL)
309 return ENOTCONN;
310 error = smb_usr_simplerequest(sdp->sd_share,
311 (struct smbioc_rq*)data, &scred);
312 break;
313 case SMBIOC_T2RQ:
314 if (sdp->sd_share == NULL)
315 return ENOTCONN;
316 error = smb_usr_t2request(sdp->sd_share,
317 (struct smbioc_t2rq*)data, &scred);
318 break;
319 case SMBIOC_SETFLAGS: {
320 struct smbioc_flags *fl = (struct smbioc_flags*)data;
321 int on;
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)
327 return ENOTCONN;
328 error = smb_vc_get(vcp, &scred);
329 if (error)
330 break;
331 if (on && (vcp->obj.co_flags & SMBV_PERMANENT) == 0) {
332 vcp->obj.co_flags |= SMBV_PERMANENT;
333 smb_vc_ref(vcp);
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);
339 } else
340 error = EINVAL;
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)
345 return ENOTCONN;
346 error = smb_share_get(ssp, &scred);
347 if (error)
348 break;
349 if (on && (ssp->obj.co_flags & SMBS_PERMANENT) == 0) {
350 ssp->obj.co_flags |= SMBS_PERMANENT;
351 smb_share_ref(ssp);
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);
357 } else
358 error = EINVAL;
359 break;
360 } else
361 error = EINVAL;
362 break;
364 case SMBIOC_LOOKUP:
365 if (sdp->sd_vc || sdp->sd_share)
366 return EISCONN;
367 vcp = NULL;
368 ssp = NULL;
369 error = smb_usr_lookup((struct smbioc_lookup*)data, &scred, &vcp, &ssp);
370 if (error)
371 break;
372 if (vcp) {
373 sdp->sd_vc = vcp;
374 smb_vc_unlock(vcp);
375 sdp->sd_level = SMBL_VC;
377 if (ssp) {
378 sdp->sd_share = ssp;
379 smb_share_unlock(ssp);
380 sdp->sd_level = SMBL_SHARE;
382 break;
383 case SMBIOC_READ: case SMBIOC_WRITE: {
384 struct smbioc_rw *rwrq = (struct smbioc_rw*)data;
385 struct uio auio;
386 struct iovec iov;
388 if ((ssp = sdp->sd_share) == NULL)
389 return ENOTCONN;
390 iov.iov_base = rwrq->ioc_base;
391 iov.iov_len = rwrq->ioc_cnt;
392 auio.uio_iov = &iov;
393 auio.uio_iovcnt = 1;
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);
400 else
401 error = smb_write(ssp, rwrq->ioc_fh, &auio, &scred);
402 rwrq->ioc_cnt -= auio.uio_resid;
403 break;
405 default:
406 error = ENODEV;
408 return error;
411 #ifndef __NetBSD__
413 nsmb_dev_read(dev_t dev, struct uio *uio, int flag)
415 return EACCES;
419 nsmb_dev_write(dev_t dev, struct uio *uio, int flag)
421 return EACCES;
425 nsmb_dev_poll(dev_t dev, int events, struct proc *p)
427 return ENODEV;
430 static int
431 nsmb_dev_load(module_t mod, int cmd, void *arg)
433 int error = 0;
435 switch (cmd) {
436 case MOD_LOAD:
437 error = smb_sm_init();
438 if (error)
439 break;
440 error = smb_iod_init();
441 if (error) {
442 smb_sm_done();
443 break;
445 cdevsw_add(&nsmb_cdevsw);
446 nsmb_dev_tag = EVENTHANDLER_REGISTER(dev_clone, nsmb_dev_clone, 0, 1000);
447 printf("netsmb_dev: loaded\n");
448 break;
449 case MOD_UNLOAD:
450 smb_iod_done();
451 error = smb_sm_done();
452 error = 0;
453 EVENTHANDLER_DEREGISTER(dev_clone, nsmb_dev_tag);
454 cdevsw_remove(&nsmb_cdevsw);
455 printf("netsmb_dev: unloaded\n");
456 break;
457 default:
458 error = EINVAL;
459 break;
461 return error;
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)
474 file_t *fp;
475 struct vnode *vp;
476 struct smb_dev *sdp;
477 struct smb_share *ssp;
478 dev_t dev;
479 int error;
481 if ((fp = fd_getfile(fd)) == NULL)
482 return (EBADF);
484 vp = fp->f_data;
485 if (fp->f_type != DTYPE_VNODE
486 || (fp->f_flag & (FREAD|FWRITE)) == 0
487 || vp->v_type != VCHR
488 || vp->v_rdev == NODEV) {
489 fd_putfile(fd);
490 return (EBADF);
493 dev = vp->v_rdev;
495 fd_putfile(fd);
497 sdp = SMB_GETDEV(dev);
498 if (!sdp)
499 return (ENXIO);
500 ssp = sdp->sd_share;
501 if (ssp == NULL)
502 return ENOTCONN;
504 error = smb_share_get(ssp, scred);
505 if (error)
506 return error;
508 *sspp = ssp;
509 return 0;