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