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 17 #include <sys/cdefs.h> 18 __FBSDID("$FreeBSD$"); 19 20 #include <sys/param.h> 21 #include <sys/systm.h> 22 #include <sys/fcntl.h> 23 #include <sys/filio.h> 24 #include <sys/malloc.h> 25 #include <sys/tty.h> 26 #include <sys/conf.h> 27 #include <sys/poll.h> 28 #include <sys/kernel.h> 29 #include <sys/module.h> 30 #include <sys/queue.h> 31 #include <sys/snoop.h> 32 #include <sys/uio.h> 33 #include <sys/file.h> 34 #include <sys/vnode.h> 35 36 static l_close_t snplclose; 37 static l_write_t snplwrite; 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 static struct cdevsw snp_cdevsw = { 46 .d_version = D_VERSION, 47 .d_flags = D_PSEUDO | D_NEEDGIANT, 48 .d_open = snpopen, 49 .d_close = snpclose, 50 .d_read = snpread, 51 .d_write = snpwrite, 52 .d_ioctl = snpioctl, 53 .d_poll = snppoll, 54 .d_name = "snp", 55 }; 56 57 static struct linesw snpdisc = { 58 .l_open = tty_open, 59 .l_close = snplclose, 60 .l_read = ttread, 61 .l_write = snplwrite, 62 .l_ioctl = l_nullioctl, 63 .l_rint = ttyinput, 64 .l_start = ttstart, 65 .l_modem = ttymodem 66 }; 67 68 /* 69 * This is the main snoop per-device structure. 70 */ 71 struct snoop { 72 LIST_ENTRY(snoop) snp_list; /* List glue. */ 73 int snp_unit; /* Device number. */ 74 struct cdev *snp_target; /* Target tty device. */ 75 struct tty *snp_tty; /* Target tty pointer. */ 76 u_long snp_len; /* Possible length. */ 77 u_long snp_base; /* Data base. */ 78 u_long snp_blen; /* Used length. */ 79 caddr_t snp_buf; /* Allocation pointer. */ 80 int snp_flags; /* Flags. */ 81 struct selinfo snp_sel; /* Select info. */ 82 int snp_olddisc; /* Old line discipline. */ 83 }; 84 85 /* 86 * Possible flags. 87 */ 88 #define SNOOP_ASYNC 0x0002 89 #define SNOOP_OPEN 0x0004 90 #define SNOOP_RWAIT 0x0008 91 #define SNOOP_OFLOW 0x0010 92 #define SNOOP_DOWN 0x0020 93 94 /* 95 * Other constants. 96 */ 97 #define SNOOP_MINLEN (4*1024) /* This should be power of 2. 98 * 4K tested to be the minimum 99 * for which on normal tty 100 * usage there is no need to 101 * allocate more. 102 */ 103 #define SNOOP_MAXLEN (64*1024) /* This one also,64K enough 104 * If we grow more,something 105 * really bad in this world.. 106 */ 107 108 static MALLOC_DEFINE(M_SNP, "snp", "Snoop device data"); 109 /* 110 * The number of the "snoop" line discipline. This gets determined at 111 * module load time. 112 */ 113 static int snooplinedisc; 114 115 static LIST_HEAD(, snoop) snp_sclist = LIST_HEAD_INITIALIZER(&snp_sclist); 116 static struct clonedevs *snpclones; 117 118 static struct tty *snpdevtotty(struct cdev *dev); 119 static void snp_clone(void *arg, struct ucred *cred, char *name, 120 int namelen, struct cdev **dev); 121 static int snp_detach(struct snoop *snp); 122 static int snp_down(struct snoop *snp); 123 static int snp_in(struct snoop *snp, char *buf, int n); 124 static int snp_modevent(module_t mod, int what, void *arg); 125 static struct snoop *ttytosnp(struct tty *); 126 127 static struct snoop * 128 ttytosnp(struct tty *tp) 129 { 130 struct snoop *snp; 131 132 LIST_FOREACH(snp, &snp_sclist, snp_list) { 133 if (snp->snp_tty == tp) 134 return (snp); 135 } 136 return (NULL); 137 } 138 139 static int 140 snplclose(tp, flag) 141 struct tty *tp; 142 int flag; 143 { 144 struct snoop *snp; 145 int error; 146 147 snp = ttytosnp(tp); 148 error = snp_down(snp); 149 if (error != 0) 150 return (error); 151 error = ttylclose(tp, flag); 152 return (error); 153 } 154 155 static int 156 snplwrite(tp, uio, flag) 157 struct tty *tp; 158 struct uio *uio; 159 int flag; 160 { 161 struct iovec iov; 162 struct uio uio2; 163 struct snoop *snp; 164 int error, ilen; 165 char *ibuf; 166 167 error = 0; 168 ibuf = NULL; 169 snp = ttytosnp(tp); 170 while (uio->uio_resid > 0) { 171 ilen = imin(512, uio->uio_resid); 172 ibuf = malloc(ilen, M_SNP, M_WAITOK); 173 error = uiomove(ibuf, ilen, uio); 174 if (error != 0) 175 break; 176 snp_in(snp, ibuf, ilen); 177 /* Hackish, but probably the least of all evils. */ 178 iov.iov_base = ibuf; 179 iov.iov_len = ilen; 180 uio2.uio_iov = &iov; 181 uio2.uio_iovcnt = 1; 182 uio2.uio_offset = 0; 183 uio2.uio_resid = ilen; 184 uio2.uio_segflg = UIO_SYSSPACE; 185 uio2.uio_rw = UIO_WRITE; 186 uio2.uio_td = uio->uio_td; 187 error = ttwrite(tp, &uio2, flag); 188 if (error != 0) 189 break; 190 free(ibuf, M_SNP); 191 ibuf = NULL; 192 } 193 if (ibuf != NULL) 194 free(ibuf, M_SNP); 195 return (error); 196 } 197 198 static struct tty * 199 snpdevtotty(dev) 200 struct cdev *dev; 201 { 202 struct cdevsw *cdp; 203 struct tty *tp; 204 205 cdp = dev_refthread(dev); 206 if (cdp == NULL) 207 return (NULL); 208 if (!(cdp->d_flags & D_TTY)) 209 tp = NULL; 210 else 211 tp = dev->si_tty; 212 dev_relthread(dev); 213 return (tp); 214 } 215 216 #define SNP_INPUT_BUF 5 /* This is even too much, the maximal 217 * interactive mode write is 3 bytes 218 * length for function keys... 219 */ 220 221 static int 222 snpwrite(dev, uio, flag) 223 struct cdev *dev; 224 struct uio *uio; 225 int flag; 226 { 227 struct snoop *snp; 228 struct tty *tp; 229 int error, i, len; 230 unsigned char c[SNP_INPUT_BUF]; 231 232 snp = dev->si_drv1; 233 tp = snp->snp_tty; 234 if (tp == NULL) 235 return (EIO); 236 if ((tp->t_state & TS_SNOOP) && tp->t_line == snooplinedisc) 237 goto tty_input; 238 239 printf("snp%d: attempt to write to bad tty\n", snp->snp_unit); 240 return (EIO); 241 242 tty_input: 243 if (!(tp->t_state & TS_ISOPEN)) 244 return (EIO); 245 246 while (uio->uio_resid > 0) { 247 len = imin(uio->uio_resid, SNP_INPUT_BUF); 248 if ((error = uiomove(c, len, uio)) != 0) 249 return (error); 250 for (i=0; i < len; i++) { 251 if (ttyinput(c[i], tp)) 252 return (EIO); 253 } 254 } 255 return (0); 256 } 257 258 259 static int 260 snpread(dev, uio, flag) 261 struct cdev *dev; 262 struct uio *uio; 263 int flag; 264 { 265 struct snoop *snp; 266 int error, len, n, nblen, s; 267 caddr_t from; 268 char *nbuf; 269 270 snp = dev->si_drv1; 271 KASSERT(snp->snp_len + snp->snp_base <= snp->snp_blen, 272 ("snoop buffer error")); 273 274 if (snp->snp_tty == NULL) 275 return (EIO); 276 277 snp->snp_flags &= ~SNOOP_RWAIT; 278 279 do { 280 if (snp->snp_len == 0) { 281 if (flag & O_NONBLOCK) 282 return (EWOULDBLOCK); 283 snp->snp_flags |= SNOOP_RWAIT; 284 error = tsleep(snp, (PZERO + 1) | PCATCH, 285 "snprd", 0); 286 if (error != 0) 287 return (error); 288 } 289 } while (snp->snp_len == 0); 290 291 n = snp->snp_len; 292 293 error = 0; 294 while (snp->snp_len > 0 && uio->uio_resid > 0 && error == 0) { 295 len = min((unsigned)uio->uio_resid, snp->snp_len); 296 from = (caddr_t)(snp->snp_buf + snp->snp_base); 297 if (len == 0) 298 break; 299 300 error = uiomove(from, len, uio); 301 snp->snp_base += len; 302 snp->snp_len -= len; 303 } 304 if ((snp->snp_flags & SNOOP_OFLOW) && (n < snp->snp_len)) { 305 snp->snp_flags &= ~SNOOP_OFLOW; 306 } 307 s = spltty(); 308 nblen = snp->snp_blen; 309 if (((nblen / 2) >= SNOOP_MINLEN) && (nblen / 2) >= snp->snp_len) { 310 while (nblen / 2 >= snp->snp_len && nblen / 2 >= SNOOP_MINLEN) 311 nblen = nblen / 2; 312 if ((nbuf = malloc(nblen, M_SNP, M_NOWAIT)) != NULL) { 313 bcopy(snp->snp_buf + snp->snp_base, nbuf, snp->snp_len); 314 free(snp->snp_buf, M_SNP); 315 snp->snp_buf = nbuf; 316 snp->snp_blen = nblen; 317 snp->snp_base = 0; 318 } 319 } 320 splx(s); 321 322 return (error); 323 } 324 325 static int 326 snp_in(snp, buf, n) 327 struct snoop *snp; 328 char *buf; 329 int n; 330 { 331 int s_free, s_tail; 332 int s, len, nblen; 333 caddr_t from, to; 334 char *nbuf; 335 336 KASSERT(n >= 0, ("negative snoop char count")); 337 338 if (n == 0) 339 return (0); 340 341 if (snp->snp_flags & SNOOP_DOWN) { 342 printf("snp%d: more data to down interface\n", snp->snp_unit); 343 return (0); 344 } 345 346 if (snp->snp_flags & SNOOP_OFLOW) { 347 printf("snp%d: buffer overflow\n", snp->snp_unit); 348 /* 349 * On overflow we just repeat the standart close 350 * procedure...yes , this is waste of space but.. Then next 351 * read from device will fail if one would recall he is 352 * snooping and retry... 353 */ 354 355 return (snp_down(snp)); 356 } 357 s_tail = snp->snp_blen - (snp->snp_len + snp->snp_base); 358 s_free = snp->snp_blen - snp->snp_len; 359 360 361 if (n > s_free) { 362 s = spltty(); 363 nblen = snp->snp_blen; 364 while ((n > s_free) && ((nblen * 2) <= SNOOP_MAXLEN)) { 365 nblen = snp->snp_blen * 2; 366 s_free = nblen - (snp->snp_len + snp->snp_base); 367 } 368 if ((n <= s_free) && (nbuf = malloc(nblen, M_SNP, M_NOWAIT))) { 369 bcopy(snp->snp_buf + snp->snp_base, nbuf, snp->snp_len); 370 free(snp->snp_buf, M_SNP); 371 snp->snp_buf = nbuf; 372 snp->snp_blen = nblen; 373 snp->snp_base = 0; 374 } else { 375 snp->snp_flags |= SNOOP_OFLOW; 376 if (snp->snp_flags & SNOOP_RWAIT) { 377 snp->snp_flags &= ~SNOOP_RWAIT; 378 wakeup(snp); 379 } 380 splx(s); 381 return (0); 382 } 383 splx(s); 384 } 385 if (n > s_tail) { 386 from = (caddr_t)(snp->snp_buf + snp->snp_base); 387 to = (caddr_t)(snp->snp_buf); 388 len = snp->snp_len; 389 bcopy(from, to, len); 390 snp->snp_base = 0; 391 } 392 to = (caddr_t)(snp->snp_buf + snp->snp_base + snp->snp_len); 393 bcopy(buf, to, n); 394 snp->snp_len += n; 395 396 if (snp->snp_flags & SNOOP_RWAIT) { 397 snp->snp_flags &= ~SNOOP_RWAIT; 398 wakeup(snp); 399 } 400 selwakeuppri(&snp->snp_sel, PZERO + 1); 401 402 return (n); 403 } 404 405 static int 406 snpopen(dev, flag, mode, td) 407 struct cdev *dev; 408 int flag, mode; 409 struct thread *td; 410 { 411 struct snoop *snp; 412 413 if (dev->si_drv1 == NULL) { 414 dev->si_flags &= ~SI_CHEAPCLONE; 415 dev->si_drv1 = snp = malloc(sizeof(*snp), M_SNP, 416 M_WAITOK | M_ZERO); 417 snp->snp_unit = dev2unit(dev); 418 } else 419 return (EBUSY); 420 421 /* 422 * We intentionally do not OR flags with SNOOP_OPEN, but set them so 423 * all previous settings (especially SNOOP_OFLOW) will be cleared. 424 */ 425 snp->snp_flags = SNOOP_OPEN; 426 427 snp->snp_buf = malloc(SNOOP_MINLEN, M_SNP, M_WAITOK); 428 snp->snp_blen = SNOOP_MINLEN; 429 snp->snp_base = 0; 430 snp->snp_len = 0; 431 432 /* 433 * snp_tty == NULL is for inactive snoop devices. 434 */ 435 snp->snp_tty = NULL; 436 snp->snp_target = NULL; 437 438 LIST_INSERT_HEAD(&snp_sclist, snp, snp_list); 439 return (0); 440 } 441 442 443 static int 444 snp_detach(snp) 445 struct snoop *snp; 446 { 447 struct tty *tp; 448 449 snp->snp_base = 0; 450 snp->snp_len = 0; 451 452 /* 453 * If line disc. changed we do not touch this pointer, SLIP/PPP will 454 * change it anyway. 455 */ 456 tp = snp->snp_tty; 457 if (tp == NULL) 458 goto detach_notty; 459 460 if ((tp->t_state & TS_SNOOP) && tp->t_line == snooplinedisc) { 461 tp->t_state &= ~TS_SNOOP; 462 tp->t_line = snp->snp_olddisc; 463 } else 464 printf("snp%d: bad attached tty data\n", snp->snp_unit); 465 466 snp->snp_tty = NULL; 467 snp->snp_target = NULL; 468 469 detach_notty: 470 selwakeuppri(&snp->snp_sel, PZERO + 1); 471 if ((snp->snp_flags & SNOOP_OPEN) == 0) 472 free(snp, M_SNP); 473 474 return (0); 475 } 476 477 static int 478 snpclose(dev, flags, fmt, td) 479 struct cdev *dev; 480 int flags; 481 int fmt; 482 struct thread *td; 483 { 484 struct snoop *snp; 485 486 snp = dev->si_drv1; 487 snp->snp_blen = 0; 488 LIST_REMOVE(snp, snp_list); 489 free(snp->snp_buf, M_SNP); 490 snp->snp_flags &= ~SNOOP_OPEN; 491 dev->si_drv1 = NULL; 492 destroy_dev(dev); 493 494 return (snp_detach(snp)); 495 } 496 497 static int 498 snp_down(snp) 499 struct snoop *snp; 500 { 501 502 if (snp->snp_blen != SNOOP_MINLEN) { 503 free(snp->snp_buf, M_SNP); 504 snp->snp_buf = malloc(SNOOP_MINLEN, M_SNP, M_WAITOK); 505 snp->snp_blen = SNOOP_MINLEN; 506 } 507 snp->snp_flags |= SNOOP_DOWN; 508 509 return (snp_detach(snp)); 510 } 511 512 static int 513 snpioctl(dev, cmd, data, flags, td) 514 struct cdev *dev; 515 u_long cmd; 516 caddr_t data; 517 int flags; 518 struct thread *td; 519 { 520 struct snoop *snp; 521 struct tty *tp, *tpo; 522 struct cdev *tdev; 523 struct file *fp; 524 int s; 525 526 snp = dev->si_drv1; 527 switch (cmd) { 528 case SNPSTTY: 529 s = *(int *)data; 530 if (s < 0) 531 return (snp_down(snp)); 532 if (fget(td, s, &fp) != 0) 533 return (EINVAL); 534 if (fp->f_type != DTYPE_VNODE || 535 fp->f_vnode->v_type != VCHR || 536 fp->f_vnode->v_rdev == NULL) { 537 fdrop(fp, td); 538 return (EINVAL); 539 } 540 tdev = fp->f_vnode->v_rdev; 541 fdrop(fp, td); 542 543 tp = snpdevtotty(tdev); 544 if (!tp) 545 return (EINVAL); 546 if (tp->t_state & TS_SNOOP) 547 return (EBUSY); 548 549 s = spltty(); 550 551 if (snp->snp_target == NULL) { 552 tpo = snp->snp_tty; 553 if (tpo) 554 tpo->t_state &= ~TS_SNOOP; 555 } 556 557 tp->t_state |= TS_SNOOP; 558 snp->snp_olddisc = tp->t_line; 559 tp->t_line = snooplinedisc; 560 snp->snp_tty = tp; 561 snp->snp_target = tdev; 562 563 /* 564 * Clean overflow and down flags - 565 * we'll have a chance to get them in the future :))) 566 */ 567 snp->snp_flags &= ~SNOOP_OFLOW; 568 snp->snp_flags &= ~SNOOP_DOWN; 569 splx(s); 570 break; 571 572 case SNPGTTY: 573 /* 574 * We keep snp_target field specially to make 575 * SNPGTTY happy, else we can't know what is device 576 * major/minor for tty. 577 */ 578 *((dev_t *)data) = dev2udev(snp->snp_target); 579 break; 580 581 case FIONBIO: 582 break; 583 584 case FIOASYNC: 585 if (*(int *)data) 586 snp->snp_flags |= SNOOP_ASYNC; 587 else 588 snp->snp_flags &= ~SNOOP_ASYNC; 589 break; 590 591 case FIONREAD: 592 s = spltty(); 593 if (snp->snp_tty != NULL) 594 *(int *)data = snp->snp_len; 595 else 596 if (snp->snp_flags & SNOOP_DOWN) { 597 if (snp->snp_flags & SNOOP_OFLOW) 598 *(int *)data = SNP_OFLOW; 599 else 600 *(int *)data = SNP_TTYCLOSE; 601 } else { 602 *(int *)data = SNP_DETACH; 603 } 604 splx(s); 605 break; 606 607 default: 608 return (ENOTTY); 609 } 610 return (0); 611 } 612 613 static int 614 snppoll(dev, events, td) 615 struct cdev *dev; 616 int events; 617 struct thread *td; 618 { 619 struct snoop *snp; 620 int revents; 621 622 snp = dev->si_drv1; 623 revents = 0; 624 /* 625 * If snoop is down, we don't want to poll() forever so we return 1. 626 * Caller should see if we down via FIONREAD ioctl(). The last should 627 * return -1 to indicate down state. 628 */ 629 if (events & (POLLIN | POLLRDNORM)) { 630 if (snp->snp_flags & SNOOP_DOWN || snp->snp_len > 0) 631 revents |= events & (POLLIN | POLLRDNORM); 632 else 633 selrecord(td, &snp->snp_sel); 634 } 635 return (revents); 636 } 637 638 static void 639 snp_clone(arg, cred, name, namelen, dev) 640 void *arg; 641 struct ucred *cred; 642 char *name; 643 int namelen; 644 struct cdev **dev; 645 { 646 int u, i; 647 648 if (*dev != NULL) 649 return; 650 if (dev_stdclone(name, NULL, "snp", &u) != 1) 651 return; 652 i = clone_create(&snpclones, &snp_cdevsw, &u, dev, 0); 653 if (i) 654 *dev = make_dev(&snp_cdevsw, unit2minor(u), 655 UID_ROOT, GID_WHEEL, 0600, "snp%d", u); 656 if (*dev != NULL) { 657 dev_ref(*dev); 658 (*dev)->si_flags |= SI_CHEAPCLONE; 659 } 660 } 661 662 static int 663 snp_modevent(mod, type, data) 664 module_t mod; 665 int type; 666 void *data; 667 { 668 static eventhandler_tag eh_tag; 669 670 switch (type) { 671 case MOD_LOAD: 672 /* XXX error checking. */ 673 clone_setup(&snpclones); 674 eh_tag = EVENTHANDLER_REGISTER(dev_clone, snp_clone, 0, 1000); 675 snooplinedisc = ldisc_register(LDISC_LOAD, &snpdisc); 676 break; 677 case MOD_UNLOAD: 678 if (!LIST_EMPTY(&snp_sclist)) 679 return (EBUSY); 680 EVENTHANDLER_DEREGISTER(dev_clone, eh_tag); 681 clone_cleanup(&snpclones); 682 ldisc_deregister(snooplinedisc); 683 break; 684 default: 685 return (EOPNOTSUPP); 686 break; 687 } 688 return (0); 689 } 690 691 static moduledata_t snp_mod = { 692 "snp", 693 snp_modevent, 694 NULL 695 }; 696 DECLARE_MODULE(snp, snp_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); 697