compat linux32 syscalls cleanup.
[netbsd-mini2440.git] / sys / netsmb / smb_dev.c
blob81c4fec5becd1b13b270bba68a0318b47f04707b
1 /* $NetBSD: smb_dev.c,v 1.25 2006/11/16 01:33:51 christos 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.25 2006/11/16 01:33:51 christos 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: cound <= 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;
180 #endif /* __NetBSD__ */
183 nsmb_dev_open(dev_t dev, int oflags, int devtype,
184 struct lwp *l)
186 struct smb_dev *sdp;
187 int s;
189 sdp = SMB_GETDEV(dev);
190 if (sdp && (sdp->sd_flags & NSMBFL_OPEN))
191 return EBUSY;
192 if (sdp == NULL) {
193 sdp = malloc(sizeof(*sdp), M_NSMBDEV, M_WAITOK);
194 smb_devtbl[minor(dev)] = (void*)sdp;
197 #ifndef __NetBSD__
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));
213 s = splnet();
214 sdp->sd_level = -1;
215 sdp->sd_flags |= NSMBFL_OPEN;
216 splx(s);
217 return 0;
221 nsmb_dev_close(dev_t dev, int flag, int fmt, struct lwp *l)
223 struct smb_dev *sdp;
224 struct smb_vc *vcp;
225 struct smb_share *ssp;
226 struct smb_cred scred;
227 int s;
229 sdp = SMB_GETDEV(dev);
230 if (!sdp)
231 return (ENXIO);
233 s = splnet();
234 if ((sdp->sd_flags & NSMBFL_OPEN) == 0) {
235 splx(s);
236 return EBADF;
238 smb_makescred(&scred, l, NULL);
239 ssp = sdp->sd_share;
240 if (ssp != NULL) {
241 smb_share_lock(ssp, 0);
242 smb_share_rele(ssp, &scred);
244 vcp = sdp->sd_vc;
245 if (vcp != NULL) {
246 smb_vc_lock(vcp, 0);
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);
255 #ifndef __NetBSD__
256 destroy_dev(dev);
257 #endif
258 splx(s);
259 return 0;
264 nsmb_dev_ioctl(dev_t dev, u_long cmd, void *data, int flag,
265 struct lwp *l)
267 struct smb_dev *sdp;
268 struct smb_vc *vcp;
269 struct smb_share *ssp;
270 struct smb_cred scred;
271 int error = 0;
273 sdp = SMB_GETDEV(dev);
274 if (!sdp)
275 return (ENXIO);
276 if ((sdp->sd_flags & NSMBFL_OPEN) == 0)
277 return EBADF;
279 smb_makescred(&scred, l, NULL);
280 switch (cmd) {
281 case SMBIOC_OPENSESSION:
282 if (sdp->sd_vc)
283 return EISCONN;
284 error = smb_usr_opensession((struct smbioc_ossn*)data,
285 &scred, &vcp);
286 if (error)
287 break;
288 sdp->sd_vc = vcp;
289 smb_vc_unlock(vcp, 0);
290 sdp->sd_level = SMBL_VC;
291 break;
292 case SMBIOC_OPENSHARE:
293 if (sdp->sd_share)
294 return EISCONN;
295 if (sdp->sd_vc == NULL)
296 return ENOTCONN;
297 error = smb_usr_openshare(sdp->sd_vc,
298 (struct smbioc_oshare*)data, &scred, &ssp);
299 if (error)
300 break;
301 sdp->sd_share = ssp;
302 smb_share_unlock(ssp, 0);
303 sdp->sd_level = SMBL_SHARE;
304 break;
305 case SMBIOC_REQUEST:
306 if (sdp->sd_share == NULL)
307 return ENOTCONN;
308 error = smb_usr_simplerequest(sdp->sd_share,
309 (struct smbioc_rq*)data, &scred);
310 break;
311 case SMBIOC_T2RQ:
312 if (sdp->sd_share == NULL)
313 return ENOTCONN;
314 error = smb_usr_t2request(sdp->sd_share,
315 (struct smbioc_t2rq*)data, &scred);
316 break;
317 case SMBIOC_SETFLAGS: {
318 struct smbioc_flags *fl = (struct smbioc_flags*)data;
319 int on;
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)
325 return ENOTCONN;
326 error = smb_vc_get(vcp, LK_EXCLUSIVE, &scred);
327 if (error)
328 break;
329 if (on && (vcp->obj.co_flags & SMBV_PERMANENT) == 0) {
330 vcp->obj.co_flags |= SMBV_PERMANENT;
331 smb_vc_ref(vcp);
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);
337 } else
338 error = EINVAL;
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)
343 return ENOTCONN;
344 error = smb_share_get(ssp, LK_EXCLUSIVE, &scred);
345 if (error)
346 break;
347 if (on && (ssp->obj.co_flags & SMBS_PERMANENT) == 0) {
348 ssp->obj.co_flags |= SMBS_PERMANENT;
349 smb_share_ref(ssp);
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);
355 } else
356 error = EINVAL;
357 break;
358 } else
359 error = EINVAL;
360 break;
362 case SMBIOC_LOOKUP:
363 if (sdp->sd_vc || sdp->sd_share)
364 return EISCONN;
365 vcp = NULL;
366 ssp = NULL;
367 error = smb_usr_lookup((struct smbioc_lookup*)data, &scred, &vcp, &ssp);
368 if (error)
369 break;
370 if (vcp) {
371 sdp->sd_vc = vcp;
372 smb_vc_unlock(vcp, 0);
373 sdp->sd_level = SMBL_VC;
375 if (ssp) {
376 sdp->sd_share = ssp;
377 smb_share_unlock(ssp, 0);
378 sdp->sd_level = SMBL_SHARE;
380 break;
381 case SMBIOC_READ: case SMBIOC_WRITE: {
382 struct smbioc_rw *rwrq = (struct smbioc_rw*)data;
383 struct uio auio;
384 struct iovec iov;
386 if ((ssp = sdp->sd_share) == NULL)
387 return ENOTCONN;
388 iov.iov_base = rwrq->ioc_base;
389 iov.iov_len = rwrq->ioc_cnt;
390 auio.uio_iov = &iov;
391 auio.uio_iovcnt = 1;
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);
398 else
399 error = smb_write(ssp, rwrq->ioc_fh, &auio, &scred);
400 rwrq->ioc_cnt -= auio.uio_resid;
401 break;
403 default:
404 error = ENODEV;
406 return error;
409 #ifndef __NetBSD__
411 nsmb_dev_read(dev_t dev, struct uio *uio, int flag)
413 return EACCES;
417 nsmb_dev_write(dev_t dev, struct uio *uio, int flag)
419 return EACCES;
423 nsmb_dev_poll(dev_t dev, int events, struct proc *p)
425 return ENODEV;
428 static int
429 nsmb_dev_load(module_t mod, int cmd, void *arg)
431 int error = 0;
433 switch (cmd) {
434 case MOD_LOAD:
435 error = smb_sm_init();
436 if (error)
437 break;
438 error = smb_iod_init();
439 if (error) {
440 smb_sm_done();
441 break;
443 cdevsw_add(&nsmb_cdevsw);
444 nsmb_dev_tag = EVENTHANDLER_REGISTER(dev_clone, nsmb_dev_clone, 0, 1000);
445 printf("netsmb_dev: loaded\n");
446 break;
447 case MOD_UNLOAD:
448 smb_iod_done();
449 error = smb_sm_done();
450 error = 0;
451 EVENTHANDLER_DEREGISTER(dev_clone, nsmb_dev_tag);
452 cdevsw_remove(&nsmb_cdevsw);
453 printf("netsmb_dev: unloaded\n");
454 break;
455 default:
456 error = EINVAL;
457 break;
459 return error;
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;
473 struct file *fp;
474 struct vnode *vp;
475 struct smb_dev *sdp;
476 struct smb_share *ssp;
477 dev_t dev;
478 int error;
480 if ((fp = fd_getfile(l->l_proc->p_fd, fd)) == NULL)
481 return (EBADF);
483 FILE_USE(fp);
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) {
490 FILE_UNUSE(fp, l);
491 return (EBADF);
494 dev = vp->v_rdev;
496 FILE_UNUSE(fp, l);
498 sdp = SMB_GETDEV(dev);
499 if (!sdp)
500 return (ENXIO);
501 ssp = sdp->sd_share;
502 if (ssp == NULL)
503 return ENOTCONN;
505 error = smb_share_get(ssp, LK_EXCLUSIVE, scred);
506 if (error)
507 return error;
509 *sspp = ssp;
510 return 0;