FreeBSD/Linux Kernel Cross Reference
sys/netsmb/smb_dev.c
1 /* $NetBSD: smb_dev.c,v 1.20 2005/02/26 22:39:50 perry Exp $ */
2
3 /*
4 * Copyright (c) 2000-2001 Boris Popov
5 * All rights reserved.
6 *
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.
21 *
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.
33 *
34 * FreeBSD: src/sys/netsmb/smb_dev.c,v 1.4 2001/12/02 08:47:29 bp Exp
35 */
36
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: smb_dev.c,v 1.20 2005/02/26 22:39:50 perry Exp $");
39
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>
59
60 #include <miscfs/specfs/specdev.h> /* XXX */
61
62 #include <net/if.h>
63
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>
69
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
74
75 #else /* !NetBSD */
76
77 #define SMB_GETDEV(dev) ((struct smb_dev*)(dev)->si_drv1)
78
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;
85
86 MODULE_DEPEND(netsmb, libiconv, 1, 1, 1);
87 MODULE_VERSION(netsmb, NSMB_VERSION);
88
89 static int smb_version = NSMB_VERSION;
90
91
92 SYSCTL_DECL(_net_smb);
93 SYSCTL_INT(_net_smb, OID_AUTO, version, CTLFLAG_RD, &smb_version, 0, "");
94 #endif /* NetBSD */
95
96 static MALLOC_DEFINE(M_NSMBDEV, "NETSMBDEV", "NET/SMB device");
97
98
99 /*
100 int smb_dev_queue(struct smb_dev *ndp, struct smb_rq *rqp, int prio);
101 */
102
103 #ifdef __NetBSD__
104 dev_type_open(nsmb_dev_open);
105 dev_type_close(nsmb_dev_close);
106 dev_type_ioctl(nsmb_dev_ioctl);
107
108 const struct cdevsw nsmb_cdevsw = {
109 nsmb_dev_open, nsmb_dev_close, noread, nowrite,
110 nsmb_dev_ioctl, nostop, notty, nopoll, nommap, nokqfilter,
111 };
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,
127 };
128 #endif /* !__NetBSD__ */
129
130 #ifndef __NetBSD__
131 static eventhandler_tag nsmb_dev_tag;
132
133 static void
134 nsmb_dev_clone(void *arg, char *name, int namelen, dev_t *dev)
135 {
136 int min;
137
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);
143 }
144
145 #else /* __NetBSD__ */
146
147 void nsmbattach(int);
148
149 void
150 nsmbattach(int num)
151 {
152
153 if (num <= 0) {
154 #ifdef DIAGNOSTIC
155 panic("nsmbattach: cound <= 0");
156 #endif
157 return;
158 }
159
160 if (num == 1)
161 num = NSMB_DEFNUM;
162
163 smb_devtbl = malloc(num * sizeof(void *), M_NSMBDEV, M_WAITOK|M_ZERO);
164
165 if (smb_sm_init()) {
166 #ifdef DIAGNOSTIC
167 panic("netsmbattach: smb_sm_init failed");
168 #endif
169 return;
170 }
171
172 if (smb_iod_init()) {
173 #ifdef DIAGNOSTIC
174 panic("netsmbattach: smb_iod_init failed");
175 #endif
176 smb_sm_done();
177 return;
178 }
179 }
180 #endif /* __NetBSD__ */
181
182 int
183 nsmb_dev_open(dev_t dev, int oflags, int devtype, struct proc *p)
184 {
185 struct smb_dev *sdp;
186 int s;
187
188 sdp = SMB_GETDEV(dev);
189 if (sdp && (sdp->sd_flags & NSMBFL_OPEN))
190 return EBUSY;
191 if (sdp == NULL) {
192 sdp = malloc(sizeof(*sdp), M_NSMBDEV, M_WAITOK);
193 smb_devtbl[minor(dev)] = (void*)sdp;
194 }
195
196 #ifndef __NetBSD__
197 /*
198 * XXX: this is just crazy - make a device for an already passed device...
199 * someone should take care of it.
200 */
201 if ((dev->si_flags & SI_NAMED) == 0)
202 make_dev(&nsmb_cdevsw, minor(dev), cred->cr_uid, cred->cr_gid, 0700,
203 NSMB_NAME"%d", dev2unit(dev));
204 #endif /* !__NetBSD__ */
205
206 bzero(sdp, sizeof(*sdp));
207 /*
208 STAILQ_INIT(&sdp->sd_rqlist);
209 STAILQ_INIT(&sdp->sd_rplist);
210 bzero(&sdp->sd_pollinfo, sizeof(struct selinfo));
211 */
212 s = splnet();
213 sdp->sd_level = -1;
214 sdp->sd_flags |= NSMBFL_OPEN;
215 splx(s);
216 return 0;
217 }
218
219 int
220 nsmb_dev_close(dev_t dev, int flag, int fmt, struct proc *p)
221 {
222 struct smb_dev *sdp;
223 struct smb_vc *vcp;
224 struct smb_share *ssp;
225 struct smb_cred scred;
226 int s;
227
228 sdp = SMB_GETDEV(dev);
229 if (!sdp)
230 return (ENXIO);
231
232 s = splnet();
233 if ((sdp->sd_flags & NSMBFL_OPEN) == 0) {
234 splx(s);
235 return EBADF;
236 }
237 smb_makescred(&scred, p, NULL);
238 ssp = sdp->sd_share;
239 if (ssp != NULL) {
240 smb_share_lock(ssp, 0);
241 smb_share_rele(ssp, &scred);
242 }
243 vcp = sdp->sd_vc;
244 if (vcp != NULL) {
245 smb_vc_lock(vcp, 0);
246 smb_vc_rele(vcp, &scred);
247 }
248 /*
249 smb_flushq(&sdp->sd_rqlist);
250 smb_flushq(&sdp->sd_rplist);
251 */
252 smb_devtbl[minor(dev)] = NULL;
253 free(sdp, M_NSMBDEV);
254 #ifndef __NetBSD__
255 destroy_dev(dev);
256 #endif
257 splx(s);
258 return 0;
259 }
260
261
262 int
263 nsmb_dev_ioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
264 {
265 struct smb_dev *sdp;
266 struct smb_vc *vcp;
267 struct smb_share *ssp;
268 struct smb_cred scred;
269 int error = 0;
270
271 sdp = SMB_GETDEV(dev);
272 if (!sdp)
273 return (ENXIO);
274 if ((sdp->sd_flags & NSMBFL_OPEN) == 0)
275 return EBADF;
276
277 smb_makescred(&scred, p, NULL);
278 switch (cmd) {
279 case SMBIOC_OPENSESSION:
280 if (sdp->sd_vc)
281 return EISCONN;
282 error = smb_usr_opensession((struct smbioc_ossn*)data,
283 &scred, &vcp);
284 if (error)
285 break;
286 sdp->sd_vc = vcp;
287 smb_vc_unlock(vcp, 0);
288 sdp->sd_level = SMBL_VC;
289 break;
290 case SMBIOC_OPENSHARE:
291 if (sdp->sd_share)
292 return EISCONN;
293 if (sdp->sd_vc == NULL)
294 return ENOTCONN;
295 error = smb_usr_openshare(sdp->sd_vc,
296 (struct smbioc_oshare*)data, &scred, &ssp);
297 if (error)
298 break;
299 sdp->sd_share = ssp;
300 smb_share_unlock(ssp, 0);
301 sdp->sd_level = SMBL_SHARE;
302 break;
303 case SMBIOC_REQUEST:
304 if (sdp->sd_share == NULL)
305 return ENOTCONN;
306 error = smb_usr_simplerequest(sdp->sd_share,
307 (struct smbioc_rq*)data, &scred);
308 break;
309 case SMBIOC_T2RQ:
310 if (sdp->sd_share == NULL)
311 return ENOTCONN;
312 error = smb_usr_t2request(sdp->sd_share,
313 (struct smbioc_t2rq*)data, &scred);
314 break;
315 case SMBIOC_SETFLAGS: {
316 struct smbioc_flags *fl = (struct smbioc_flags*)data;
317 int on;
318
319 if (fl->ioc_level == SMBL_VC) {
320 if (fl->ioc_mask & SMBV_PERMANENT) {
321 on = fl->ioc_flags & SMBV_PERMANENT;
322 if ((vcp = sdp->sd_vc) == NULL)
323 return ENOTCONN;
324 error = smb_vc_get(vcp, LK_EXCLUSIVE, &scred);
325 if (error)
326 break;
327 if (on && (vcp->obj.co_flags & SMBV_PERMANENT) == 0) {
328 vcp->obj.co_flags |= SMBV_PERMANENT;
329 smb_vc_ref(vcp);
330 } else if (!on && (vcp->obj.co_flags & SMBV_PERMANENT)) {
331 vcp->obj.co_flags &= ~SMBV_PERMANENT;
332 smb_vc_rele(vcp, &scred);
333 }
334 smb_vc_put(vcp, &scred);
335 } else
336 error = EINVAL;
337 } else if (fl->ioc_level == SMBL_SHARE) {
338 if (fl->ioc_mask & SMBS_PERMANENT) {
339 on = fl->ioc_flags & SMBS_PERMANENT;
340 if ((ssp = sdp->sd_share) == NULL)
341 return ENOTCONN;
342 error = smb_share_get(ssp, LK_EXCLUSIVE, &scred);
343 if (error)
344 break;
345 if (on && (ssp->obj.co_flags & SMBS_PERMANENT) == 0) {
346 ssp->obj.co_flags |= SMBS_PERMANENT;
347 smb_share_ref(ssp);
348 } else if (!on && (ssp->obj.co_flags & SMBS_PERMANENT)) {
349 ssp->obj.co_flags &= ~SMBS_PERMANENT;
350 smb_share_rele(ssp, &scred);
351 }
352 smb_share_put(ssp, &scred);
353 } else
354 error = EINVAL;
355 break;
356 } else
357 error = EINVAL;
358 break;
359 }
360 case SMBIOC_LOOKUP:
361 if (sdp->sd_vc || sdp->sd_share)
362 return EISCONN;
363 vcp = NULL;
364 ssp = NULL;
365 error = smb_usr_lookup((struct smbioc_lookup*)data, &scred, &vcp, &ssp);
366 if (error)
367 break;
368 if (vcp) {
369 sdp->sd_vc = vcp;
370 smb_vc_unlock(vcp, 0);
371 sdp->sd_level = SMBL_VC;
372 }
373 if (ssp) {
374 sdp->sd_share = ssp;
375 smb_share_unlock(ssp, 0);
376 sdp->sd_level = SMBL_SHARE;
377 }
378 break;
379 case SMBIOC_READ: case SMBIOC_WRITE: {
380 struct smbioc_rw *rwrq = (struct smbioc_rw*)data;
381 struct uio auio;
382 struct iovec iov;
383
384 if ((ssp = sdp->sd_share) == NULL)
385 return ENOTCONN;
386 iov.iov_base = rwrq->ioc_base;
387 iov.iov_len = rwrq->ioc_cnt;
388 auio.uio_iov = &iov;
389 auio.uio_iovcnt = 1;
390 auio.uio_offset = rwrq->ioc_offset;
391 auio.uio_resid = rwrq->ioc_cnt;
392 auio.uio_segflg = UIO_USERSPACE;
393 auio.uio_rw = (cmd == SMBIOC_READ) ? UIO_READ : UIO_WRITE;
394 auio.uio_procp = p;
395 if (cmd == SMBIOC_READ)
396 error = smb_read(ssp, rwrq->ioc_fh, &auio, &scred);
397 else
398 error = smb_write(ssp, rwrq->ioc_fh, &auio, &scred);
399 rwrq->ioc_cnt -= auio.uio_resid;
400 break;
401 }
402 default:
403 error = ENODEV;
404 }
405 return error;
406 }
407
408 #ifndef __NetBSD__
409 int
410 nsmb_dev_read(dev_t dev, struct uio *uio, int flag)
411 {
412 return EACCES;
413 }
414
415 int
416 nsmb_dev_write(dev_t dev, struct uio *uio, int flag)
417 {
418 return EACCES;
419 }
420
421 int
422 nsmb_dev_poll(dev_t dev, int events, struct proc *p)
423 {
424 return ENODEV;
425 }
426
427 static int
428 nsmb_dev_load(module_t mod, int cmd, void *arg)
429 {
430 int error = 0;
431
432 switch (cmd) {
433 case MOD_LOAD:
434 error = smb_sm_init();
435 if (error)
436 break;
437 error = smb_iod_init();
438 if (error) {
439 smb_sm_done();
440 break;
441 }
442 cdevsw_add(&nsmb_cdevsw);
443 nsmb_dev_tag = EVENTHANDLER_REGISTER(dev_clone, nsmb_dev_clone, 0, 1000);
444 printf("netsmb_dev: loaded\n");
445 break;
446 case MOD_UNLOAD:
447 smb_iod_done();
448 error = smb_sm_done();
449 error = 0;
450 EVENTHANDLER_DEREGISTER(dev_clone, nsmb_dev_tag);
451 cdevsw_remove(&nsmb_cdevsw);
452 printf("netsmb_dev: unloaded\n");
453 break;
454 default:
455 error = EINVAL;
456 break;
457 }
458 return error;
459 }
460
461 DEV_MODULE (dev_netsmb, nsmb_dev_load, 0);
462 #endif /* !__NetBSD__ */
463
464 /*
465 * Convert a file descriptor to appropriate smb_share pointer
466 */
467 int
468 smb_dev2share(int fd, int mode, struct smb_cred *scred,
469 struct smb_share **sspp)
470 {
471 struct proc *p = scred->scr_p;
472 struct file *fp;
473 struct vnode *vp;
474 struct smb_dev *sdp;
475 struct smb_share *ssp;
476 dev_t dev;
477 int error;
478
479 if ((fp = fd_getfile(p->p_fd, fd)) == NULL)
480 return (EBADF);
481
482 FILE_USE(fp);
483
484 vp = (struct vnode *) 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 FILE_UNUSE(fp, p);
490 return (EBADF);
491 }
492
493 dev = vp->v_rdev;
494
495 FILE_UNUSE(fp, p);
496
497 sdp = SMB_GETDEV(dev);
498 if (!sdp)
499 return (ENXIO);
500 ssp = sdp->sd_share;
501 if (ssp == NULL)
502 return ENOTCONN;
503
504 error = smb_share_get(ssp, LK_EXCLUSIVE, scred);
505 if (error)
506 return error;
507
508 *sspp = ssp;
509 return 0;
510 }
511
Cache object: e5ce6dd0321f2cfd5d87c812cc1fa5f5
|