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