The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/tty_snoop.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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 
   41 static  d_open_t        snpopen;
   42 static  d_close_t       snpclose;
   43 static  d_read_t        snpread;
   44 static  d_write_t       snpwrite;
   45 static  d_ioctl_t       snpioctl;
   46 static  d_poll_t        snppoll;
   47 
   48 #define CDEV_MAJOR 53
   49 static 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 
   59 static struct snoop snoopsw[NSNP];
   60 
   61 static struct tty       *snpdevtotty __P((dev_t dev));
   62 static int              snp_detach __P((struct snoop *snp));
   63 
   64 static struct tty *
   65 snpdevtotty (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 
   85 static  int
   86 snpwrite(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 
  108 tty_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 
  126 static  int
  127 snpread(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)) {
  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 
  188 int
  189 snpinc(struct snoop *snp, char c)
  190 {
  191         char    buf[1];
  192 
  193         buf[0]=c;
  194         return (snpin(snp,buf,1));
  195 }
  196 
  197 
  198 int
  199 snpin(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 
  285 static  int
  286 snpopen(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->p_ucred, &p->p_acflag))
  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 
  325 static int
  326 snp_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 
  354 detach_notty:
  355         selwakeup(&snp->snp_sel);
  356         snp->snp_sel.si_pid = 0;
  357 
  358         return (0);
  359 }
  360 
  361 static  int
  362 snpclose(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 
  378 int
  379 snpdown(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 
  391 static  int
  392 snpioctl(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 
  484 static  int
  485 snppoll(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
  510 static  void    *snp_devfs_token[NSNP];
  511 #endif
  512 static  int     snp_devsw_installed;
  513 
  514 static void snp_drvinit __P((void *unused));
  515 static void
  516 snp_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 
  538 SYSINIT(snpdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,snp_drvinit,NULL)
  539 
  540 
  541 #endif

Cache object: 10169c9b67e92834942a55a9d931a786


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.