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
snplclose(struct tty * tp,int flag)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
snplwrite(struct tty * tp,struct uio * uio,int flag)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 *
snpdevtotty(cdev_t dev)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
snpwrite(struct dev_write_args * ap)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
snpread(struct dev_read_args * ap)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
snp_in(struct snoop * snp,char * buf,int n)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
snpopen(struct dev_open_args * ap)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
snp_detach(struct snoop * snp)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
snpclose(struct dev_close_args * ap)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
snp_down(struct snoop * snp)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
snpioctl(struct dev_ioctl_args * ap)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
snpkqfilter(struct dev_kqfilter_args * ap)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
snpfilter_detach(struct knote * kn)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
snpfilter_rd(struct knote * kn,long hint)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
snpfilter_wr(struct knote * kn,long hint)692 snpfilter_wr(struct knote *kn, long hint)
693 {
694 /* Writing is always OK */
695 return (1);
696 }
697
698 static int
snpclone(struct dev_clone_args * ap)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
snp_modevent(module_t mod,int type,void * data)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