xref: /dragonfly/sys/dev/misc/snp/snp.c (revision 2ac7d1050a3c50c16d77203ac6ed01a65757e5b0)
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