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

Cache object: baf25854ad89870b30cd197bc3c3bdb8


[ 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.