]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/kern/tty_snoop.c
Remove five now unused fields from struct cdevsw. They should never
[FreeBSD/FreeBSD.git] / sys / kern / tty_snoop.c
1 /*
2  * Copyright (c) 1995 Ugen J.S.Antsilevich
3  *
4  * Redistribution and use in source forms, with and without modification,
5  * are permitted provided that this entire comment appears intact.
6  *
7  * Redistribution in binary form may occur without any restrictions.
8  * Obviously, it would be nice if you gave credit where credit is due
9  * but requiring it would be too onerous.
10  *
11  * This software is provided ``AS IS'' without any warranties of any kind.
12  *
13  * Snoop stuff.
14  *
15  * $FreeBSD$
16  */
17
18 #include "snp.h"
19
20 #if NSNP > 0
21
22 #include "opt_compat.h"
23 #include <sys/param.h>
24 #include <sys/systm.h>
25 #include <sys/filio.h>
26 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
27 #include <sys/ioctl_compat.h>
28 #endif
29 #include <sys/proc.h>
30 #include <sys/malloc.h>
31 #include <sys/tty.h>
32 #include <sys/conf.h>
33 #include <sys/poll.h>
34 #include <sys/kernel.h>
35 #include <sys/snoop.h>
36 #include <sys/vnode.h>
37
38 static  d_open_t        snpopen;
39 static  d_close_t       snpclose;
40 static  d_read_t        snpread;
41 static  d_write_t       snpwrite;
42 static  d_ioctl_t       snpioctl;
43 static  d_poll_t        snppoll;
44
45 #define CDEV_MAJOR 53
46 static struct cdevsw snp_cdevsw = {
47         /* open */      snpopen,
48         /* close */     snpclose,
49         /* read */      snpread,
50         /* write */     snpwrite,
51         /* ioctl */     snpioctl,
52         /* poll */      snppoll,
53         /* mmap */      nommap,
54         /* strategy */  nostrategy,
55         /* name */      "snp",
56         /* maj */       CDEV_MAJOR,
57         /* dump */      nodump,
58         /* psize */     nopsize,
59         /* flags */     0,
60         /* bmaj */      -1
61 };
62
63
64 #ifndef MIN
65 #define MIN(a,b) (((a)<(b))?(a):(b))
66 #endif
67
68 static struct snoop snoopsw[NSNP];
69
70 static struct tty       *snpdevtotty __P((dev_t dev));
71 static int              snp_detach __P((struct snoop *snp));
72
73 static struct tty *
74 snpdevtotty (dev)
75         dev_t           dev;
76 {
77         struct cdevsw   *cdp;
78
79         cdp = devsw(dev);
80         if (cdp && cdp->d_flags & D_TTY)
81                 return (dev->si_tty);
82         return (NULL);
83 }
84
85 #define SNP_INPUT_BUF   5       /* This is even too  much,the maximal
86                                  * interactive mode write is 3 bytes
87                                  * length for function keys...
88                                  */
89
90 static  int
91 snpwrite(dev, uio, flag)
92         dev_t           dev;
93         struct uio     *uio;
94         int             flag;
95 {
96         int             unit = minor(dev), len, i, error;
97         struct snoop   *snp = &snoopsw[unit];
98         struct tty     *tp;
99         char            c[SNP_INPUT_BUF];
100
101         if (snp->snp_tty == NULL)
102                 return (EIO);
103
104         tp = snp->snp_tty;
105
106         if ((tp->t_sc == snp) && (tp->t_state & TS_SNOOP) &&
107             (tp->t_line == OTTYDISC || tp->t_line == NTTYDISC))
108                 goto tty_input;
109
110         printf("Snoop: attempt to write to bad tty.\n");
111         return (EIO);
112
113 tty_input:
114         if (!(tp->t_state & TS_ISOPEN))
115                 return (EIO);
116
117         while (uio->uio_resid > 0) {
118                 len = MIN(uio->uio_resid,SNP_INPUT_BUF);
119                 if ((error = uiomove(c, len, uio)) != 0)
120                         return (error);
121                 for (i=0;i<len;i++) {
122                         if (ttyinput(c[i] , tp))
123                                 return (EIO);
124                 }
125         }
126         return 0;
127
128 }
129
130
131 static  int
132 snpread(dev, uio, flag)
133         dev_t           dev;
134         struct uio     *uio;
135         int             flag;
136 {
137         int             unit = minor(dev), s;
138         struct snoop   *snp = &snoopsw[unit];
139         int             len, n, nblen, error = 0;
140         caddr_t         from;
141         char           *nbuf;
142
143         KASSERT(snp->snp_len + snp->snp_base <= snp->snp_blen,
144             ("snoop buffer error"));
145
146         if (snp->snp_tty == NULL)
147                 return (EIO);
148
149         snp->snp_flags &= ~SNOOP_RWAIT;
150
151         do {
152                 if (snp->snp_len == 0) {
153                         if (flag & IO_NDELAY)
154                                 return (EWOULDBLOCK);
155                         snp->snp_flags |= SNOOP_RWAIT;
156                         tsleep((caddr_t) snp, (PZERO + 1) | PCATCH, "snoopread", 0);
157                 }
158         } while (snp->snp_len == 0);
159
160         n = snp->snp_len;
161
162         while (snp->snp_len > 0 && uio->uio_resid > 0 && error == 0) {
163                 len = MIN(uio->uio_resid, snp->snp_len);
164                 from = (caddr_t) (snp->snp_buf + snp->snp_base);
165                 if (len == 0)
166                         break;
167
168                 error = uiomove(from, len, uio);
169                 snp->snp_base += len;
170                 snp->snp_len -= len;
171         }
172         if ((snp->snp_flags & SNOOP_OFLOW) && (n < snp->snp_len)) {
173                 snp->snp_flags &= ~SNOOP_OFLOW;
174         }
175         s = spltty();
176         nblen = snp->snp_blen;
177         if (((nblen / 2) >= SNOOP_MINLEN) && (nblen / 2) >= snp->snp_len) {
178                 while (((nblen / 2) >= snp->snp_len) && ((nblen / 2) >= SNOOP_MINLEN))
179                         nblen = nblen / 2;
180                 if ((nbuf = malloc(nblen, M_TTYS, M_NOWAIT)) != NULL) {
181                         bcopy(snp->snp_buf + snp->snp_base, nbuf, snp->snp_len);
182                         free(snp->snp_buf, M_TTYS);
183                         snp->snp_buf = nbuf;
184                         snp->snp_blen = nblen;
185                         snp->snp_base = 0;
186                 }
187         }
188         splx(s);
189
190         return error;
191 }
192
193 int
194 snpinc(struct snoop *snp, char c)
195 {
196         char    buf[1];
197
198         buf[0]=c;
199         return (snpin(snp,buf,1));
200 }
201
202
203 int
204 snpin(snp, buf, n)
205         struct snoop   *snp;
206         char           *buf;
207         int             n;
208 {
209         int             s_free, s_tail;
210         int             s, len, nblen;
211         caddr_t         from, to;
212         char           *nbuf;
213
214         KASSERT(n >= 0, ("negative snoop char count"));
215
216         if (n == 0)
217                 return 0;
218
219 #ifdef DIAGNOSTIC
220         if (!(snp->snp_flags & SNOOP_OPEN)) {
221                 printf("Snoop: data coming to closed device.\n");
222                 return 0;
223         }
224 #endif
225         if (snp->snp_flags & SNOOP_DOWN) {
226                 printf("Snoop: more data to down interface.\n");
227                 return 0;
228         }
229
230         if (snp->snp_flags & SNOOP_OFLOW) {
231                 printf("Snoop: buffer overflow.\n");
232                 /*
233                  * On overflow we just repeat the standart close
234                  * procedure...yes , this is waste of space but.. Then next
235                  * read from device will fail if one would recall he is
236                  * snooping and retry...
237                  */
238
239                 return (snpdown(snp));
240         }
241         s_tail = snp->snp_blen - (snp->snp_len + snp->snp_base);
242         s_free = snp->snp_blen - snp->snp_len;
243
244
245         if (n > s_free) {
246                 s = spltty();
247                 nblen = snp->snp_blen;
248                 while ((n > s_free) && ((nblen * 2) <= SNOOP_MAXLEN)) {
249                         nblen = snp->snp_blen * 2;
250                         s_free = nblen - (snp->snp_len + snp->snp_base);
251                 }
252                 if ((n <= s_free) && (nbuf = malloc(nblen, M_TTYS, M_NOWAIT))) {
253                         bcopy(snp->snp_buf + snp->snp_base, nbuf, snp->snp_len);
254                         free(snp->snp_buf, M_TTYS);
255                         snp->snp_buf = nbuf;
256                         snp->snp_blen = nblen;
257                         snp->snp_base = 0;
258                 } else {
259                         snp->snp_flags |= SNOOP_OFLOW;
260                         if (snp->snp_flags & SNOOP_RWAIT) {
261                                 snp->snp_flags &= ~SNOOP_RWAIT;
262                                 wakeup((caddr_t) snp);
263                         }
264                         splx(s);
265                         return 0;
266                 }
267                 splx(s);
268         }
269         if (n > s_tail) {
270                 from = (caddr_t) (snp->snp_buf + snp->snp_base);
271                 to = (caddr_t) (snp->snp_buf);
272                 len = snp->snp_len;
273                 bcopy(from, to, len);
274                 snp->snp_base = 0;
275         }
276         to = (caddr_t) (snp->snp_buf + snp->snp_base + snp->snp_len);
277         bcopy(buf, to, n);
278         snp->snp_len += n;
279
280         if (snp->snp_flags & SNOOP_RWAIT) {
281                 snp->snp_flags &= ~SNOOP_RWAIT;
282                 wakeup((caddr_t) snp);
283         }
284         selwakeup(&snp->snp_sel);
285         snp->snp_sel.si_pid = 0;
286
287         return n;
288 }
289
290 static  int
291 snpopen(dev, flag, mode, p)
292         dev_t           dev;
293         int             flag, mode;
294         struct proc    *p;
295 {
296         struct snoop   *snp;
297         register int    unit, error;
298
299         if ((error = suser(p)) != 0)
300                 return (error);
301
302         if ((unit = minor(dev)) >= NSNP)
303                 return (ENXIO);
304
305         snp = &snoopsw[unit];
306
307         if (snp->snp_flags & SNOOP_OPEN)
308                 return (ENXIO);
309
310         /*
311          * We intentionally do not OR flags with SNOOP_OPEN,but set them so
312          * all previous settings (especially SNOOP_OFLOW) will be cleared.
313          */
314         snp->snp_flags = SNOOP_OPEN;
315
316         snp->snp_buf = malloc(SNOOP_MINLEN, M_TTYS, M_WAITOK);
317         snp->snp_blen = SNOOP_MINLEN;
318         snp->snp_base = 0;
319         snp->snp_len = 0;
320
321         /*
322          * snp_tty == NULL  is for inactive snoop devices.
323          */
324         snp->snp_tty = NULL;
325         snp->snp_target = NODEV;
326         return (0);
327 }
328
329
330 static int
331 snp_detach(snp)
332         struct snoop   *snp;
333 {
334         struct tty     *tp;
335
336         snp->snp_base = 0;
337         snp->snp_len = 0;
338
339         /*
340          * If line disc. changed we do not touch this pointer,SLIP/PPP will
341          * change it anyway.
342          */
343
344         if (snp->snp_tty == NULL)
345                 goto detach_notty;
346
347         tp = snp->snp_tty;
348
349         if (tp && (tp->t_sc == snp) && (tp->t_state & TS_SNOOP) &&
350             (tp->t_line == OTTYDISC || tp->t_line == NTTYDISC)) {
351                 tp->t_sc = NULL;
352                 tp->t_state &= ~TS_SNOOP;
353         } else
354                 printf("Snoop: bad attached tty data.\n");
355
356         snp->snp_tty = NULL;
357         snp->snp_target = NODEV;
358
359 detach_notty:
360         selwakeup(&snp->snp_sel);
361         snp->snp_sel.si_pid = 0;
362
363         return (0);
364 }
365
366 static  int
367 snpclose(dev, flags, fmt, p)
368         dev_t           dev;
369         int             flags;
370         int             fmt;
371         struct proc    *p;
372 {
373         register int    unit = minor(dev);
374         struct snoop   *snp = &snoopsw[unit];
375
376         snp->snp_blen = 0;
377         free(snp->snp_buf, M_TTYS);
378         snp->snp_flags &= ~SNOOP_OPEN;
379
380         return (snp_detach(snp));
381 }
382
383 int
384 snpdown(snp)
385         struct snoop    *snp;
386 {
387         snp->snp_blen = SNOOP_MINLEN;
388         free(snp->snp_buf, M_TTYS);
389         snp->snp_buf = malloc(SNOOP_MINLEN, M_TTYS, M_WAITOK);
390         snp->snp_flags |= SNOOP_DOWN;
391
392         return (snp_detach(snp));
393 }
394
395
396 static  int
397 snpioctl(dev, cmd, data, flags, p)
398         dev_t           dev;
399         u_long          cmd;
400         caddr_t         data;
401         int             flags;
402         struct proc    *p;
403 {
404         int             unit = minor(dev), s;
405         dev_t           tdev;
406         struct snoop   *snp = &snoopsw[unit];
407         struct tty     *tp, *tpo;
408
409         switch (cmd) {
410         case SNPSTTY:
411                 tdev = udev2dev(*((udev_t *) data), 0);
412                 if (tdev == NODEV)
413                         return (snpdown(snp));
414
415                 tp = snpdevtotty(tdev);
416                 if (!tp)
417                         return (EINVAL);
418
419                 if ((tp->t_sc != (caddr_t) snp) && (tp->t_state & TS_SNOOP))
420                         return (EBUSY);
421
422                 if ((tp->t_line != OTTYDISC) && (tp->t_line != NTTYDISC))
423                         return (EBUSY);
424
425                 s = spltty();
426
427                 if (snp->snp_target == NODEV) {
428                         tpo = snp->snp_tty;
429                         if (tpo)
430                                 tpo->t_state &= ~TS_SNOOP;
431                 }
432
433                 tp->t_sc = (caddr_t) snp;
434                 tp->t_state |= TS_SNOOP;
435                 snp->snp_tty = tp;
436                 snp->snp_target = tdev;
437
438                 /*
439                  * Clean overflow and down flags -
440                  * we'll have a chance to get them in the future :)))
441                  */
442                 snp->snp_flags &= ~SNOOP_OFLOW;
443                 snp->snp_flags &= ~SNOOP_DOWN;
444                 splx(s);
445                 break;
446
447         case SNPGTTY:
448                 /*
449                  * We keep snp_target field specially to make
450                  * SNPGTTY happy,else we can't know what is device
451                  * major/minor for tty.
452                  */
453                 *((dev_t *) data) = snp->snp_target;
454                 break;
455
456         case FIONBIO:
457                 break;
458
459         case FIOASYNC:
460                 if (*(int *) data)
461                         snp->snp_flags |= SNOOP_ASYNC;
462                 else
463                         snp->snp_flags &= ~SNOOP_ASYNC;
464                 break;
465
466         case FIONREAD:
467                 s = spltty();
468                 if (snp->snp_tty != NULL)
469                         *(int *) data = snp->snp_len;
470                 else
471                         if (snp->snp_flags & SNOOP_DOWN) {
472                                 if (snp->snp_flags & SNOOP_OFLOW)
473                                         *(int *) data = SNP_OFLOW;
474                                 else
475                                         *(int *) data = SNP_TTYCLOSE;
476                         } else {
477                                 *(int *) data = SNP_DETACH;
478                         }
479                 splx(s);
480                 break;
481
482         default:
483                 return (ENOTTY);
484         }
485         return (0);
486 }
487
488
489 static  int
490 snppoll(dev, events, p)
491         dev_t           dev;
492         int             events;
493         struct proc    *p;
494 {
495         int             unit = minor(dev);
496         struct snoop   *snp = &snoopsw[unit];
497         int             revents = 0;
498
499
500         /*
501          * If snoop is down,we don't want to poll() forever so we return 1.
502          * Caller should see if we down via FIONREAD ioctl().The last should
503          * return -1 to indicate down state.
504          */
505         if (events & (POLLIN | POLLRDNORM)) {
506                 if (snp->snp_flags & SNOOP_DOWN || snp->snp_len > 0)
507                         revents |= events & (POLLIN | POLLRDNORM);
508                 else
509                         selrecord(p, &snp->snp_sel);
510         }
511         return (revents);
512 }
513
514 static void snp_drvinit __P((void *unused));
515
516 static void
517 snp_drvinit(unused)
518         void *unused;
519 {
520         int     i;
521
522         cdevsw_add(&snp_cdevsw);
523         for ( i = 0 ; i < NSNP ; i++) 
524                 make_dev(&snp_cdevsw, i, 0, 0, 0600, "snp%d", i);
525 }
526
527 SYSINIT(snpdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,snp_drvinit,NULL)
528
529
530 #endif