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