home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / contrib / usr.x25 / x29d / x29d.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-29  |  16.8 KB  |  745 lines

  1. /*
  2.  * X.29 server
  3.  *
  4.  * Frank Pronk (...!ubc-vision!pronk)
  5.  * April, September 1984
  6.  *
  7.  * Laboratory for Computational Vision
  8.  * University of British Columbia
  9.  * Copyright (c)
  10.  */
  11.  
  12. #include <sys/param.h>
  13. #include <sys/socket.h>
  14. #include <sys/stat.h>
  15. #include <sys/wait.h>
  16.  
  17. #include <netccitt/x25.h>
  18.  
  19. #include <errno.h>
  20. #include <netdb.h>
  21. #include <signal.h>
  22. #include <sys/ioctl.h>
  23. #include <sys/termios.h>
  24. #include <paths.h>
  25.  
  26. #include "../h/x29.h"
  27.  
  28. #define BUFSIZ        1024
  29. #define MAXARGS        10    /* maximum size of server argument list */
  30.  
  31. #define X25NET        0    /* no ITI parameters */
  32. #define CCITT1978    1    /* 1978 CCITT standard parameter set */
  33. #define CCITT1980    2    /* 1980 CCITT standard parameter set */
  34.  
  35.  
  36. char    pibuf[BUFSIZ], fibuf[BUFSIZ];
  37. int    pty, net;
  38. extern    char **environ;
  39. extern    int errno;
  40. char    line[MAXPATHLEN];
  41. char    console[] = "/dev/console";
  42. short    packet_size;
  43. short    debug;
  44. char    *tracefn;        /* trace file name */
  45. char    *server;
  46. short    send_banner;
  47. struct    termios pt, old_pt;
  48. struct    sockaddr_x25 sock;
  49.  
  50. int    reapchild();
  51. struct    net *lookup ();
  52.  
  53. char    ccitt1978_prof[] = {        /* initial profile */
  54.     Q_BIT,    X29_SET_AND_READ_PARMS,
  55.     X29_ECHO_CODE,            1,    /* echo on */
  56.     X29_FORWARDING_SIGNAL_CODE,    126,    /* forward on all cntl */
  57.     X29_IDLE_TIMER_CODE,        0,    /* off */
  58.     X29_AUX_DEV_CONTROL_CODE,    0,    /* off */
  59.     X29_RECEIVE_NET_MSGS_CODE,    1,    /* xmit network msgs */
  60.     X29_BREAK_PROCEDURE_CODE,    21,
  61.     X29_PADDING_CODE,        0,    /* off */
  62.     X29_LINE_FOLDING_CODE,        0,    /* off */
  63.     X29_TRANSMISSION_SPEED_CODE,    0,
  64.     X29_XON_XOFF_CODE,        1,    /* enable XON/XOFF */
  65. };
  66.  
  67. char    ccitt1980_prof[] = {        /* initial profile */
  68.     Q_BIT,    X29_SET_AND_READ_PARMS,
  69.     X29_ECHO_CODE,            1,    /* echo on */
  70.     X29_FORWARDING_SIGNAL_CODE,    126,    /* forward on all cntl */
  71.     X29_IDLE_TIMER_CODE,        0,    /* off */
  72.     X29_AUX_DEV_CONTROL_CODE,    0,    /* off */
  73.     X29_RECEIVE_NET_MSGS_CODE,    1,    /* xmit network msgs */
  74.     X29_BREAK_PROCEDURE_CODE,    21,
  75.     X29_PADDING_CODE,        0,    /* off */
  76.     X29_LINE_FOLDING_CODE,        0,    /* off */
  77.     X29_TRANSMISSION_SPEED_CODE,    0,
  78.     X29_XON_XOFF_CODE,        1,    /* enable XON/XOFF */
  79.  
  80.     X29_LF_AFTER_CR,        4,    /* lf after cr from terminal */
  81.     X29_EDITING,            1,    /* on */
  82.     X29_CHARACTER_DELETE,        CERASE,
  83.     X29_LINE_DELETE,        CKILL,
  84.     X29_LINE_DISPLAY,        CRPRNT,
  85. };
  86.  
  87. char    datapac_prof[] = {        /* Canadian X.25 network */
  88.     Q_BIT,    X29_SET_AND_READ_PARMS,
  89.     X29_ECHO_CODE,            1,    /* echo on */
  90.     X29_FORWARDING_SIGNAL_CODE,    126,    /* forward on all cntl */
  91.     X29_IDLE_TIMER_CODE,        0,    /* off */
  92.     X29_AUX_DEV_CONTROL_CODE,    0,    /* off */
  93.     X29_RECEIVE_NET_MSGS_CODE,    1,    /* xmit network msgs */
  94.     X29_BREAK_PROCEDURE_CODE,    21,
  95.     X29_PADDING_CODE,        0,    /* off */
  96.     X29_LINE_FOLDING_CODE,        0,    /* off */
  97.     X29_TRANSMISSION_SPEED_CODE,    0,
  98.     X29_XON_XOFF_CODE,        1,    /* enable XON/XOFF */
  99.  
  100.     X29_LF_AFTER_CR,        4,    /* lf after cr from terminal */
  101.     X29_EDITING,            1,    /* on */
  102.     X29_CHARACTER_DELETE,        CERASE,
  103.     X29_LINE_DELETE,        CKILL,
  104.     X29_LINE_DISPLAY,        CRPRNT,
  105.  
  106.     /*
  107.      * This rubbish can be removed when Datapac
  108.      * adopts the 1980 standard parameter set.
  109.      */
  110.  
  111.     0,                0,    /* national parameter marker */
  112.     123,                0,    /* parity off */
  113. };
  114.  
  115. struct    net {
  116.     char    *n_name;    /* generic name */
  117.     short    n_type;        /* see defines above */
  118.     char    *n_profile;    /* initial profile */
  119.     short    n_proflen;    /* length of n_profile */
  120. } *netp, nets[] = {
  121.     "x.25",        X25NET,        0,        0,
  122.     "1978",        CCITT1978,    ccitt1978_prof,    sizeof(ccitt1978_prof),
  123.     "ccitt1978",    CCITT1978,    ccitt1978_prof,    sizeof(ccitt1978_prof),
  124.     "1980",        CCITT1980,    ccitt1980_prof,    sizeof(ccitt1980_prof),
  125.     "ccitt1980",    CCITT1980,    ccitt1980_prof,    sizeof(ccitt1980_prof),
  126.     "datapac",    CCITT1980,    datapac_prof,    sizeof(datapac_prof),
  127.     0,        0,        0,        0
  128. };
  129.  
  130. main(argc, argv)
  131. register char **argv;
  132. {
  133.     register int s, pid;
  134.     register char *p;
  135.  
  136.     /*
  137.      * If this host doesn't support X.25, give up.
  138.      */
  139.     s = socket(AF_CCITT, SOCK_STREAM, 0);
  140.     if (s < 0 && errno == EPROTONOSUPPORT)
  141.         fatal(2, "X.25 is not supported on this machine");
  142.     close(s);
  143.     netp = lookup ("ccitt1978");
  144.     sock.x25_family = AF_CCITT;
  145.     sock.x25_len = sizeof(sock);
  146.     sock.x25_opts.op_flags = X25_MQBIT;
  147.     sock.x25_udata[0] = ITI_CALL;
  148.     sock.x25_udlen = 4;
  149.  
  150.     for (argv++; argc > 1; argc--, argv++)
  151.         if (**argv == '-')
  152.             for (p = *argv+1; *p; p++)
  153.             switch (*p) {
  154.             case 'b':
  155.                 send_banner++;
  156.                 break;
  157.  
  158.             case 'c':
  159.                 if (argc > 1) {
  160.                     argc--; argv++;
  161.                     if ((netp = lookup (*argv)) == 0)
  162.                         fatal(1, "Unknown network type");
  163.                 }
  164.                 break;
  165.  
  166.             case 'p':
  167.                 if (argc > 1) {
  168.                     argc--; argv++;
  169.                     strcpy (sock.x25_udata, *argv);
  170.                 }
  171.                 break;
  172.  
  173.             case 'r':
  174.                 sock.x25_opts.op_flags |= X25_REVERSE_CHARGE;
  175.                 break;
  176.  
  177.             case 'd':
  178.                 debug++;
  179.                 break;
  180.  
  181.             case 't':
  182.                 if (argc > 1) {
  183.                     argc--; argv++;
  184.                     tracefn = *argv;
  185.                 }
  186.                 else fatal(1, "missing trace file");
  187.                 break;
  188.  
  189.             default:
  190.                 fatal (1, "usage: x29d -b -c nettype -p protocol -r -t trace_file server");
  191.             }
  192.         else
  193.             server = *argv;
  194.     if (server == 0)
  195.         fatal (1, "no server specified");
  196.     if (debug == 0)
  197.         daemon(0, 0);
  198.  
  199.     while ((s = socket(AF_CCITT, SOCK_STREAM, 0)) < 0)
  200.         sleep(60);
  201.     while (bind(s, (caddr_t)&sock, sizeof (sock)) < 0)
  202.         sleep(60);
  203.     signal(SIGCHLD, reapchild);
  204.     listen(s, 5);
  205.  
  206.     for (;;) {
  207.         struct sockaddr_x25 from;
  208.         int fromlen = sizeof (from);
  209.  
  210.         if ((net = accept(s, (caddr_t)&from, &fromlen)) < 0) {
  211.             if (errno != EINTR)
  212.                 sleep (60);
  213.             continue;
  214.         }
  215.         while ((pid = fork()) < 0)
  216.             sleep(60);
  217.         if (pid == 0) {
  218.             signal(SIGCHLD, SIG_DFL);
  219.             doit(&from);
  220.         }
  221.         close(net);
  222.     }
  223.     /*NOTREACHED*/
  224. }
  225.  
  226. struct net *
  227. lookup (name)
  228. char *name;
  229. {
  230.     register struct net *np;
  231.  
  232.     for (np = nets; np->n_name; np++)
  233.         if (strcmp (np->n_name, name) == 0)
  234.             return (np);
  235.     return (0);
  236. }
  237.  
  238. reapchild()
  239. {
  240.     union wait status;
  241.  
  242.     while (wait3(&status, WNOHANG, 0) > 0)
  243.         ;
  244. }
  245.  
  246. char    *envinit[] = { "TERM=ccitt", 0 };
  247. int    cleanup();
  248. struct termios term;
  249.  
  250. /*
  251.  * Get a pty, scan input lines.
  252.  */
  253. doit(who)
  254. struct sockaddr_x25 *who;
  255. {
  256.     register char *cp;
  257.     int i, p, t;
  258.  
  259.     packet_size = 1 << who->x25_opts.op_psize;
  260.     i = forkpty(&pty, line, &term, 0);
  261.     if (i > 0)
  262.         x29d();
  263.     if (i < 0)
  264.         fatalperror("fork", errno);
  265.     environ = envinit;
  266.     call_server (who);
  267.     /*NOTREACHED*/
  268. }
  269.  
  270. call_server (who)
  271. struct sockaddr_x25 *who;
  272. {
  273.     register struct hostent *hp = 0;
  274.     register char *p, **ap;
  275.     char *args[MAXARGS];
  276.     struct stat st;
  277.     struct hostent *getx25hostbyaddr();
  278.     int ccitt = 0;
  279.  
  280.     p = server;
  281.     while (*p && *p != ' ' && *p != '\t')    /* split program from args */
  282.         p++;
  283.     if (*p)
  284.         *p++ = '\0';
  285.     ap = args;
  286.     while (*p) {
  287.         while (*p == ' ' || *p == '\t')
  288.             p++;
  289.         if (ap < &args[MAXARGS-2])
  290.             *ap++ = p;
  291.         if (strcmp(p, "-ccitt") == 0)
  292.             ccitt = 1;
  293.         while (*p && *p != ' ' && *p != '\t')
  294.             p++;
  295.         if (*p)
  296.             *p++ = '\0';
  297.     }
  298.     if (stat (server, &st) < 0)
  299.         fatalperror (server, errno);
  300.     /*
  301.      * For security: if running as root, switch to user
  302.      * and group id of server.  This prevents privately
  303.      * maintainted or bogus servers from getting super-
  304.      * user permissions.
  305.      */
  306.     if (getuid() == 0) {
  307.         setgid (st.st_gid);
  308.         setuid (st.st_uid);
  309.     }
  310.     if (hp = getx25hostbyaddr (who->x25_addr))
  311.         *ap++ = hp->h_name;
  312.     else
  313.         *ap++ = (char *)who->x25_addr;
  314.     /*
  315.      * If the -ccitt flag was given, add another argument
  316.      * to tell login if charging is being reversed or not.
  317.      */
  318.     if (ccitt)
  319.         *ap++ = (who->x25_opts.op_flags & X25_REVERSE_CHARGE) ? "y" : "n";
  320.     *ap = 0;
  321.     execv (server, args);
  322.     fatalperror (server, errno);
  323.     /*NOTREACHED*/
  324. }
  325.  
  326. fatal(f, msg)
  327.     int f;
  328.     char *msg;
  329. {
  330.     register char *p;
  331.     char buf[BUFSIZ], *index();
  332.  
  333.     p = buf;
  334.     if (f == net)
  335.         *p++ = 0;
  336.     strcpy(p, "x29d: ");
  337.     strcat(p, msg);
  338.     strcat(p, "\n");
  339.     (void) write(f, p, (index(p, '\n')-p)+1);
  340.     exit(1);
  341. }
  342.  
  343. fatalperror(msg, err)
  344. char *msg;
  345. {
  346.     char buf[BUFSIZ];
  347.     extern char *sys_errlist[];
  348.  
  349.     strcpy(buf, msg);
  350.     strcat(buf, ": ");
  351.     strcat(buf, sys_errlist[err]);
  352.     fatal(net, buf);
  353. }
  354.  
  355. /*
  356.  * Main loop.  Select from pty and network, and
  357.  * hand data to iti receiver.
  358.  */
  359. x29d()
  360. {
  361.     register int pcc, fcc, cc;
  362.     register char *fbp;
  363.     int pgrp, x25_interrupt(), on = 1;
  364.     char hostname[32];
  365.  
  366.     ioctl(net, FIONBIO, (char *)&on);
  367.     ioctl(pty, FIONBIO, (char *)&on);
  368.     /*ioctl(pty, TIOCREMECHO, (char *)&on);    /* enable special pty mode */
  369.     /* new equivalent is no processing in pty, no echo, but let
  370.        user set modes and have either remote end do line mode processing
  371.        or do it in daemon */
  372.     ioctl(pty, TIOCEXT, (char *)&on);
  373.     ioctl(pty, TIOCPKT, (char *)&on);
  374.     ioctl(pty, TIOCGETA, (char *)&pt);
  375.     signal(SIGPIPE, SIG_IGN);    /* why not cleanup?  --kwl */
  376.     signal(SIGTSTP, SIG_IGN);
  377.     signal(SIGCHLD, cleanup);
  378.     signal(SIGHUP, cleanup);
  379.  
  380.     signal(SIGTTOU, SIG_IGN);
  381.     signal(SIGURG, x25_interrupt);    /* for out-of-band data */
  382.  
  383.     if (netp->n_proflen)
  384.         (void) write(net, netp->n_profile, netp->n_proflen);
  385.  
  386.     /*
  387.      * Show banner that getty never gave.
  388.      */
  389.     if (send_banner) {
  390.         gethostname(hostname, sizeof (hostname));
  391. #ifdef BSD4_3
  392.         strcpy(pibuf+1, "\r\n\r\n4.3 BSD UNIX (");
  393. #else
  394.         strcpy(pibuf+1, "\r\n\r\n4.2 BSD UNIX (");
  395. #endif
  396.         strcat(pibuf+1, hostname);
  397.         strcat(pibuf+1, ")\r\n\r\n");
  398.         pcc = strlen(pibuf+1) + 1;
  399.     } else
  400.         pcc = 0;
  401.  
  402.     fcc = 0;
  403.     for (;;) {
  404.         int ibits, obits;
  405.  
  406.         ibits = obits = 0;
  407.         /*
  408.          * Never look for input if there's still
  409.          * stuff in the corresponding output buffer
  410.          */
  411.         if (fcc >= 0)            /* net connection alive? */
  412.             if (fcc && pcc >= 0)    /* output pending? */
  413.                 obits |= (1 << pty);
  414.             else
  415.                 if (pcc >= 0)    /* pty still alive? */
  416.                     ibits |= (1 << net);
  417.         if (pcc >= 0)            /* pty connection alive? */
  418.             if (pcc && fcc >= 0)    /* output pending? */
  419.                 obits |= (1 << net);
  420.             else
  421.                 if (fcc >= 0)    /* net still alive? */
  422.                     ibits |= (1 << pty);
  423.         if (ibits == 0 && obits == 0)
  424.             break;
  425.         (void) select(16, &ibits, &obits, (int *)0, 0);
  426.         if (ibits == 0 && obits == 0) {
  427.             sleep(5);
  428.             continue;
  429.         }
  430.  
  431.         /*
  432.          * Something to read from the network...
  433.          */
  434.         if (fcc == 0 && (ibits & (1 << net))) {
  435.             fcc = read(net, fibuf, BUFSIZ);
  436.             fbp = fibuf+1;
  437.             if (fcc < 0 && errno == EWOULDBLOCK)
  438.                 fcc = 0;
  439.             else if (fcc <= 0)
  440.                 fcc = -1;
  441.             else {
  442.                 if (tracefn)
  443.                     x29d_trace("netread", fibuf, fcc);
  444.                 if (fibuf[0] & Q_BIT) {
  445.                     x29_qbit(fcc);
  446.                     fcc = 0;
  447.                 } else
  448.                     fcc--;
  449.             }
  450.         }
  451.  
  452.         /*
  453.          * Something to read from the pty...
  454.          */
  455.         if (ibits & (1 << pty)) {
  456.             pcc = read(pty, pibuf, packet_size+1);
  457.             if (pcc < 0 && errno == EWOULDBLOCK)
  458.                 pcc = 0;
  459.             else if (pcc <= 0)
  460.                 pcc = -1;
  461.             else if (pibuf[0] != 0) {    /* non-data packet */
  462.                 if (pibuf[0] & TIOCPKT_IOCTL) {
  463.                     if (--pcc > sizeof(pt))
  464.                         pcc = sizeof(pt);
  465.                     old_pt = pt;
  466.                     bcopy(pibuf + 1, (char *)&pt, pcc);
  467.                     pcc = set_x29_parameters();
  468.                 } else
  469.                     pcc = 0;
  470.             } else                /* data packet */
  471.                 pibuf[0] = 0;
  472.         }
  473.  
  474.         if ((obits & (1<<net)) && pcc > 0)
  475.             if ((cc = write(net, pibuf, pcc)) == pcc) {
  476.                 if (tracefn)
  477.                     x29d_trace("netwrite", pibuf, pcc);
  478.                 pcc = 0;
  479.             } else {
  480.                 extern char *sys_errlist[];
  481.  
  482.                 if (tracefn)
  483.                     x29d_trace("netwrite",
  484.                         sys_errlist[errno],
  485.                         strlen(sys_errlist[errno]));
  486.                     
  487.             }
  488.  
  489.         if ((obits & (1 << pty)) && fcc > 0) {
  490.             cc = ptywrite(fbp, fcc);
  491.             if (cc > 0) {
  492.                 fcc -= cc;
  493.                 fbp += cc;
  494.             }
  495.         }
  496.     }
  497.     cleanup();
  498. }
  499.  
  500.  
  501. /*
  502.  * Send interrupt to process on other side of pty.
  503.  * If it is in raw mode, just write NULL;
  504.  * otherwise, write intr char.
  505.  */
  506.  
  507. x25_interrupt()
  508. {
  509.     struct termios tt;
  510.     int zero = 0;
  511.  
  512.     signal(SIGURG, x25_interrupt);
  513.     tcgetattr(pty, &tt);
  514.     if (tt.c_lflag & ISIG) {
  515.         tcsetattr(pty, TCSAFLUSH, &tt);
  516.         (void) write(pty, &tt.c_cc[VINTR], 1);
  517.     } else
  518.         (void) write(pty, "\0", 1);
  519. }
  520.  
  521. cleanup()
  522. {
  523.     char *p;
  524.  
  525.     p = line + sizeof(_PATH_DEV) - 1;
  526.     if (logout(p))
  527.         logwtmp(p, "", "");
  528.     (void)chmod(line, 0666);
  529.     (void)chown(line, 0, 0);
  530.     *p = 'p';
  531.     (void)chmod(line, 0666);
  532.     (void)chown(line, 0, 0);
  533.     shutdown(net, 2);
  534.     exit(1);
  535. }
  536.  
  537. /*
  538.  * Map unix tty modes and special characters
  539.  * into x29 parameters.
  540.  */
  541.  
  542. set_x29_parameters()
  543. {
  544.     register char *p;
  545.     int f;
  546.     char *lim = p + sizeof (pt);
  547.  
  548.     if (netp->n_type == X25NET)
  549.         return (0);
  550.     if ((old_pt.c_lflag & ICANON) != (pt.c_lflag & ICANON)) {
  551.         f = pt.c_lflag & ICANON;
  552.         ioctl(pty, TIOCEXT, &f);
  553.         /* this precipitates more junk of the same
  554.          * sort that caused our call here, but we can't
  555.          * turn it off since something may be going on in our progeny.
  556.          *
  557.          * Instead, we'll check the next time around to see if nothing
  558.          * has changed, and skip informing the network.
  559.          */
  560.     }
  561.     if (bcmp((char *)&pt, (char *)&old_pt, sizeof (pt)) == 0)
  562.         return;
  563.     p = pibuf;
  564.     *p++ = Q_BIT;
  565.     *p++ = X29_SET_PARMS;
  566.     /* *p++ = X29_ESCAPE_TO_CMD_CODE; *p++ = (f & (RAW|CBREAK)) == 0;*/
  567.     *p++ = X29_ESCAPE_TO_CMD_CODE; *p++ = (pt.c_lflag & ICANON) != 0;
  568.  
  569.     *p++ = X29_ECHO_CODE; *p++ = (pt.c_lflag & ECHO) != 0;
  570.     *p++ = X29_FORWARDING_SIGNAL_CODE;
  571.             *p++ = (pt.c_lflag & ISIG) ? 0 : 126;
  572.  
  573.     /*
  574.      * The value of 10 (0.5 seconds) for the idle timer when
  575.      * in raw or cbreak mode is a compromise value.  For good
  576.      * interactive response this value should be as low as
  577.      * possible; for reasonable efficiency with file transfers
  578.      * this value should be at fairly high.  This number should
  579.      * be changed to suit local requirements.
  580.      */
  581.  
  582.     /**p++ = X29_IDLE_TIMER_CODE;    *p++ = (f & (RAW|CBREAK)) ? 10 : 0;*/
  583.     *p++ = X29_IDLE_TIMER_CODE; *p++ = (pt.c_lflag & ICANON)  ? 0 : 10;
  584.  
  585.     /**p++ = X29_AUX_DEV_CONTROL_CODE;*p++ = (f & TANDEM) != 0;*/
  586.     *p++ = X29_AUX_DEV_CONTROL_CODE;*p++ = (pt.c_iflag & IXOFF) != 0;
  587.     *p++ = X29_XON_XOFF_CODE;    *p++ = (pt.c_iflag & IXON) != 0;
  588.     if (netp->n_type == CCITT1980) {
  589.         *p++ = X29_LF_AFTER_CR;
  590.         /* *p++ = (f & (RAW|CBREAK) || (f & ECHO) == 0) ? 0 : 4; */
  591.         *p++ = ((pt.c_lflag & (ICANON | ECHO)) != (ICANON | ECHO)) ?
  592.             0 : 4;
  593.  
  594.         *p++ = X29_EDITING; *p++ = (pt.c_lflag & ICANON) != 0;
  595. #define ctlchar(x) \
  596.   (0 == (pt.c_lflag & ICANON) || pt.c_cc[x] == _POSIX_VDISABLE) ? 0 : pt.c_cc[x]
  597.         *p++ = X29_CHARACTER_DELETE; *p++ = ctlchar(VERASE);
  598.         *p++ = X29_LINE_DELETE; *p++ = ctlchar(VKILL);
  599.         *p++ = X29_LINE_DISPLAY; *p++ = ctlchar(VREPRINT);
  600.     }
  601. #undef ctlchar
  602.     return (p - pibuf);
  603. }
  604.  
  605. /* Have to be careful writing to pty.  The pad will forward control
  606.  * characters without necessarily sending an interrupt so if ISIG and
  607.  * ICANNON are set, must inspect line for quit or interrupt or suspend.
  608.  */
  609. ptywrite(buf, n)
  610. char *buf;
  611. int n;
  612. {
  613.     register char *cp, *lim;
  614.     char *last;
  615. #define is_ctl(x) (pt.c_cc[x] == *(cc_t *)cp)
  616.  
  617.     if ((pt.c_lflag & EXTPROC) && (pt.c_lflag & ISIG)) {
  618.         for (cp = buf, lim = buf + n; cp < lim; cp ++) {
  619.             if (is_ctl(VLNEXT))
  620.                 { cp++; continue; }
  621.             if (is_ctl(VSUSP) || is_ctl(VDSUSP) || 
  622.                 is_ctl(VINTR) || is_ctl(VQUIT))  {
  623.                 int onoff = 0;
  624.                 tcflag_t old_echo = pt.c_lflag & ECHO;
  625.  
  626.                 ioctl(pty, TIOCPKT, (char *)&onoff);
  627.                 ioctl(pty, FIONBIO, (char *)&onoff);
  628.                 ioctl(pty, TIOCEXT, (char *)&onoff);
  629.                 if (old_echo) {
  630.                     pt.c_lflag &= ~ECHO;
  631.                     ioctl(pty, TIOCSETA, (char *)&pt);
  632.                 }
  633.                 n = write(pty, buf, n);
  634.                 onoff = 1;
  635.                 if (old_echo) {
  636.                     pt.c_lflag |= ECHO;
  637.                     ioctl(pty, TIOCSETA, (char *)&pt);
  638.                 }
  639.                 ioctl(pty, TIOCEXT, (char *)&onoff);
  640.                 ioctl(pty, FIONBIO, (char *)&onoff);
  641.                 ioctl(pty, TIOCPKT, (char *)&onoff);
  642.                 return (n);
  643.             }
  644.         }
  645.     }
  646.     return write(pty, buf, n);
  647. }
  648.  
  649. /*
  650.  * Process Q BIT (control) packets from the net.
  651.  * The only message that we are interested in are
  652.  * those indicating output is being discarded.
  653.  */
  654.  
  655. x29_qbit(n)
  656. {
  657.     register char *p;
  658.  
  659.     switch (fibuf[1]) {
  660.     case X29_SET_PARMS:
  661.     case X29_SET_AND_READ_PARMS:
  662.     case X29_PARAMETER_INDICATION:
  663.     case X29_INDICATION_OF_BREAK:
  664.         for (p = &fibuf[2]; p < fibuf+n; p++) {
  665.             if (*p == X29_TRANSMISSION_SPEED_CODE) {
  666.                 static char speeds[] = {
  667.                     B110, B0, B300, B1200, B600,
  668.                     B0, B0, B0, B0, B0, B0, B0,
  669.                     B2400, B4800, B9600, EXTA };
  670.  
  671.                 if (*++p >= 0 && *p < sizeof(speeds)) {
  672.                     cfsetspeed(&pt, speeds[*p]);
  673.                     tcsetattr(pty, TCSANOW, &pt);
  674.                 }
  675.             } else if (*p == X29_DISCARD_OUTPUT_CODE && *++p != 0) {
  676.                 char message[4];
  677.  
  678.                 /*
  679.                  * Always re-enable normal output
  680.                  */
  681.                 message[0] = Q_BIT;
  682.                 message[1] = X29_SET_PARMS;
  683.                 message[2] = X29_DISCARD_OUTPUT_CODE;
  684.                 message[3] = 0;
  685.                 (void) write(net, message, sizeof(message));
  686.                 if (tracefn)
  687.                     x29d_trace("netwrite", message, 4);
  688.             }
  689.         }
  690.         return;
  691.  
  692.     default: {
  693.             register char *p2;
  694.             char buf[BUFSIZ*4];
  695.             static int fd;
  696.  
  697.             /*
  698.              * Bad news - we received an x29 error message or
  699.              * some other unknown packet.  Dump the contents
  700.              * of the packet on the console.
  701.              */
  702.             p = buf;
  703.             for (p2 = "x29d: unknown q-bit packet: "; *p++ = *p2++; );
  704.             for (p2 = fibuf+1; p2 < fibuf+n; p2++)
  705.                 if (*p2 >= ' ' && *p2 < 0177)
  706.                     *p++ = *p2;
  707.                 else {
  708.                     *p++ = '\\';
  709.                     *p++ = ((*p2 & 0300) >> 6) + '0';
  710.                     *p++ = ((*p2 & 070) >> 3) + '0';
  711.                     *p++ = (*p2 & 07) + '0';
  712.                 }
  713.             *p++ = '\n';
  714.             if (fd <= 0)
  715.                 fd = open(console, 1);
  716.             (void) write(fd, buf, p-buf);
  717.         }
  718.     }
  719. }
  720.  
  721. x29d_trace(s, bp, n)
  722. char *s, *bp;
  723. {
  724.     static int fd;
  725.     char buf[BUFSIZ*4];
  726.     register char *p1, *p2;
  727.  
  728.     for (p1 = buf; *s; *p1++ = *s++);
  729.     *p1++ = ':';
  730.     *p1++ = ' ';
  731.     for (p2=bp; p2 < bp+n; p2++)
  732.         if (*p2 >= ' ' && *p2 < 0177)
  733.             *p1++ = *p2;
  734.         else {
  735.             *p1++ = '\\';
  736.             *p1++ = ((*p2 & 0300) >> 6) + '0';
  737.             *p1++ = ((*p2 & 070) >> 3) + '0';
  738.             *p1++ = (*p2 & 07) + '0';
  739.         }
  740.     *p1++ = '\n';
  741.     if (fd <= 0)
  742.         fd = creat(tracefn, 0666);
  743.     (void) write(fd, buf, p1-buf);
  744. }
  745.