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