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