Fix a couple of NULL dereferences in error paths.
[dragonfly.git] / sys / dev / misc / snp / snp.c
CommitLineData
984263bc 1/*
22ff886e
AH
2 * (MPSAFE)
3 *
984263bc
MD
4 * Copyright (c) 1995 Ugen J.S.Antsilevich
5 *
6 * Redistribution and use in source forms, with and without modification,
7 * are permitted provided that this entire comment appears intact.
8 *
9 * Redistribution in binary form may occur without any restrictions.
10 * Obviously, it would be nice if you gave credit where credit is due
11 * but requiring it would be too onerous.
12 *
13 * This software is provided ``AS IS'' without any warranties of any kind.
14 *
15 * Snoop stuff.
16 *
17 * $FreeBSD: src/sys/dev/snp/snp.c,v 1.69.2.2 2002/05/06 07:30:02 dd Exp $
18 */
19
95db3aac 20#include "use_snp.h"
984263bc
MD
21#include <sys/param.h>
22#include <sys/systm.h>
23#include <sys/filio.h>
24#include <sys/malloc.h>
25#include <sys/tty.h>
26#include <sys/conf.h>
5d7a9a94 27#include <sys/event.h>
984263bc
MD
28#include <sys/kernel.h>
29#include <sys/queue.h>
30#include <sys/snoop.h>
12cc2857 31#include <sys/thread2.h>
984263bc 32#include <sys/vnode.h>
f15db79e 33#include <sys/device.h>
2c1e28dd 34#include <sys/devfs.h>
984263bc
MD
35
36static l_close_t snplclose;
37static l_write_t snplwrite;
38static d_open_t snpopen;
39static d_close_t snpclose;
40static d_read_t snpread;
41static d_write_t snpwrite;
42static d_ioctl_t snpioctl;
5d7a9a94 43static d_kqfilter_t snpkqfilter;
8be7edad 44static d_clone_t snpclone;
0cf7fc2c 45DEVFS_DEFINE_CLONE_BITMAP(snp);
95db3aac 46
5d7a9a94 47static void snpfilter_detach(struct knote *);
163625b9
SG
48static int snpfilter_rd(struct knote *, long);
49static int snpfilter_wr(struct knote *, long);
5d7a9a94 50
95db3aac 51#if NSNP <= 1
8be7edad 52#define SNP_PREALLOCATED_UNITS 4
95db3aac
AH
53#else
54#define SNP_PREALLOCATED_UNITS NSNP
55#endif
984263bc 56
fef8985e 57static struct dev_ops snp_ops = {
88abd8b5 58 { "snp", 0, 0 },
fef8985e
MD
59 .d_open = snpopen,
60 .d_close = snpclose,
61 .d_read = snpread,
62 .d_write = snpwrite,
63 .d_ioctl = snpioctl,
5d7a9a94 64 .d_kqfilter = snpkqfilter
984263bc
MD
65};
66
67static struct linesw snpdisc = {
68 ttyopen, snplclose, ttread, snplwrite,
69 l_nullioctl, ttyinput, ttstart, ttymodem
70};
71
72/*
73 * This is the main snoop per-device structure.
74 */
75struct snoop {
76 LIST_ENTRY(snoop) snp_list; /* List glue. */
b13267a5 77 cdev_t snp_target; /* Target tty device. */
984263bc
MD
78 struct tty *snp_tty; /* Target tty pointer. */
79 u_long snp_len; /* Possible length. */
80 u_long snp_base; /* Data base. */
81 u_long snp_blen; /* Used length. */
82 caddr_t snp_buf; /* Allocation pointer. */
83 int snp_flags; /* Flags. */
5b22f1a7 84 struct kqinfo snp_kq; /* Kqueue info. */
984263bc
MD
85 int snp_olddisc; /* Old line discipline. */
86};
87
88/*
89 * Possible flags.
90 */
91#define SNOOP_ASYNC 0x0002
92#define SNOOP_OPEN 0x0004
93#define SNOOP_RWAIT 0x0008
94#define SNOOP_OFLOW 0x0010
95#define SNOOP_DOWN 0x0020
96
97/*
98 * Other constants.
99 */
100#define SNOOP_MINLEN (4*1024) /* This should be power of 2.
101 * 4K tested to be the minimum
102 * for which on normal tty
103 * usage there is no need to
104 * allocate more.
105 */
106#define SNOOP_MAXLEN (64*1024) /* This one also,64K enough
107 * If we grow more,something
108 * really bad in this world..
109 */
110
111static MALLOC_DEFINE(M_SNP, "snp", "Snoop device data");
112/*
113 * The number of the "snoop" line discipline. This gets determined at
114 * module load time.
115 */
116static int snooplinedisc;
117
118
119static LIST_HEAD(, snoop) snp_sclist = LIST_HEAD_INITIALIZER(&snp_sclist);
2efb75f3 120static struct lwkt_token snp_token = LWKT_TOKEN_INITIALIZER(snp_token);
984263bc 121
b13267a5 122static struct tty *snpdevtotty (cdev_t dev);
38e94a25
RG
123static int snp_detach (struct snoop *snp);
124static int snp_down (struct snoop *snp);
125static int snp_in (struct snoop *snp, char *buf, int n);
126static int snp_modevent (module_t mod, int what, void *arg);
984263bc
MD
127
128static int
c436375a 129snplclose(struct tty *tp, int flag)
984263bc
MD
130{
131 struct snoop *snp;
132 int error;
133
2efb75f3 134 lwkt_gettoken(&snp_token);
984263bc
MD
135 snp = tp->t_sc;
136 error = snp_down(snp);
22ff886e 137 if (error != 0) {
2efb75f3 138 lwkt_reltoken(&snp_token);
984263bc 139 return (error);
22ff886e 140 }
2efb75f3 141 lwkt_gettoken(&tp->t_token);
984263bc 142 error = ttylclose(tp, flag);
2efb75f3
MD
143 lwkt_reltoken(&tp->t_token);
144 lwkt_reltoken(&snp_token);
145
984263bc
MD
146 return (error);
147}
148
149static int
c436375a 150snplwrite(struct tty *tp, struct uio *uio, int flag)
984263bc
MD
151{
152 struct iovec iov;
153 struct uio uio2;
154 struct snoop *snp;
155 int error, ilen;
156 char *ibuf;
157
2efb75f3 158 lwkt_gettoken(&tp->t_token);
984263bc
MD
159 error = 0;
160 ibuf = NULL;
161 snp = tp->t_sc;
162 while (uio->uio_resid > 0) {
e54488bb 163 ilen = (int)szmin(512, uio->uio_resid);
efda3bd0 164 ibuf = kmalloc(ilen, M_SNP, M_WAITOK);
e54488bb 165 error = uiomove(ibuf, (size_t)ilen, uio);
984263bc
MD
166 if (error != 0)
167 break;
168 snp_in(snp, ibuf, ilen);
169 /* Hackish, but probably the least of all evils. */
170 iov.iov_base = ibuf;
171 iov.iov_len = ilen;
172 uio2.uio_iov = &iov;
173 uio2.uio_iovcnt = 1;
174 uio2.uio_offset = 0;
175 uio2.uio_resid = ilen;
176 uio2.uio_segflg = UIO_SYSSPACE;
177 uio2.uio_rw = UIO_WRITE;
dadab5e9 178 uio2.uio_td = uio->uio_td;
984263bc
MD
179 error = ttwrite(tp, &uio2, flag);
180 if (error != 0)
181 break;
efda3bd0 182 kfree(ibuf, M_SNP);
984263bc
MD
183 ibuf = NULL;
184 }
185 if (ibuf != NULL)
efda3bd0 186 kfree(ibuf, M_SNP);
2efb75f3 187 lwkt_reltoken(&tp->t_token);
984263bc
MD
188 return (error);
189}
190
191static struct tty *
b13267a5 192snpdevtotty(cdev_t dev)
984263bc 193{
f15db79e 194 if ((dev_dflags(dev) & D_TTY) == 0)
984263bc
MD
195 return (NULL);
196 return (dev->si_tty);
197}
198
199#define SNP_INPUT_BUF 5 /* This is even too much, the maximal
200 * interactive mode write is 3 bytes
201 * length for function keys...
202 */
203
204static int
fef8985e 205snpwrite(struct dev_write_args *ap)
984263bc 206{
b13267a5 207 cdev_t dev = ap->a_head.a_dev;
fef8985e 208 struct uio *uio = ap->a_uio;
984263bc
MD
209 struct snoop *snp;
210 struct tty *tp;
211 int error, i, len;
212 unsigned char c[SNP_INPUT_BUF];
213
214 snp = dev->si_drv1;
215 tp = snp->snp_tty;
42e46aee 216 if (tp == NULL)
984263bc 217 return (EIO);
42e46aee 218 lwkt_gettoken(&tp->t_token);
984263bc
MD
219 if ((tp->t_sc == snp) && (tp->t_state & TS_SNOOP) &&
220 tp->t_line == snooplinedisc)
221 goto tty_input;
222
e3869ec7 223 kprintf("Snoop: attempt to write to bad tty.\n");
2efb75f3 224 lwkt_reltoken(&tp->t_token);
984263bc
MD
225 return (EIO);
226
227tty_input:
22ff886e 228 if (!(tp->t_state & TS_ISOPEN)) {
2efb75f3 229 lwkt_reltoken(&tp->t_token);
984263bc 230 return (EIO);
22ff886e 231 }
984263bc
MD
232
233 while (uio->uio_resid > 0) {
e54488bb 234 len = (int)szmin(uio->uio_resid, SNP_INPUT_BUF);
22ff886e 235 if ((error = uiomove(c, (size_t)len, uio)) != 0) {
2efb75f3 236 lwkt_reltoken(&tp->t_token);
984263bc 237 return (error);
22ff886e 238 }
984263bc 239 for (i=0; i < len; i++) {
22ff886e 240 if (ttyinput(c[i], tp)) {
2efb75f3 241 lwkt_reltoken(&tp->t_token);
984263bc 242 return (EIO);
22ff886e 243 }
984263bc
MD
244 }
245 }
2efb75f3 246 lwkt_reltoken(&tp->t_token);
984263bc
MD
247 return (0);
248}
249
250
251static int
fef8985e 252snpread(struct dev_read_args *ap)
984263bc 253{
b13267a5 254 cdev_t dev = ap->a_head.a_dev;
fef8985e 255 struct uio *uio = ap->a_uio;
984263bc 256 struct snoop *snp;
2efb75f3 257 struct tty *tp;
12cc2857 258 int error, len, n, nblen;
984263bc
MD
259 caddr_t from;
260 char *nbuf;
261
262 snp = dev->si_drv1;
2efb75f3
MD
263 tp = snp->snp_tty;
264 lwkt_gettoken(&tp->t_token);
984263bc
MD
265 KASSERT(snp->snp_len + snp->snp_base <= snp->snp_blen,
266 ("snoop buffer error"));
267
22ff886e 268 if (snp->snp_tty == NULL) {
2efb75f3 269 lwkt_reltoken(&tp->t_token);
984263bc 270 return (EIO);
22ff886e 271 }
984263bc
MD
272
273 snp->snp_flags &= ~SNOOP_RWAIT;
274
275 do {
276 if (snp->snp_len == 0) {
22ff886e 277 if (ap->a_ioflag & IO_NDELAY) {
2efb75f3 278 lwkt_reltoken(&tp->t_token);
984263bc 279 return (EWOULDBLOCK);
22ff886e 280 }
984263bc 281 snp->snp_flags |= SNOOP_RWAIT;
377d4740 282 error = tsleep((caddr_t)snp, PCATCH, "snprd", 0);
22ff886e 283 if (error != 0) {
2efb75f3 284 lwkt_reltoken(&tp->t_token);
984263bc 285 return (error);
22ff886e 286 }
984263bc
MD
287 }
288 } while (snp->snp_len == 0);
289
290 n = snp->snp_len;
291
292 error = 0;
293 while (snp->snp_len > 0 && uio->uio_resid > 0 && error == 0) {
e54488bb 294 len = (int)szmin(uio->uio_resid, snp->snp_len);
984263bc
MD
295 from = (caddr_t)(snp->snp_buf + snp->snp_base);
296 if (len == 0)
297 break;
298
e54488bb 299 error = uiomove(from, (size_t)len, uio);
984263bc
MD
300 snp->snp_base += len;
301 snp->snp_len -= len;
302 }
303 if ((snp->snp_flags & SNOOP_OFLOW) && (n < snp->snp_len)) {
304 snp->snp_flags &= ~SNOOP_OFLOW;
305 }
984263bc
MD
306 nblen = snp->snp_blen;
307 if (((nblen / 2) >= SNOOP_MINLEN) && (nblen / 2) >= snp->snp_len) {
308 while (nblen / 2 >= snp->snp_len && nblen / 2 >= SNOOP_MINLEN)
309 nblen = nblen / 2;
efda3bd0 310 if ((nbuf = kmalloc(nblen, M_SNP, M_NOWAIT)) != NULL) {
984263bc 311 bcopy(snp->snp_buf + snp->snp_base, nbuf, snp->snp_len);
efda3bd0 312 kfree(snp->snp_buf, M_SNP);
984263bc
MD
313 snp->snp_buf = nbuf;
314 snp->snp_blen = nblen;
315 snp->snp_base = 0;
316 }
317 }
2efb75f3 318 lwkt_reltoken(&tp->t_token);
984263bc
MD
319
320 return (error);
321}
322
22ff886e 323/*
2efb75f3 324 * NOTE: Must be called with tp->t_token held
22ff886e 325 */
984263bc 326static int
c436375a 327snp_in(struct snoop *snp, char *buf, int n)
984263bc
MD
328{
329 int s_free, s_tail;
12cc2857 330 int len, nblen;
984263bc
MD
331 caddr_t from, to;
332 char *nbuf;
333
334 KASSERT(n >= 0, ("negative snoop char count"));
335
336 if (n == 0)
337 return (0);
338
339 if (snp->snp_flags & SNOOP_DOWN) {
e3869ec7 340 kprintf("Snoop: more data to down interface.\n");
984263bc
MD
341 return (0);
342 }
343
344 if (snp->snp_flags & SNOOP_OFLOW) {
e3869ec7 345 kprintf("Snoop: buffer overflow.\n");
984263bc
MD
346 /*
347 * On overflow we just repeat the standart close
348 * procedure...yes , this is waste of space but.. Then next
349 * read from device will fail if one would recall he is
350 * snooping and retry...
351 */
352
353 return (snp_down(snp));
354 }
355 s_tail = snp->snp_blen - (snp->snp_len + snp->snp_base);
356 s_free = snp->snp_blen - snp->snp_len;
357
358
359 if (n > s_free) {
984263bc
MD
360 nblen = snp->snp_blen;
361 while ((n > s_free) && ((nblen * 2) <= SNOOP_MAXLEN)) {
362 nblen = snp->snp_blen * 2;
363 s_free = nblen - (snp->snp_len + snp->snp_base);
364 }
efda3bd0 365 if ((n <= s_free) && (nbuf = kmalloc(nblen, M_SNP, M_NOWAIT))) {
984263bc 366 bcopy(snp->snp_buf + snp->snp_base, nbuf, snp->snp_len);
efda3bd0 367 kfree(snp->snp_buf, M_SNP);
984263bc
MD
368 snp->snp_buf = nbuf;
369 snp->snp_blen = nblen;
370 snp->snp_base = 0;
371 } else {
372 snp->snp_flags |= SNOOP_OFLOW;
373 if (snp->snp_flags & SNOOP_RWAIT) {
374 snp->snp_flags &= ~SNOOP_RWAIT;
375 wakeup((caddr_t)snp);
376 }
984263bc
MD
377 return (0);
378 }
984263bc
MD
379 }
380 if (n > s_tail) {
381 from = (caddr_t)(snp->snp_buf + snp->snp_base);
382 to = (caddr_t)(snp->snp_buf);
383 len = snp->snp_len;
384 bcopy(from, to, len);
385 snp->snp_base = 0;
386 }
387 to = (caddr_t)(snp->snp_buf + snp->snp_base + snp->snp_len);
388 bcopy(buf, to, n);
389 snp->snp_len += n;
390
391 if (snp->snp_flags & SNOOP_RWAIT) {
392 snp->snp_flags &= ~SNOOP_RWAIT;
393 wakeup((caddr_t)snp);
394 }
5b22f1a7 395 KNOTE(&snp->snp_kq.ki_note, 0);
984263bc
MD
396
397 return (n);
398}
399
400static int
fef8985e 401snpopen(struct dev_open_args *ap)
984263bc 402{
b13267a5 403 cdev_t dev = ap->a_head.a_dev;
984263bc
MD
404 struct snoop *snp;
405
2efb75f3 406 lwkt_gettoken(&snp_token);
984263bc 407 if (dev->si_drv1 == NULL) {
8be7edad 408#if 0
fef8985e 409 make_dev(&snp_ops, minor(dev), UID_ROOT, GID_WHEEL,
984263bc 410 0600, "snp%d", minor(dev));
8be7edad 411#endif
efda3bd0 412 dev->si_drv1 = snp = kmalloc(sizeof(*snp), M_SNP,
2efb75f3 413 M_WAITOK | M_ZERO);
e4c9c0c8 414 } else {
2efb75f3 415 lwkt_reltoken(&snp_token);
984263bc 416 return (EBUSY);
e4c9c0c8 417 }
984263bc
MD
418
419 /*
420 * We intentionally do not OR flags with SNOOP_OPEN, but set them so
421 * all previous settings (especially SNOOP_OFLOW) will be cleared.
422 */
423 snp->snp_flags = SNOOP_OPEN;
424
efda3bd0 425 snp->snp_buf = kmalloc(SNOOP_MINLEN, M_SNP, M_WAITOK);
984263bc
MD
426 snp->snp_blen = SNOOP_MINLEN;
427 snp->snp_base = 0;
428 snp->snp_len = 0;
429
430 /*
431 * snp_tty == NULL is for inactive snoop devices.
432 */
433 snp->snp_tty = NULL;
028066b1 434 snp->snp_target = NULL;
984263bc
MD
435
436 LIST_INSERT_HEAD(&snp_sclist, snp, snp_list);
2efb75f3 437 lwkt_reltoken(&snp_token);
984263bc
MD
438 return (0);
439}
440
22ff886e 441/*
2efb75f3 442 * NOTE: Must be called with snp_token held
22ff886e 443 */
984263bc 444static int
c436375a 445snp_detach(struct snoop *snp)
984263bc
MD
446{
447 struct tty *tp;
448
2efb75f3 449 ASSERT_LWKT_TOKEN_HELD(&snp_token);
984263bc
MD
450 snp->snp_base = 0;
451 snp->snp_len = 0;
452
453 /*
454 * If line disc. changed we do not touch this pointer, SLIP/PPP will
455 * change it anyway.
456 */
457 tp = snp->snp_tty;
458 if (tp == NULL)
459 goto detach_notty;
460
2efb75f3
MD
461 lwkt_gettoken(&tp->t_token);
462 if ((tp->t_sc == snp) && (tp->t_state & TS_SNOOP) &&
984263bc
MD
463 tp->t_line == snooplinedisc) {
464 tp->t_sc = NULL;
465 tp->t_state &= ~TS_SNOOP;
466 tp->t_line = snp->snp_olddisc;
2efb75f3 467 } else {
e3869ec7 468 kprintf("Snoop: bad attached tty data.\n");
2efb75f3
MD
469 }
470 lwkt_reltoken(&tp->t_token);
984263bc
MD
471
472 snp->snp_tty = NULL;
028066b1 473 snp->snp_target = NULL;
984263bc
MD
474
475detach_notty:
5b22f1a7 476 KNOTE(&snp->snp_kq.ki_note, 0);
984263bc 477 if ((snp->snp_flags & SNOOP_OPEN) == 0)
efda3bd0 478 kfree(snp, M_SNP);
984263bc
MD
479
480 return (0);
481}
482
483static int
fef8985e 484snpclose(struct dev_close_args *ap)
984263bc 485{
b13267a5 486 cdev_t dev = ap->a_head.a_dev;
984263bc 487 struct snoop *snp;
22ff886e 488 int ret;
984263bc 489
2efb75f3 490 lwkt_gettoken(&snp_token);
984263bc
MD
491 snp = dev->si_drv1;
492 snp->snp_blen = 0;
493 LIST_REMOVE(snp, snp_list);
efda3bd0 494 kfree(snp->snp_buf, M_SNP);
984263bc
MD
495 snp->snp_flags &= ~SNOOP_OPEN;
496 dev->si_drv1 = NULL;
8be7edad
MD
497 if (dev->si_uminor >= SNP_PREALLOCATED_UNITS) {
498 devfs_clone_bitmap_put(&DEVFS_CLONE_BITMAP(snp), dev->si_uminor);
499 destroy_dev(dev);
500 }
22ff886e 501 ret = snp_detach(snp);
2efb75f3 502 lwkt_reltoken(&snp_token);
22ff886e 503 return ret;
984263bc
MD
504}
505
22ff886e 506/*
2efb75f3 507 * NOTE: Must be called with snp_token held
22ff886e 508 */
984263bc 509static int
c436375a 510snp_down(struct snoop *snp)
984263bc 511{
2efb75f3 512 ASSERT_LWKT_TOKEN_HELD(&snp_token);
984263bc 513 if (snp->snp_blen != SNOOP_MINLEN) {
efda3bd0
MD
514 kfree(snp->snp_buf, M_SNP);
515 snp->snp_buf = kmalloc(SNOOP_MINLEN, M_SNP, M_WAITOK);
984263bc
MD
516 snp->snp_blen = SNOOP_MINLEN;
517 }
518 snp->snp_flags |= SNOOP_DOWN;
519
520 return (snp_detach(snp));
521}
522
523static int
fef8985e 524snpioctl(struct dev_ioctl_args *ap)
984263bc 525{
b13267a5 526 cdev_t dev = ap->a_head.a_dev;
984263bc
MD
527 struct snoop *snp;
528 struct tty *tp, *tpo;
b13267a5 529 cdev_t tdev;
22ff886e 530 int ret;
984263bc 531
2efb75f3 532 lwkt_gettoken(&snp_token);
984263bc 533 snp = dev->si_drv1;
2efb75f3 534
fef8985e 535 switch (ap->a_cmd) {
984263bc 536 case SNPSTTY:
fef8985e 537 tdev = udev2dev(*((udev_t *)ap->a_data), 0);
22ff886e 538 if (tdev == NULL) {
2efb75f3 539 lwkt_reltoken(&snp_token);
22ff886e
AH
540 ret = snp_down(snp);
541 return ret;
542 }
984263bc
MD
543
544 tp = snpdevtotty(tdev);
22ff886e 545 if (!tp) {
2efb75f3 546 lwkt_reltoken(&snp_token);
984263bc 547 return (EINVAL);
22ff886e 548 }
2efb75f3 549 lwkt_gettoken(&tp->t_token);
22ff886e 550 if (tp->t_state & TS_SNOOP) {
2efb75f3
MD
551 lwkt_reltoken(&tp->t_token);
552 lwkt_reltoken(&snp_token);
984263bc 553 return (EBUSY);
22ff886e 554 }
984263bc 555
028066b1 556 if (snp->snp_target == NULL) {
984263bc
MD
557 tpo = snp->snp_tty;
558 if (tpo)
559 tpo->t_state &= ~TS_SNOOP;
560 }
561
562 tp->t_sc = (caddr_t)snp;
563 tp->t_state |= TS_SNOOP;
564 snp->snp_olddisc = tp->t_line;
565 tp->t_line = snooplinedisc;
566 snp->snp_tty = tp;
567 snp->snp_target = tdev;
568
569 /*
570 * Clean overflow and down flags -
571 * we'll have a chance to get them in the future :)))
572 */
573 snp->snp_flags &= ~SNOOP_OFLOW;
574 snp->snp_flags &= ~SNOOP_DOWN;
2efb75f3 575 lwkt_reltoken(&tp->t_token);
984263bc
MD
576 break;
577
578 case SNPGTTY:
579 /*
580 * We keep snp_target field specially to make
581 * SNPGTTY happy, else we can't know what is device
582 * major/minor for tty.
583 */
b13267a5 584 *((cdev_t *)ap->a_data) = snp->snp_target;
984263bc
MD
585 break;
586
984263bc 587 case FIOASYNC:
fef8985e 588 if (*(int *)ap->a_data)
984263bc
MD
589 snp->snp_flags |= SNOOP_ASYNC;
590 else
591 snp->snp_flags &= ~SNOOP_ASYNC;
592 break;
593
594 case FIONREAD:
2efb75f3 595 if (snp->snp_tty != NULL) {
fef8985e 596 *(int *)ap->a_data = snp->snp_len;
2efb75f3 597 } else {
984263bc
MD
598 if (snp->snp_flags & SNOOP_DOWN) {
599 if (snp->snp_flags & SNOOP_OFLOW)
fef8985e 600 *(int *)ap->a_data = SNP_OFLOW;
984263bc 601 else
fef8985e 602 *(int *)ap->a_data = SNP_TTYCLOSE;
984263bc 603 } else {
fef8985e 604 *(int *)ap->a_data = SNP_DETACH;
984263bc 605 }
2efb75f3 606 }
984263bc
MD
607 break;
608
609 default:
2efb75f3 610 lwkt_reltoken(&snp_token);
984263bc
MD
611 return (ENOTTY);
612 }
2efb75f3
MD
613 lwkt_reltoken(&snp_token);
614
984263bc
MD
615 return (0);
616}
617
163625b9 618static struct filterops snpfiltops_rd =
4c91dbc9 619 { FILTEROP_ISFD, NULL, snpfilter_detach, snpfilter_rd };
163625b9 620static struct filterops snpfiltops_wr =
4c91dbc9 621 { FILTEROP_ISFD, NULL, snpfilter_detach, snpfilter_wr };
5d7a9a94
SG
622
623static int
624snpkqfilter(struct dev_kqfilter_args *ap)
625{
626 cdev_t dev = ap->a_head.a_dev;
627 struct snoop *snp = dev->si_drv1;
628 struct knote *kn = ap->a_kn;
629 struct klist *klist;
2efb75f3 630 struct tty *tp = snp->snp_tty;
5d7a9a94 631
2efb75f3 632 lwkt_gettoken(&tp->t_token);
5d7a9a94
SG
633 ap->a_result = 0;
634
635 switch (kn->kn_filter) {
636 case EVFILT_READ:
163625b9
SG
637 kn->kn_fop = &snpfiltops_rd;
638 kn->kn_hook = (caddr_t)snp;
639 break;
640 case EVFILT_WRITE:
641 kn->kn_fop = &snpfiltops_wr;
5d7a9a94
SG
642 kn->kn_hook = (caddr_t)snp;
643 break;
644 default:
b287d649 645 ap->a_result = EOPNOTSUPP;
2efb75f3 646 lwkt_reltoken(&tp->t_token);
5d7a9a94
SG
647 return (0);
648 }
649
5b22f1a7
SG
650 klist = &snp->snp_kq.ki_note;
651 knote_insert(klist, kn);
2efb75f3 652 lwkt_reltoken(&tp->t_token);
5d7a9a94
SG
653
654 return (0);
655}
656
657static void
658snpfilter_detach(struct knote *kn)
659{
660 struct snoop *snp = (struct snoop *)kn->kn_hook;
661 struct klist *klist;
662
5b22f1a7 663 klist = &snp->snp_kq.ki_note;
156756e7 664 knote_remove(klist, kn);
5d7a9a94
SG
665}
666
667static int
163625b9 668snpfilter_rd(struct knote *kn, long hint)
5d7a9a94
SG
669{
670 struct snoop *snp = (struct snoop *)kn->kn_hook;
2efb75f3 671 struct tty *tp = snp->snp_tty;
5d7a9a94
SG
672 int ready = 0;
673
2efb75f3 674 lwkt_gettoken(&tp->t_token);
5d7a9a94
SG
675 /*
676 * If snoop is down, we don't want to poll forever so we return 1.
677 * Caller should see if we down via FIONREAD ioctl(). The last should
678 * return -1 to indicate down state.
679 */
680 if (snp->snp_flags & SNOOP_DOWN || snp->snp_len > 0)
681 ready = 1;
2efb75f3 682 lwkt_reltoken(&tp->t_token);
5d7a9a94
SG
683
684 return (ready);
685}
686
163625b9
SG
687static int
688snpfilter_wr(struct knote *kn, long hint)
689{
690 /* Writing is always OK */
691 return (1);
692}
693
8be7edad
MD
694static int
695snpclone(struct dev_clone_args *ap)
696{
697 int unit;
2efb75f3
MD
698
699 lwkt_gettoken(&snp_token);
8be7edad
MD
700 unit = devfs_clone_bitmap_get(&DEVFS_CLONE_BITMAP(snp), 0);
701 ap->a_dev = make_only_dev(&snp_ops, unit, UID_ROOT, GID_WHEEL, 0600,
2efb75f3
MD
702 "snp%d", unit);
703 lwkt_reltoken(&snp_token);
704
8be7edad
MD
705 return 0;
706}
707
984263bc 708static int
c436375a 709snp_modevent(module_t mod, int type, void *data)
984263bc 710{
8be7edad 711 int i;
984263bc 712
2efb75f3
MD
713 lwkt_gettoken(&snp_token);
714
984263bc
MD
715 switch (type) {
716 case MOD_LOAD:
717 snooplinedisc = ldisc_register(LDISC_LOAD, &snpdisc);
b96f3782
AH
718 make_autoclone_dev(&snp_ops, &DEVFS_CLONE_BITMAP(snp),
719 snpclone, UID_ROOT, GID_WHEEL, 0600, "snp");
8be7edad
MD
720
721 for (i = 0; i < SNP_PREALLOCATED_UNITS; i++) {
722 make_dev(&snp_ops, i, UID_ROOT, GID_WHEEL, 0600, "snp%d", i);
723 devfs_clone_bitmap_set(&DEVFS_CLONE_BITMAP(snp), i);
724 }
984263bc
MD
725 break;
726 case MOD_UNLOAD:
1013402d 727 if (!LIST_EMPTY(&snp_sclist)) {
2efb75f3 728 lwkt_reltoken(&snp_token);
984263bc 729 return (EBUSY);
1013402d 730 }
984263bc 731 ldisc_deregister(snooplinedisc);
8be7edad 732 devfs_clone_handler_del("snp");
cd29885a 733 dev_ops_remove_all(&snp_ops);
8be7edad 734 devfs_clone_bitmap_uninit(&DEVFS_CLONE_BITMAP(snp));
984263bc
MD
735 break;
736 default:
737 break;
738 }
2efb75f3
MD
739 lwkt_reltoken(&snp_token);
740
984263bc
MD
741 return (0);
742}
743
744static moduledata_t snp_mod = {
745 "snp",
746 snp_modevent,
747 NULL
748};
88abd8b5 749DECLARE_MODULE(snp, snp_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);