putter.c revision 1.35.8.2 1 /* $NetBSD: putter.c,v 1.35.8.2 2016/07/19 06:26:59 pgoyette Exp $ */
2
3 /*
4 * Copyright (c) 2006, 2007 Antti Kantee. All Rights Reserved.
5 *
6 * Development of this software was supported by the
7 * Ulla Tuominen Foundation and the Finnish Cultural Foundation and the
8 * Research Foundation of Helsinki University of Technology
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
20 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 /*
33 * Pass-to-Userspace TransporTER: generic kernel-user request-response
34 * transport interface.
35 */
36
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: putter.c,v 1.35.8.2 2016/07/19 06:26:59 pgoyette Exp $");
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/conf.h>
43 #include <sys/file.h>
44 #include <sys/filedesc.h>
45 #include <sys/kmem.h>
46 #include <sys/poll.h>
47 #include <sys/stat.h>
48 #include <sys/socketvar.h>
49 #include <sys/module.h>
50 #include <sys/kauth.h>
51 #include <sys/localcount.h>
52
53 #include <dev/putter/putter_sys.h>
54
55 /*
56 * Device routines. These are for when /dev/putter is initially
57 * opened before it has been cloned.
58 */
59
60 dev_type_open(puttercdopen);
61 dev_type_close(puttercdclose);
62 dev_type_ioctl(puttercdioctl);
63
64 /* dev */
65
66 const struct cdevsw putter_cdevsw = {
67 LOCALCOUNT_INITIALIZER
68 .d_open = puttercdopen,
69 .d_close = puttercdclose,
70 .d_read = noread,
71 .d_write = nowrite,
72 .d_ioctl = noioctl,
73 .d_stop = nostop,
74 .d_tty = notty,
75 .d_poll = nopoll,
76 .d_mmap = nommap,
77 .d_kqfilter = nokqfilter,
78 .d_discard = nodiscard,
79 .d_flag = D_OTHER
80 };
81
82 /*
83 * Configuration data.
84 *
85 * This is static-size for now. Will be redone for devfs.
86 */
87
88 #define PUTTER_CONFSIZE 16
89
90 static struct putter_config {
91 int pc_minor;
92 int (*pc_config)(int, int, int);
93 } putterconf[PUTTER_CONFSIZE];
94
95 static int
96 putter_configure(dev_t dev, int flags, int fmt, int fd)
97 {
98 struct putter_config *pc;
99
100 /* are we the catch-all node? */
101 if (minor(dev) == PUTTER_MINOR_WILDCARD
102 || minor(dev) == PUTTER_MINOR_COMPAT)
103 return 0;
104
105 /* nopes? try to configure us */
106 for (pc = putterconf; pc->pc_config; pc++)
107 if (minor(dev) == pc->pc_minor)
108 return pc->pc_config(fd, flags, fmt);
109 return ENXIO;
110 }
111
112 int
113 putter_register(putter_config_fn pcfn, int minor)
114 {
115 int i;
116
117 for (i = 0; i < PUTTER_CONFSIZE; i++)
118 if (putterconf[i].pc_config == NULL)
119 break;
120 if (i == PUTTER_CONFSIZE)
121 return EBUSY;
122
123 putterconf[i].pc_minor = minor;
124 putterconf[i].pc_config = pcfn;
125 return 0;
126 }
127
128 /*
129 * putter instance structures. these are always allocated and freed
130 * from the context of the transport user.
131 */
132 struct putter_instance {
133 pid_t pi_pid;
134 int pi_idx;
135 int pi_fd;
136 struct selinfo pi_sel;
137
138 void *pi_private;
139 struct putter_ops *pi_pop;
140
141 uint8_t *pi_curput;
142 size_t pi_curres;
143 void *pi_curopaq;
144 struct timespec pi_atime;
145 struct timespec pi_mtime;
146 struct timespec pi_btime;
147
148 TAILQ_ENTRY(putter_instance) pi_entries;
149 };
150 #define PUTTER_EMBRYO ((void *)-1) /* before attach */
151 #define PUTTER_DEAD ((void *)-2) /* after detach */
152
153 static TAILQ_HEAD(, putter_instance) putter_ilist
154 = TAILQ_HEAD_INITIALIZER(putter_ilist);
155
156 static int get_pi_idx(struct putter_instance *);
157
158 #ifdef DEBUG
159 #ifndef PUTTERDEBUG
160 #define PUTTERDEBUG
161 #endif
162 #endif
163
164 #ifdef PUTTERDEBUG
165 int putterdebug = 0;
166 #define DPRINTF(x) if (putterdebug > 0) printf x
167 #define DPRINTF_VERBOSE(x) if (putterdebug > 1) printf x
168 #else
169 #define DPRINTF(x)
170 #define DPRINTF_VERBOSE(x)
171 #endif
172
173 /*
174 * public init / deinit
175 */
176
177 /* protects both the list and the contents of the list elements */
178 static kmutex_t pi_mtx;
179
180 void putterattach(void);
181
182 void
183 putterattach(void)
184 {
185
186 mutex_init(&pi_mtx, MUTEX_DEFAULT, IPL_NONE);
187 }
188
189 #if 0
190 void
191 putter_destroy(void)
192 {
193
194 mutex_destroy(&pi_mtx);
195 }
196 #endif
197
198 /*
199 * fd routines, for cloner
200 */
201 static int putter_fop_read(file_t *, off_t *, struct uio *,
202 kauth_cred_t, int);
203 static int putter_fop_write(file_t *, off_t *, struct uio *,
204 kauth_cred_t, int);
205 static int putter_fop_ioctl(file_t*, u_long, void *);
206 static int putter_fop_poll(file_t *, int);
207 static int putter_fop_stat(file_t *, struct stat *);
208 static int putter_fop_close(file_t *);
209 static int putter_fop_kqfilter(file_t *, struct knote *);
210
211
212 static const struct fileops putter_fileops = {
213 .fo_read = putter_fop_read,
214 .fo_write = putter_fop_write,
215 .fo_ioctl = putter_fop_ioctl,
216 .fo_fcntl = fnullop_fcntl,
217 .fo_poll = putter_fop_poll,
218 .fo_stat = putter_fop_stat,
219 .fo_close = putter_fop_close,
220 .fo_kqfilter = putter_fop_kqfilter,
221 .fo_restart = fnullop_restart,
222 };
223
224 static int
225 putter_fop_read(file_t *fp, off_t *off, struct uio *uio,
226 kauth_cred_t cred, int flags)
227 {
228 struct putter_instance *pi = fp->f_data;
229 size_t origres, moved;
230 int error;
231
232 KERNEL_LOCK(1, NULL);
233 getnanotime(&pi->pi_atime);
234
235 if (pi->pi_private == PUTTER_EMBRYO || pi->pi_private == PUTTER_DEAD) {
236 printf("putter_fop_read: private %d not inited\n", pi->pi_idx);
237 KERNEL_UNLOCK_ONE(NULL);
238 return ENOENT;
239 }
240
241 if (pi->pi_curput == NULL) {
242 error = pi->pi_pop->pop_getout(pi->pi_private, uio->uio_resid,
243 fp->f_flag & O_NONBLOCK, &pi->pi_curput,
244 &pi->pi_curres, &pi->pi_curopaq);
245 if (error) {
246 KERNEL_UNLOCK_ONE(NULL);
247 return error;
248 }
249 }
250
251 origres = uio->uio_resid;
252 error = uiomove(pi->pi_curput, pi->pi_curres, uio);
253 moved = origres - uio->uio_resid;
254 DPRINTF(("putter_fop_read (%p): moved %zu bytes from %p, error %d\n",
255 pi, moved, pi->pi_curput, error));
256
257 KASSERT(pi->pi_curres >= moved);
258 pi->pi_curres -= moved;
259 pi->pi_curput += moved;
260
261 if (pi->pi_curres == 0) {
262 pi->pi_pop->pop_releaseout(pi->pi_private,
263 pi->pi_curopaq, error);
264 pi->pi_curput = NULL;
265 }
266
267 KERNEL_UNLOCK_ONE(NULL);
268 return error;
269 }
270
271 static int
272 putter_fop_write(file_t *fp, off_t *off, struct uio *uio,
273 kauth_cred_t cred, int flags)
274 {
275 struct putter_instance *pi = fp->f_data;
276 struct putter_hdr pth;
277 uint8_t *buf;
278 size_t frsize;
279 int error;
280
281 KERNEL_LOCK(1, NULL);
282 getnanotime(&pi->pi_mtime);
283
284 DPRINTF(("putter_fop_write (%p): writing response, resid %zu\n",
285 pi->pi_private, uio->uio_resid));
286
287 if (pi->pi_private == PUTTER_EMBRYO || pi->pi_private == PUTTER_DEAD) {
288 printf("putter_fop_write: putter %d not inited\n", pi->pi_idx);
289 KERNEL_UNLOCK_ONE(NULL);
290 return ENOENT;
291 }
292
293 error = uiomove(&pth, sizeof(struct putter_hdr), uio);
294 if (error) {
295 KERNEL_UNLOCK_ONE(NULL);
296 return error;
297 }
298
299 /* Sorry mate, the kernel doesn't buffer. */
300 frsize = pth.pth_framelen - sizeof(struct putter_hdr);
301 if (uio->uio_resid < frsize) {
302 KERNEL_UNLOCK_ONE(NULL);
303 return EINVAL;
304 }
305
306 buf = kmem_alloc(frsize + sizeof(struct putter_hdr), KM_SLEEP);
307 memcpy(buf, &pth, sizeof(pth));
308 error = uiomove(buf+sizeof(struct putter_hdr), frsize, uio);
309 if (error == 0) {
310 pi->pi_pop->pop_dispatch(pi->pi_private,
311 (struct putter_hdr *)buf);
312 }
313 kmem_free(buf, frsize + sizeof(struct putter_hdr));
314
315 KERNEL_UNLOCK_ONE(NULL);
316 return error;
317 }
318
319 /*
320 * Poll query interface. The question is only if an event
321 * can be read from us.
322 */
323 #define PUTTERPOLL_EVSET (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)
324 static int
325 putter_fop_poll(file_t *fp, int events)
326 {
327 struct putter_instance *pi = fp->f_data;
328 int revents;
329
330 KERNEL_LOCK(1, NULL);
331
332 if (pi->pi_private == PUTTER_EMBRYO || pi->pi_private == PUTTER_DEAD) {
333 printf("putter_fop_ioctl: putter %d not inited\n", pi->pi_idx);
334 KERNEL_UNLOCK_ONE(NULL);
335 return ENOENT;
336 }
337
338 revents = events & (POLLOUT | POLLWRNORM | POLLWRBAND);
339 if ((events & PUTTERPOLL_EVSET) == 0) {
340 KERNEL_UNLOCK_ONE(NULL);
341 return revents;
342 }
343
344 /* check queue */
345 if (pi->pi_pop->pop_waitcount(pi->pi_private))
346 revents |= PUTTERPOLL_EVSET;
347 else
348 selrecord(curlwp, &pi->pi_sel);
349
350 KERNEL_UNLOCK_ONE(NULL);
351 return revents;
352 }
353
354 /*
355 * device close = forced unmount.
356 *
357 * unmounting is a frightfully complex operation to avoid races
358 */
359 static int
360 putter_fop_close(file_t *fp)
361 {
362 struct putter_instance *pi = fp->f_data;
363 int rv;
364
365 DPRINTF(("putter_fop_close: device closed\n"));
366
367 KERNEL_LOCK(1, NULL);
368
369 restart:
370 mutex_enter(&pi_mtx);
371 /*
372 * First check if the driver was never born. In that case
373 * remove the instance from the list. If mount is attempted later,
374 * it will simply fail.
375 */
376 if (pi->pi_private == PUTTER_EMBRYO) {
377 TAILQ_REMOVE(&putter_ilist, pi, pi_entries);
378 mutex_exit(&pi_mtx);
379
380 DPRINTF(("putter_fop_close: data associated with fp %p was "
381 "embryonic\n", fp));
382
383 goto out;
384 }
385
386 /*
387 * Next, analyze if unmount was called and the instance is dead.
388 * In this case we can just free the structure and go home, it
389 * was removed from the list by putter_rmprivate().
390 */
391 if (pi->pi_private == PUTTER_DEAD) {
392 mutex_exit(&pi_mtx);
393
394 DPRINTF(("putter_fop_close: putter associated with fp %p (%d) "
395 "dead, freeing\n", fp, pi->pi_idx));
396
397 goto out;
398 }
399
400 /*
401 * So we have a reference. Proceed to unravel the
402 * underlying driver.
403 */
404 mutex_exit(&pi_mtx);
405
406 /* hmm? suspicious locking? */
407 if (pi->pi_curput != NULL) {
408 pi->pi_pop->pop_releaseout(pi->pi_private, pi->pi_curopaq,
409 ENXIO);
410 pi->pi_curput = NULL;
411 }
412 while ((rv = pi->pi_pop->pop_close(pi->pi_private)) == ERESTART)
413 goto restart;
414
415 out:
416 KERNEL_UNLOCK_ONE(NULL);
417 /*
418 * Finally, release the instance information. It was already
419 * removed from the list by putter_rmprivate() and we know it's
420 * dead, so no need to lock.
421 */
422 kmem_free(pi, sizeof(struct putter_instance));
423
424 return 0;
425 }
426
427 static int
428 putter_fop_stat(file_t *fp, struct stat *st)
429 {
430 struct putter_instance *pi = fp->f_data;
431
432 (void)memset(st, 0, sizeof(*st));
433 KERNEL_LOCK(1, NULL);
434 st->st_dev = makedev(cdevsw_lookup_major(&putter_cdevsw), pi->pi_idx);
435 st->st_atimespec = pi->pi_atime;
436 st->st_mtimespec = pi->pi_mtime;
437 st->st_ctimespec = st->st_birthtimespec = pi->pi_btime;
438 st->st_uid = kauth_cred_geteuid(fp->f_cred);
439 st->st_gid = kauth_cred_getegid(fp->f_cred);
440 st->st_mode = S_IFCHR;
441 KERNEL_UNLOCK_ONE(NULL);
442 return 0;
443 }
444
445 static int
446 putter_fop_ioctl(file_t *fp, u_long cmd, void *data)
447 {
448
449 /*
450 * work already done in sys_ioctl(). skip sanity checks to enable
451 * setting non-blocking fd on an embryotic driver.
452 */
453 if (cmd == FIONBIO)
454 return 0;
455
456 return EINVAL;
457 }
458
459 /* kqueue stuff */
460
461 static void
462 filt_putterdetach(struct knote *kn)
463 {
464 struct putter_instance *pi = kn->kn_hook;
465
466 KERNEL_LOCK(1, NULL);
467 mutex_enter(&pi_mtx);
468 SLIST_REMOVE(&pi->pi_sel.sel_klist, kn, knote, kn_selnext);
469 mutex_exit(&pi_mtx);
470 KERNEL_UNLOCK_ONE(NULL);
471 }
472
473 static int
474 filt_putter(struct knote *kn, long hint)
475 {
476 struct putter_instance *pi = kn->kn_hook;
477 int error, rv;
478
479 KERNEL_LOCK(1, NULL);
480 error = 0;
481 mutex_enter(&pi_mtx);
482 if (pi->pi_private == PUTTER_EMBRYO || pi->pi_private == PUTTER_DEAD)
483 error = 1;
484 mutex_exit(&pi_mtx);
485 if (error) {
486 KERNEL_UNLOCK_ONE(NULL);
487 return 0;
488 }
489
490 kn->kn_data = pi->pi_pop->pop_waitcount(pi->pi_private);
491 rv = kn->kn_data != 0;
492 KERNEL_UNLOCK_ONE(NULL);
493 return rv;
494 }
495
496 static const struct filterops putter_filtops =
497 { 1, NULL, filt_putterdetach, filt_putter };
498
499 static int
500 putter_fop_kqfilter(file_t *fp, struct knote *kn)
501 {
502 struct putter_instance *pi = fp->f_data;
503 struct klist *klist;
504
505 KERNEL_LOCK(1, NULL);
506
507 switch (kn->kn_filter) {
508 case EVFILT_READ:
509 klist = &pi->pi_sel.sel_klist;
510 kn->kn_fop = &putter_filtops;
511 kn->kn_hook = pi;
512
513 mutex_enter(&pi_mtx);
514 SLIST_INSERT_HEAD(klist, kn, kn_selnext);
515 mutex_exit(&pi_mtx);
516
517 break;
518 case EVFILT_WRITE:
519 kn->kn_fop = &seltrue_filtops;
520 break;
521 default:
522 KERNEL_UNLOCK_ONE(NULL);
523 return EINVAL;
524 }
525
526 KERNEL_UNLOCK_ONE(NULL);
527 return 0;
528 }
529
530 int
531 puttercdopen(dev_t dev, int flags, int fmt, struct lwp *l)
532 {
533 struct putter_instance *pi;
534 file_t *fp;
535 int error, fd, idx;
536 proc_t *p;
537
538 p = curproc;
539 pi = kmem_alloc(sizeof(struct putter_instance), KM_SLEEP);
540 mutex_enter(&pi_mtx);
541 idx = get_pi_idx(pi);
542
543 pi->pi_pid = p->p_pid;
544 pi->pi_idx = idx;
545 pi->pi_curput = NULL;
546 pi->pi_curres = 0;
547 pi->pi_curopaq = NULL;
548 getnanotime(&pi->pi_btime);
549 pi->pi_atime = pi->pi_mtime = pi->pi_btime;
550 selinit(&pi->pi_sel);
551 mutex_exit(&pi_mtx);
552
553 if ((error = fd_allocfile(&fp, &fd)) != 0)
554 goto bad1;
555
556 if ((error = putter_configure(dev, flags, fmt, fd)) != 0)
557 goto bad2;
558
559 DPRINTF(("puttercdopen: registered embryonic pmp for pid: %d\n",
560 pi->pi_pid));
561
562 error = fd_clone(fp, fd, FREAD|FWRITE, &putter_fileops, pi);
563 KASSERT(error == EMOVEFD);
564 return error;
565
566 bad2:
567 fd_abort(p, fp, fd);
568 bad1:
569 putter_detach(pi);
570 kmem_free(pi, sizeof(struct putter_instance));
571 return error;
572 }
573
574 int
575 puttercdclose(dev_t dev, int flags, int fmt, struct lwp *l)
576 {
577
578 panic("puttercdclose impossible\n");
579
580 return 0;
581 }
582
583
584 /*
585 * Set the private structure for the file descriptor. This is
586 * typically done immediately when the counterpart has knowledge
587 * about the private structure's address and the file descriptor
588 * (e.g. vfs mount routine).
589 *
590 * We only want to make sure that the caller had the right to open the
591 * device, we don't so much care about which context it gets in case
592 * the same process opened multiple (since they are equal at this point).
593 */
594 struct putter_instance *
595 putter_attach(pid_t pid, int fd, void *ppriv, struct putter_ops *pop)
596 {
597 struct putter_instance *pi = NULL;
598
599 mutex_enter(&pi_mtx);
600 TAILQ_FOREACH(pi, &putter_ilist, pi_entries) {
601 if (pi->pi_pid == pid && pi->pi_private == PUTTER_EMBRYO) {
602 pi->pi_private = ppriv;
603 pi->pi_fd = fd;
604 pi->pi_pop = pop;
605 break;
606 }
607 }
608 mutex_exit(&pi_mtx);
609
610 DPRINTF(("putter_setprivate: pi at %p (%d/%d)\n", pi,
611 pi ? pi->pi_pid : 0, pi ? pi->pi_fd : 0));
612
613 return pi;
614 }
615
616 /*
617 * Remove fp <-> private mapping.
618 */
619 void
620 putter_detach(struct putter_instance *pi)
621 {
622
623 mutex_enter(&pi_mtx);
624 TAILQ_REMOVE(&putter_ilist, pi, pi_entries);
625 pi->pi_private = PUTTER_DEAD;
626 mutex_exit(&pi_mtx);
627 seldestroy(&pi->pi_sel);
628
629 DPRINTF(("putter_nukebypmp: nuked %p\n", pi));
630 }
631
632 void
633 putter_notify(struct putter_instance *pi)
634 {
635
636 selnotify(&pi->pi_sel, 0, 0);
637 }
638
639 /* search sorted list of instances for free minor, sorted insert arg */
640 static int
641 get_pi_idx(struct putter_instance *pi_i)
642 {
643 struct putter_instance *pi;
644 int i;
645
646 KASSERT(mutex_owned(&pi_mtx));
647
648 i = 0;
649 TAILQ_FOREACH(pi, &putter_ilist, pi_entries) {
650 if (i != pi->pi_idx)
651 break;
652 i++;
653 }
654
655 pi_i->pi_private = PUTTER_EMBRYO;
656
657 if (pi == NULL)
658 TAILQ_INSERT_TAIL(&putter_ilist, pi_i, pi_entries);
659 else
660 TAILQ_INSERT_BEFORE(pi, pi_i, pi_entries);
661
662 return i;
663 }
664
665 MODULE(MODULE_CLASS_DRIVER, putter, NULL);
666
667 static int
668 putter_modcmd(modcmd_t cmd, void *arg)
669 {
670 #ifdef _MODULE
671 devmajor_t bmajor = NODEVMAJOR, cmajor = NODEVMAJOR;
672
673 switch (cmd) {
674 case MODULE_CMD_INIT:
675 putterattach();
676 return devsw_attach("putter", NULL, &bmajor,
677 &putter_cdevsw, &cmajor);
678 case MODULE_CMD_FINI:
679 return ENOTTY; /* XXX: putterdetach */
680 default:
681 return ENOTTY;
682 }
683 #else
684 if (cmd == MODULE_CMD_INIT)
685 return 0;
686 return ENOTTY;
687 #endif
688 }
689