home *** CD-ROM | disk | FTP | other *** search
- From: Chris Torek <talcott!mimsy.umd.edu:gymble!chris>
- Subject: dial-out mods for 4.3BSD
- Newsgroups: mod.sources
- Approved: jpn@panda.UUCP
-
- Mod.sources: Volume 3, Issue 71
- Submitted by: Chris Torek <seismo!umcp-cs!chris>
-
- [ I don't have BSD 4.3, so have not been able to check this out - moderator ]
-
- : Run this shell script with "sh" not "csh"
- PATH=/bin:/usr/bin:/usr/ucb:/etc:$PATH
- export PATH
- all=FALSE
- if [ x$1 = x-a ]; then
- all=TRUE
- fi
- echo 'Extracting README'
- sed 's/^X//' <<'//go.sysin dd *' >README
- 4.3BSD DIALOUT MODS
- -------------------
-
- N.B.: These changes should work for 4.2BSD as well; but
- the `original' code shown in the diff listings will not
- quite match. You will have to install the changes by
- hand---`patch' will not work.
-
- Installation instructions for the dial devices:
-
- 1. Save copies of the files you will edit. These include vax/conf.c
- and at least one of the device drivers in vaxuba (vaxuba/dh.c,
- vaxuba/dz.c, etc.)
-
- 2. Apply the changes shown to the device driver(s). For other
- devices you will need to extrapolate the changes. Look at dh.c
- and dz.c to see what needs to be done, and read the `dial
- device' document.
-
- N.B.: For dmf32s the changes can be rather tricky. I have a
- dmf32 driver that does dial out, but it is not the standard
- 4.3BSD version, so I cannot make diff listings.
-
- 3. Add the device(s) to the `cdevsw' table in vax/conf.c. The
- diff listing included here is heavily edited and should be used
- only as an example. You will need to assign major device
- numbers yourself. We used 41 and 42 for the dz and dh
- respectively; but the first number free in the distributed
- kernel is much lower---near 25, as I recall.
-
- 4. Compile a new kernel, and reboot.
-
- 5. Make `/dev' entries for the dial devices. (See the `dial device'
- document.)
-
- 6. Test. Included is a C program that can talk to dial lines.
- The program may need slight changes for 4.2BSD, though I think
- I have removed most system dependencies already. (You will,
- however, need `getopt'.)
-
-
- May the stars shine upon your kernel for ever,
- Chris Torek
- University of Maryland
- 22 December 1983
- //go.sysin dd *
- if [ `wc -c < README` != 1700 ]; then
- made=FALSE
- echo 'error transmitting "README" --'
- echo 'length should be 1700, not' `wc -c < README`
- else
- made=TRUE
- fi
- if [ $made = TRUE ]; then
- chmod 644 README
- echo -n ' '; ls -ld README
- fi
- echo 'Extracting c.1'
- sed 's/^X//' <<'//go.sysin dd *' >c.1
- X.TH C 1
- X.UC 4
- X.SH NAME
- c \- communications program
- X.SH SYNOPSIS
- X.B "c -l"
- X.I link
- [
- X.B -s
- X.I speed
- ] [
- X.B -p
- X.I parity
- ] [
- X.B -e
- X.I escape
- ]
- X.SH DESCRIPTION
- X.I C
- is a small communications program for tty lines. It has almost
- no features, unlike
- X.IR tip ,
- so it starts and runs quickly and is very small. It is also useful
- for talking to balky modems when all other methods fail.
- X.PP
- The
- X.I link
- option is required, and should be the name of the tty line, e.g.,
- `/dev/dial05' or `/dev/ttya'.
- X.PP
- The
- X.I speed
- option selects the baud rate. It should be a numeric value from
- the set {300, 600, 1200, 2400, 4800, 9600}. The default is 1200
- baud.
- X.PP
- The
- X.I parity
- switch selects parity, which may be any of the following:
- X.TP
- X.B e
- Even parity
- X.TP
- X.B o
- Odd parity
- X.TP
- X.B 1
- One parity
- X.TP
- X.B 0
- Zero parity
- X.TP
- X.B n
- No parity (the data path is eight bits wide\(emthis is the default).
- X.PP
- The
- X.I esc
- parameter sets the escape character (default ESC). This
- character must be doubled to be sent through the link. Also
- available are the following `escape commands':
- X.TP
- X.B b
- Generate a break.
- X.TP
- X.B h, ?
- Help (list these options).
- X.TP
- X.B o
- Set options. The program will prompt for an option line
- on which any of the flags except
- X.B -l
- may be changed. Options are given in the same way
- as when the program is initially run.
- X.TP
- X.B q
- Quit (exit the program). The program will quit by itself
- if carrier is lost, though this depends on the kernel configuration.
- X.TP
- X.B z
- Suspend.
- X.PP
- Other characters cause the bell to ring.
- X.SH SEE ALSO
- tip(1), cu(1)
- X.SH AUTHOR
- Chris Torek (seismo!umcp-cs!chris, chris@mimsy.umd.edu)
- X.SH BUGS
- Parity only affects outgoing characters. Incoming data is
- always turned into zero parity.
- //go.sysin dd *
- if [ `wc -c < c.1` != 1715 ]; then
- made=FALSE
- echo 'error transmitting "c.1" --'
- echo 'length should be 1715, not' `wc -c < c.1`
- else
- made=TRUE
- fi
- if [ $made = TRUE ]; then
- chmod 644 c.1
- echo -n ' '; ls -ld c.1
- fi
- echo 'Extracting c.c'
- sed 's/^X//' <<'//go.sysin dd *' >c.c
- #ifndef lint
- static char rcsid[] = "$Header$";
- #endif
-
- #include <stdio.h>
- #include <signal.h>
- #include <sys/types.h>
- #include <sys/file.h>
- #include <sgtty.h>
- #ifdef lint
- #include <sys/time.h>
- #endif
-
- X/*
- * Usage: c -l link [ -s speed ] [ -p e|o|0|1|n ] [ -e escapechar ]
- *
- * Comm program.
- *
- * Compilation:
- % cc -O -R -o c c.c
- *
- * N.B.: Should be setuid root, so that it can run at high priority
- * (helps avoid losing input at high baud rates).
- */
-
- #ifndef lint
- extern int errno;
- extern char *optarg;
- extern int optind;
- #else
- int errno;
- char *optarg;
- int optind;
- X/* VARARGS3 ARGSUSED */
- error(quit, e, fmt) int quit, e; char *fmt; { ; }
- #endif
-
- char *_argv0;
- char *linkname;
- int linkfd;
- int speed;
- int escchar;
- int parbis;
- int parbic;
- char *partab;
- char ttybuf[BUFSIZ];
- int ttycount;
- char ttyobuf[BUFSIZ];
- int ttyocount;
- char linebuf[BUFSIZ];
- int linecount;
- char lineobuf[BUFSIZ];
- int lineocount;
-
- X/*
- * 4.3 and V8 style file descriptor mask macros
- * Should be in <sys/types.h> but aren't in 4.2.
- */
- #ifndef FD_SET
- typedef struct fd_set {
- int fds_bits;
- } fd_set;
- #define FD_SET(n, p) ((p)->fds_bits[0] |= (1 << (n)))
- #define FD_CLR(n, p) ((p)->fds_bits[0] &= ~(1 << (n)))
- #define FD_ISSET(n, p) ((p)->fds_bits[0] & (1 << (n)))
- #define FD_ZERO(p) ((p)->fds_bits = 0)
- #endif
-
- char evenpar[128] = {
- 0x00, 0x81, 0x82, 0x03, 0x84, 0x05, 0x06, 0x87,
- 0x88, 0x09, 0x0a, 0x8b, 0x0c, 0x8d, 0x8e, 0x0f,
- 0x90, 0x11, 0x12, 0x93, 0x14, 0x95, 0x96, 0x17,
- 0x18, 0x99, 0x9a, 0x1b, 0x9c, 0x1d, 0x1e, 0x9f,
- 0xa0, 0x21, 0x22, 0xa3, 0x24, 0xa5, 0xa6, 0x27,
- 0x28, 0xa9, 0xaa, 0x2b, 0xac, 0x2d, 0x2e, 0xaf,
- 0x30, 0xb1, 0xb2, 0x33, 0xb4, 0x35, 0x36, 0xb7,
- 0xb8, 0x39, 0x3a, 0xbb, 0x3c, 0xbd, 0xbe, 0x3f,
- 0xc0, 0x41, 0x42, 0xc3, 0x44, 0xc5, 0xc6, 0x47,
- 0x48, 0xc9, 0xca, 0x4b, 0xcc, 0x4d, 0x4e, 0xcf,
- 0x50, 0xd1, 0xd2, 0x53, 0xd4, 0x55, 0x56, 0xd7,
- 0xd8, 0x59, 0x5a, 0xdb, 0x5c, 0xdd, 0xde, 0x5f,
- 0x60, 0xe1, 0xe2, 0x63, 0xe4, 0x65, 0x66, 0xe7,
- 0xe8, 0x69, 0x6a, 0xeb, 0x6c, 0xed, 0xee, 0x6f,
- 0xf0, 0x71, 0x72, 0xf3, 0x74, 0xf5, 0xf6, 0x77,
- 0x78, 0xf9, 0xfa, 0x7b, 0xfc, 0x7d, 0x7e, 0xff,
- };
- char oddpar[128] = {
- 0x80, 0x01, 0x02, 0x83, 0x04, 0x85, 0x86, 0x07,
- 0x08, 0x89, 0x8a, 0x0b, 0x8c, 0x0d, 0x0e, 0x8f,
- 0x10, 0x91, 0x92, 0x13, 0x94, 0x15, 0x16, 0x97,
- 0x98, 0x19, 0x1a, 0x9b, 0x1c, 0x9d, 0x9e, 0x1f,
- 0x20, 0xa1, 0xa2, 0x23, 0xa4, 0x25, 0x26, 0xa7,
- 0xa8, 0x29, 0x2a, 0xab, 0x2c, 0xad, 0xae, 0x2f,
- 0xb0, 0x31, 0x32, 0xb3, 0x34, 0xb5, 0xb6, 0x37,
- 0x38, 0xb9, 0xba, 0x3b, 0xbc, 0x3d, 0x3e, 0xbf,
- 0x40, 0xc1, 0xc2, 0x43, 0xc4, 0x45, 0x46, 0xc7,
- 0xc8, 0x49, 0x4a, 0xcb, 0x4c, 0xcd, 0xce, 0x4f,
- 0xd0, 0x51, 0x52, 0xd3, 0x54, 0xd5, 0xd6, 0x57,
- 0x58, 0xd9, 0xda, 0x5b, 0xdc, 0x5d, 0x5e, 0xdf,
- 0xe0, 0x61, 0x62, 0xe3, 0x64, 0xe5, 0xe6, 0x67,
- 0x68, 0xe9, 0xea, 0x6b, 0xec, 0x6d, 0x6e, 0xef,
- 0x70, 0xf1, 0xf2, 0x73, 0xf4, 0x75, 0x76, 0xf7,
- 0xf8, 0x79, 0x7a, 0xfb, 0x7c, 0xfd, 0xfe, 0x7f,
- };
-
- struct sgttyb sgbuf;
-
- main(argc, argv)
- int argc;
- char **argv;
- {
- register int fd, c, tx, lx;
- static int state;
-
- _argv0 = argv[0];
-
- speed = B1200;
- escchar = 27;
- argue(argc, argv, 1);
-
- (void) nice(-10);
- (void) setuid(getuid());
-
- fd = open(linkname, O_RDWR, 0);
- if (fd < 0)
- error(1, errno, "can't open %s", linkname);
-
- linkfd = fd;
- fixlink();
- rawtty();
- printf("open\r\n");
- lx = 0;
- tx = 0;
-
- for (;;) {
- if (lx >= linecount && tx >= ttycount) {
- fd_set inbits;
-
- if (ttyocount)
- flusho(ttyobuf, &ttyocount, 1);
- if (lineocount)
- flusho(lineobuf, &lineocount, fd);
-
- /* read from tty and/or line */
- FD_ZERO(&inbits);
- FD_SET(1, &inbits);
- FD_SET(fd, &inbits);
- c = select(fd + 1, &inbits, (fd_set *) 0, (fd_set *) 0,
- (struct timeval *) 0);
- if (c == 0) {
- error(0, errno, "select");
- cleanup(1);
- }
- if (FD_ISSET(1, &inbits)) {
- ttycount = read(0, ttybuf, BUFSIZ);
- if (ttycount < 0) {
- error(0, errno, "read(0)");
- cleanup(1);
- }
- if (ttycount == 0) {
- error(0, 0, "eof(0)?");
- cleanup(1);
- }
- tx = 0;
- }
- if (FD_ISSET(fd, &inbits)) {
- linecount = read(fd, linebuf, BUFSIZ);
- if (linecount < 0) {
- error(0, errno, "read(%d)", fd);
- cleanup(1);
- }
- if (linecount == 0) {
- error(0, 0, "eof(%d)?", fd);
- cleanup(1);
- }
- lx = 0;
- }
- }
- /* handle tty input */
- while (tx < ttycount) {
- c = ttybuf[tx++] & 0x7f;
- if (state) {
- state = 0;
- if (c == escchar)
- goto put;
- switch (c) {
- case 'b':
- genbreak();
- break;
-
- case 'q':
- cleanup(0);
- /*NOTREACHED*/
-
- case 'z':
- printf("\r\nsuspend\r\n");
- susp();
- printf("resumed\r\n");
- break;
-
- case 'h':
- case 'H':
- case '?':
- printf("\r\n\
- ESC subcommands:\r\n\
- b - generate a break\r\n\
- o - set options\r\n\
- q - quit\r\n\
- z - suspend\r\n");
- break;
-
- case 'o':
- case 'O':
- options();
- break;
-
- default:
- beep:
- ttyobuf[ttyocount++] = 7;
- if (ttyocount == BUFSIZ)
- flusho(ttyobuf, &ttyocount, 1);
- break;
- }
- } else if (c == escchar) {
- state = 1;
- goto beep;
- } else {
- put:
- if (partab)
- c = partab[c];
- else /* restore parity */
- c = ttybuf[tx - 1];
- c |= parbis;
- c &= ~parbic;
- lineobuf[lineocount++] = c;
- if (lineocount == BUFSIZ)
- flusho(lineobuf, &lineocount, fd);
- }
- }
- /* handle line input */
- while (lx < linecount) {
- c = linebuf[lx++];
- /* handle parity here someday */
- ttyobuf[ttyocount++] = c & 0x7f;
- if (ttyocount == BUFSIZ)
- flusho(ttyobuf, &ttyocount, fd);
- }
- }
- }
-
- flusho(buf, p, fd)
- char *buf;
- register int *p;
- int fd;
- {
-
- if (write(fd, buf, *p) != *p) {
- error(0, errno, "write(%d)", fd);
- cleanup(1);
- }
- *p = 0;
- }
-
- cleanup(code)
- int code;
- {
-
- printf("\r\nclosed\r\n");
- (void) ioctl(0, TIOCSETP, &sgbuf);
- exit(code);
- }
-
- rawtty()
- {
- struct sgttyb raw;
-
- if (ioctl(0, TIOCGETP, &sgbuf))
- error(1, errno, "ioctl TIOCGETP");
- raw = sgbuf;
- raw.sg_flags = RAW;
- (void) ioctl(0, TIOCSETP, &raw);
- }
-
- susp()
- {
-
- (void) ioctl(0, TIOCSETP, &sgbuf);
- kill(0, SIGTSTP);
- rawtty();
- }
-
- struct speeds {
- int sp;
- int sp_b;
- };
-
- findspeed(sp)
- {
- register struct speeds *spp;
- static struct speeds speeds[] = {
- 300, B300, 600, B600, 1200, B1200, 2400, B2400,
- 4800, B4800, 9600, B9600, -1, -1
- };
-
- spp = speeds;
- while (spp->sp >= 0) {
- if (spp->sp == sp)
- return (spp->sp_b);
- spp++;
- }
- return (-1);
- }
-
- genbreak()
- {
-
- (void) ioctl(linkfd, TIOCSBRK, 0);
- sleep(1);
- (void) ioctl(linkfd, TIOCCBRK, 0);
- }
-
- char **
- makeargv(avp, s)
- register char **avp, *s;
- {
-
- for (;;) {
- while (*s == ' ' || *s == '\t' || *s == '\n')
- s++;
- if (*s == 0) {
- *avp = 0;
- return avp;
- }
- *avp++ = s;
- while (*s && *s != ' ' && *s != '\t' && *s != '\n')
- s++;
- if (*s == 0) {
- *avp = 0;
- return avp;
- }
- *s++ = 0;
- }
- }
-
- options()
- {
- char buf[200];
- char *argv[100];
- int argc;
-
- (void) ioctl(0, TIOCSETP, &sgbuf);
- printf("options: ");
- if (fgets(buf, sizeof buf, stdin) == NULL)
- exit(1);
- argv[0] = _argv0;
- argc = makeargv(argv + 1, buf) - argv;
- argue(argc, argv, 0);
- rawtty();
- }
-
- argue(argc, argv, toplevel)
- int argc;
- char **argv;
- int toplevel;
- {
- register int c;
-
- optind = 1;
- while ((c = getopt(argc, argv, "s:p:l:e:")) != EOF) {
- switch (c) {
- case '?':
- usage:
- if (toplevel) {
- error(1, 0, "\
- usage: c -l link [-s speed] [-p par] [-e esc]");
- /* NOTREACHED */
- }
- error(0, 0, "options: [-s speed] [-p par] [-e esc]");
- break;
-
- case 'l':
- if (!toplevel) {
- error(0, 0, "can't change link in midstream");
- break;
- }
- if (linkname)
- error(1, 0, "use only one -l option");
- linkname = optarg;
- break;
-
- case 's':
- if ((speed = findspeed(atoi(optarg))) < 0)
- error(toplevel, 0, "invalid speed %s", optarg);
- if (!toplevel)
- fixlink();
- break;
-
- case 'p':
- if (*optarg == 'e') {
- partab = evenpar;
- parbis = parbic = 0;
- } else if (*optarg == 'o') {
- partab = oddpar;
- parbis = parbic = 0;
- } else if (*optarg == '1') {
- parbis = 0x80;
- parbic = 0;
- } else if (*optarg == '0') {
- parbis = 0;
- parbic = 0x80;
- } else if (*optarg == 'n') {
- parbis = parbic = 0;
- partab = 0;
- } else
- error(toplevel, 0, "\
- for -p, use one of [e, o, 1, 0, n]");
- break;
-
- case 'e':
- if (optarg[1] == 0)
- escchar = *optarg;
- else if (optarg[0] == '^')
- escchar = optarg[1] == '?' ? 0x7f :
- *optarg & 0x1f;
- else
- escchar = atoi(optarg);
- printf("escape set to %s%c.\n",
- escchar >= 0x20 && escchar < 0x7f ? "" : "^",
- escchar >= 0x20 ? (escchar == 0x7f ? '?' : escchar) :
- escchar + '@');
- break;
- default:
- error(1, 0, "internal error: argue switch");
- }
- }
- if (linkname == 0)
- goto usage;
- }
-
- fixlink()
- {
- struct sgttyb l;
-
- l.sg_ispeed = l.sg_ospeed = speed;
- l.sg_flags = RAW;
- (void) ioctl(linkfd, TIOCSETN, &l);
- }
-
- #ifndef lint
- X/*
- * Error routine from the local C library
- * N.B.: This code is system dependent.
- */
-
- X/*
- * error - University of Maryland specific (sigh)
- *
- * Useful for printing error messages. Will print the program name
- * and (optionally) the system error associated with the values in
- * <errno.h>.
- *
- * Note that the type (and even the existence!) of ``arg'' is undefined.
- */
- error(quit, e, fmt, arg)
- int quit;
- register int e;
- char *fmt;
- {
- extern char *sys_errlist[];
- extern int sys_nerr;
- register char *p = _argv0;
-
- if (p != NULL)
- (void) fprintf(stderr, "%s: ", p);
- _doprnt(fmt, &arg, stderr); /* magic */
- if (e > 0) {
- if (e < sys_nerr)
- (void) fprintf(stderr, ": %s", sys_errlist[e]);
- else
- (void) fprintf(stderr, ": unknown error number %d", e);
- }
- (void) putc('\n', stderr);
- (void) fflush(stderr);
- if (quit)
- exit(quit);
- }
- #endif
- //go.sysin dd *
- if [ `wc -c < c.c` != 9712 ]; then
- made=FALSE
- echo 'error transmitting "c.c" --'
- echo 'length should be 9712, not' `wc -c < c.c`
- else
- made=TRUE
- fi
- if [ $made = TRUE ]; then
- chmod 644 c.c
- echo -n ' '; ls -ld c.c
- fi
- echo 'Extracting dial.tex'
- sed 's/^X//' <<'//go.sysin dd *' >dial.tex
- %
- % dial.tex - some notes on the implementation of simultaneous dial in/out
- % on modem lines.
- %
-
- % 11 pt
- \magnification=\magstephalf
-
- % Fonts. If you are using TeX78, or the new Computer Modern fonts, change
- % this to cmcsc10.
- \font\tencsc=amcsc10
-
- % Macros
- \newif\iftm % true if we have mentioned the trademark
- \def\Unix{{\tencsc Unix}\iftm\else\footnote{$\dag$}{{\tencsc Unix} is a
- footnote of AT\&T Bell Laboratories}\global\tmtrue\fi}
- \def\bsd{{\tencsc 4.3bsd} \Unix}
- % \tencsc does not look very good on these, so we will use regular fonts.
- %\def\dec{{\tencsc dec}}
- %\def\dz{{\tencsc dz11}} % official version
- %\def\dzz{{\tencsc dz}} % short version, purely for variety
- %\def\dh{{\tencsc dh11}}
- \def\dec{{\rm DEC}}
- \def\dz{{\rm DZ11}}
- \def\dzz{{\rm DZ}}
- \def\dh{{\rm DH11}}
- \chardef\us=`\_
-
- % Layout
- \parskip=.5\baselineskip plus1pt
- \footline={\ifnum\pageno=1\hfil\else{\tenrm\hfil Dial Devices for
- \bsd\hfil\llap{\folio}}\fi}
-
- % Here we go...
-
- % Header, plus page 1 (save paper)
- % How about THIS title! Catchy, no?
- \null
- \vskip1cm
- \centerline{Some Notes on the Implementation of Dialout Capabilites}
- \centerline{for Modem Lines under \bsd}
- \vskip.5cm
- \centerline{Chris Torek}
- \vskip.5cm
- \centerline{Department of Computer Science}
- \centerline{University of Maryland}
- \centerline{College Park, MD 20742}
-
- \vskip 2cm
-
- % Ok. Now what?
- % How about this:
-
- Modern modems may be used in both `originate' and `answer' modes---that
- is, they can both call out and answer incoming calls. Traditional
- \Unix\ systems, however, cannot handle this well; modems have
- typically been dedicated to one purpose or the other. At the
- University of Maryland, we have devised a set of kernel modifications
- that allow modem lines to be used bidirectionally. These present
- a simple user interface and require none of the error-prone locking
- protocols that have been used in the past to implement similar
- functionality. Moreover, using our scheme, site administrators
- can if they so choose implement accounting for all outgoing calls.
- Previous systems rendered this difficult at best.
-
- % Enough extolling of virtues. Now for some details:
-
- As far as user programs are concerned, the only change to the system
- is the addition of a new set of {\it dial} devices. These devices
- have a one-to-one correspondence with the {\it tty} lines; they
- are distinguished by having a different major device number. For
- example, on one machine we have two Racal-Vadic
- VA3400\footnote{$\ddag$}{Vadic and VA3400 are no doubt trademarks
- of someone or another} modems. These appear as {\tt tty04} and {\tt
- tty05}, and also as {\tt dial04} and {\tt dial05}:
-
- {\tt\vskip\parskip\parskip=0pt\obeylines\obeyspaces%
- crw--w--w- 1 root 1, 4 Dec 3 00:06 /dev/tty04
- crw--w--w- 1 root 1, 5 Dec 2 00:27 /dev/tty05
- crw-rw-rw- 1 root 41, 4 Dec 2 23:13 /dev/dial04
- crw-rw-rw- 1 root 41, 5 Dec 2 23:16 /dev/dial05
-
- } % what, me, work late? ^^^
-
- Here major device 1 corresponds to the \dec\ \dz.\footnote{*}{\dec,
- \dh, and \dz\ are trademarks of Digital Equipment Corporation}
- Major device 41 is also the \dz, but in `dial out' or `outgoing'
- mode. When a program opens the normal or `incoming' line, it
- behaves as such programs always have: If there is a carrier on
- the line, the open completes normally; if not, the open
- `hangs'---suspends---waiting for a carrier. When a program opens
- the `outgoing' line, however, something new occurs. If there is
- a carrier on the line, that indicates that the device is already
- in use; and the open is rejected with a `Device busy' error, {\tt
- EBUSY}. (In previous versions of \Unix\ this was called a `Mount
- device busy' error.) The open is likewise rejected if the line is
- already in use outgoing. Indeed, in such cases there is always a
- carrier, so no additional code is required for this: Only if there
- is no carrier does the open complete---and it will hang up
- automatically once a carrier has appeared and then vanished.
-
- What happens, then, when a line is in the process of being opened
- for incoming use when the outgoing call is made? Why, nothing, of
- course: the incoming open remains suspended until the outgoing
- call has been completed. Anything else would break existing code.
- As a bonus, no locking is required; outgoing opens succeed if and
- only if the line is not in use, and incoming opens remain hung
- during outgoing calls.
-
- % Finally, the nitty-gritty; the details; the real guts of the game.
-
- To illustrate how this is accomplished, I shall refer again to the
- \dz\ driver. We have added two new arrays, and made use of an
- existing third array: There is now a {\tt dz\us inout} and a {\tt
- dz\us flags}, both of size {\tt NDZ} and type {\tt char}. The first
- holds the `outgoing mode' flag for each \dzz\ line. Bit $b$ is set
- in {\tt dz\us inout[$d\/$]} whenever line $b$ of \dzz\ $d$ has an outgoing
- open in progress. {\tt dz\us flags} holds a permanent copy of the
- `flags' parameter from the kernel configuration file. In this case
- these are the software carrier flags. In the original kernel these
- were put into the array {\tt dz\us softCAR}---also of size {\tt
- NDZ}---and never touched. We must save them somewhere as outgoing
- opens work by temporarily asserting the software carrier.
-
- We modified the device open code to return {\tt EBUSY} not only on
- attempts to open a line in `exclusive use' mode, but also on attempts
- to open a line in outgoing mode whenever the line is already open
- in any mode. As usual, the super-user is exempt from this restriction.
- We also modified the open code to:
-
- \item {1)} assert the software carrier on outgoing opens;
-
- \item {2)} hang until there is a carrier (or software carrier);
-
- \item {3)} hang until the line is not in use outgoing, unless this is
- the outgoing call itself; and
-
- \item {4)} reassert DTR every time the state of the line changes.
-
- \noindent
- Incoming and outgoing opens are distinguished by the `flag' argument
- to the device open routine. This is always a small nonnegative
- integer for normal opens; but the outgoing open routine calls the
- regular open routine with a {\tt flag} of {\tt -1}.
-
- The fourth point is important because of a change in the close
- routine. To ensure that a modem hangs up, it is necessary to drop
- DTR for at least $1\over2$ second. But modems will generally not
- answer the phone unless DTR is asserted. So the close routine
- first drops DTR and maintains it that way for one second, then, if
- it is an outgoing close, turns off the outgoing mode flag, restores
- the software carrier, and awakens any hung incoming opens so that
- they may reassert DTR if necessary. As with the open routine, an
- outgoing close is distinguished by its {\tt flag} argument.
-
- We made one more change to the driver. The modem interrupt code---or
- in the case of the \dz, the modem poll code, for there are no modem
- interrupts---now checks both the real carrier and the software
- carrier. Either will allow the open to complete; but if the real
- carrier is asserted when the line is open in outgoing mode, the
- software carrier for that line is cleared. This means that once
- an outgoing call completes, the line is usable only until the
- connection is closed: When the carrier goes away, the line will
- be hung up, just as for a normal incoming open. This allows one
- to perform call accounting, under the condition that the modem
- never allows calls to be placed without having first lost carrier;
- and this is true of most modems. The dial-out program would be
- set-group-ID to a group that can open the `dial' devices. This
- program would open the device, dial the number, wait for the call
- to complete, and then log the call in a file. As long as the
- program were careful not to let the user set {\tt NOHUP} mode on
- the line, no further calls could be made, as the file descriptor
- would be invalidated and the program would be sent a {\tt SIGHUP}
- signal as soon as the connection were broken.
-
- (We actually made another change to the \dzz\ driver. {\tt MDMBUF}
- mode, wherein carrier transitions act as flow control, now works
- on \dz s as well as \dh s. This is, however, of limited usefulness,
- as the \dzz\ modem status is only polled once every second; at 1200
- baud, up to 120 characters may be sent after a carrier drop before
- transmission is suspended, and at 9600 baud, up to 960 characters
- could conceivably be sent. The lack of a modem interrupt is one of
- many problems with \dz s, and cannot truly be corrected in software.)
-
- % Ok. Summary:
-
- These kernel changes have allowed us to make greater use, with more
- ease, of our existing dialer resources. The automatic locking has
- eliminated all protocol errors that have plagued other systems in
- the past. And we even log outgoing calls, though we do not charge
- for them or otherwise restrict them.
-
- % clean up
-
- \vskip.5cm
- \line{\it Acknowledgements\hfil}
-
- Credit is due Joe Pallas, Bob Kirby, and Fred Blonder, who worked
- with me on our original implementation for V6 and 4.1{\tencsc bsd}
- \Unix. This work was no doubt indirectly supported by several
- government grants and other misdirected research funds. All the
- errors in this document, however, should be credited only to myself.
-
- \bye
- //go.sysin dd *
- if [ `wc -c < dial.tex` != 9184 ]; then
- made=FALSE
- echo 'error transmitting "dial.tex" --'
- echo 'length should be 9184, not' `wc -c < dial.tex`
- else
- made=TRUE
- fi
- if [ $made = TRUE ]; then
- chmod 644 dial.tex
- echo -n ' '; ls -ld dial.tex
- fi
- echo 'Extracting diff.vax.conf.c'
- sed 's/^X//' <<'//go.sysin dd *' >diff.vax.conf.c
- RCS file: RCS/conf.c,v
- retrieving revision 1.1.1.2
- retrieving revision 1.5
- diff -c2 -r1.1.1.2 -r1.5 [edited]
- *** /tmp/,RCSt1000435 Mon Dec 2 23:47:17 1985
- --- /tmp/,RCSt2000435 Mon Dec 2 23:47:19 1985
- ***************
- *** 268,277 ****
- --- 301,3?? ----
- #define dhstop nodev
- #define dhreset nulldev
- + #define dhoopen nodev
- + #define dhoclose nodev
- #define dh11 0
- #else
- int dhopen(),dhclose(),dhread(),dhwrite(),dhioctl(),dhstop(),dhreset();
- + int dhoopen(),dhoclose();
- struct tty dh11[];
- #endif
- ***************
- *** 316,322 ****
- --- 375,384 ----
- #define dzstop nodev
- #define dzreset nulldev
- + #define dzoopen nodev
- + #define dzoclose nodev
- #define dz_tty 0
- #else
- int dzopen(),dzclose(),dzread(),dzwrite(),dzioctl(),dzstop(),dzreset();
- + int dzoopen(),dzoclose();
- struct tty dz_tty[];
- #endif
- ***************
- *** ???,??? ****
- --- ???,??? ----
- + dzoopen, dzoclose, dzread, dzwrite, /*??*/
- + dzioctl, dzstop, nulldev, dz_tty,
- + ttselect, nodev,
- + dhoopen, dhoclose, dhread, dhwrite, /*??*/
- + dhioctl, dhstop, nulldev, dh11,
- + ttselect, nodev,
- //go.sysin dd *
- if [ `wc -c < diff.vax.conf.c` != 1076 ]; then
- made=FALSE
- echo 'error transmitting "diff.vax.conf.c" --'
- echo 'length should be 1076, not' `wc -c < diff.vax.conf.c`
- else
- made=TRUE
- fi
- if [ $made = TRUE ]; then
- chmod 644 diff.vax.conf.c
- echo -n ' '; ls -ld diff.vax.conf.c
- fi
- echo 'Extracting diff.vaxuba.dh.c'
- sed 's/^X//' <<'//go.sysin dd *' >diff.vaxuba.dh.c
- RCS file: RCS/dh.c,v
- retrieving revision 1.1.1.3
- retrieving revision 1.4
- diff -c2 -r1.1.1.3 -r1.4
- *** /tmp/,RCSt1000424 Mon Dec 2 23:46:43 1985
- --- /tmp/,RCSt2000424 Mon Dec 2 23:46:45 1985
- ***************
- *** 70,73 ****
- --- 70,74 ----
- short dhsar[NDH]; /* software copy of last bar */
- short dhsoftCAR[NDH];
- + short dh_inout[NDH];
-
- struct tty dh11[NDH*16];
- ***************
- *** 80,84 ****
- int dhlowrate = 75; /* silo off if dhrate < dhlowrate */
- static short timerstarted;
- ! int dhstart(), ttrstrt();
-
- /*
- --- 81,85 ----
- int dhlowrate = 75; /* silo off if dhrate < dhlowrate */
- static short timerstarted;
- ! int dhstart(), ttrstrt(), wakeup();
-
- /*
- ***************
- *** 169,173 ****
- * the first use of it. Also do a dmopen to wait for carrier.
- */
- - /*ARGSUSED*/
- dhopen(dev, flag)
- dev_t dev;
- --- 170,173 ----
- ***************
- *** 184,188 ****
- return (ENXIO);
- tp = &dh11[unit];
- ! if (tp->t_state&TS_XCLUDE && u.u_uid!=0)
- return (EBUSY);
- addr = (struct dhdevice *)ui->ui_addr;
- --- 184,189 ----
- return (ENXIO);
- tp = &dh11[unit];
- ! if (u.u_uid != 0 && (tp->t_state&TS_XCLUDE ||
- ! flag < 0 && tp->t_state&TS_ISOPEN))
- return (EBUSY);
- addr = (struct dhdevice *)ui->ui_addr;
- ***************
- *** 231,235 ****
- * Wait for carrier, then process line discipline specific open.
- */
- ! dmopen(dev);
- return ((*linesw[tp->t_line].l_open)(dev, tp));
- }
- --- 232,236 ----
- * Wait for carrier, then process line discipline specific open.
- */
- ! dmopen(dev, flag);
- return ((*linesw[tp->t_line].l_open)(dev, tp));
- }
- ***************
- *** 236,242 ****
-
- /*
- ! * Close a DH11 line, turning off the DM11.
- */
- /*ARGSUSED*/
- dhclose(dev, flag)
- dev_t dev;
- --- 237,254 ----
-
- /*
- ! * Outgoing mode open: fake the carrier.
- */
- /*ARGSUSED*/
- + dhoopen(dev, flag)
- + dev_t dev;
- + int flag;
- + {
- +
- + return (dhopen(dev, -1));
- + }
- +
- + /*
- + * Close a DH11 line, turning off the DM11.
- + */
- dhclose(dev, flag)
- dev_t dev;
- ***************
- *** 250,258 ****
- (*linesw[tp->t_line].l_close)(tp);
- ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017));
- ! if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN)==0)
- dmctl(unit, DML_OFF, DMSET);
- ttyclose(tp);
- }
-
- dhread(dev, uio)
- dev_t dev;
- --- 262,290 ----
- (*linesw[tp->t_line].l_close)(tp);
- ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017));
- ! if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN)==0 || flag < 0) {
- dmctl(unit, DML_OFF, DMSET);
- + /* hold DTR low long enough for it to be detected */
- + timeout(wakeup, (caddr_t)&tp->t_state, hz);
- + sleep((caddr_t)&tp->t_state, TTOPRI);
- + }
- ttyclose(tp);
- + if (flag < 0) { /* clear outgoing mode */
- + dh_inout[unit >> 4] &= ~(1 << (unit & 0xf));
- + wakeup((caddr_t)&tp->t_rawq);
- + }
- }
-
- + /*
- + * Close an outgoing DH line
- + */
- + /*ARGSUSED*/
- + dhoclose(dev, flag)
- + dev_t dev;
- + int flag;
- + {
- +
- + dhclose(dev, -1);
- + }
- +
- dhread(dev, uio)
- dev_t dev;
- ***************
- *** 403,406 ****
- --- 435,439 ----
- tp->t_state |= TS_HUPCLS;
- dmctl(unit, DML_OFF, DMSET);
- + splx(s);
- return;
- }
- ***************
- *** 671,676 ****
- * Turn on the line associated with dh dev.
- */
- ! dmopen(dev)
- dev_t dev;
- {
- register struct tty *tp;
- --- 704,710 ----
- * Turn on the line associated with dh dev.
- */
- ! dmopen(dev, flag)
- dev_t dev;
- + int flag;
- {
- register struct tty *tp;
- ***************
- *** 685,689 ****
- tp = &dh11[unit];
- unit &= 0xf;
- ! if (dm >= NDH || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0) {
- tp->t_state |= TS_CARR_ON;
- return;
- --- 719,724 ----
- tp = &dh11[unit];
- unit &= 0xf;
- ! if (dm >= NDH || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0 ||
- ! (dhsoftCAR[dm]&(1<<unit))) {
- tp->t_state |= TS_CARR_ON;
- return;
- ***************
- *** 691,694 ****
- --- 726,754 ----
- addr = (struct dmdevice *)ui->ui_addr;
- s = spl5();
- + if (flag < 0) {
- + dh_inout[dm] |= 1 << unit;
- + dmassert(addr, dm, unit, tp);
- + tp->t_state |= TS_CARR_ON;
- + }
- + else {
- + do {
- + dmassert(addr, dm, unit, tp);
- + if (tp->t_state&TS_CARR_ON &&
- + (dh_inout[dm]&(1<<unit)) == 0)
- + break;
- + tp->t_state |= TS_WOPEN;
- + sleep((caddr_t)&tp->t_rawq, TTIPRI);
- + } while ((tp->t_state&TS_CARR_ON) == 0 ||
- + (dh_inout[dm]&(1<<unit)));
- + }
- + splx(s);
- + }
- +
- + dmassert(addr, dm, unit, tp)
- + register struct dmdevice *addr;
- + int dm, unit;
- + struct tty *tp;
- + {
- +
- addr->dmcsr &= ~DM_SE;
- while (addr->dmcsr & DM_BUSY)
- ***************
- *** 696,705 ****
- addr->dmcsr = unit;
- addr->dmlstat = DML_ON;
- ! if ((addr->dmlstat&DML_CAR) || (dhsoftCAR[dm]&(1<<unit)))
- tp->t_state |= TS_CARR_ON;
- addr->dmcsr = DM_IE|DM_SE;
- - while ((tp->t_state&TS_CARR_ON)==0)
- - sleep((caddr_t)&tp->t_rawq, TTIPRI);
- - splx(s);
- }
-
- --- 756,762 ----
- addr->dmcsr = unit;
- addr->dmlstat = DML_ON;
- ! if (addr->dmlstat & DML_CAR || dhsoftCAR[dm] & (1 << unit))
- tp->t_state |= TS_CARR_ON;
- addr->dmcsr = DM_IE|DM_SE;
- }
-
- //go.sysin dd *
- if [ `wc -c < diff.vaxuba.dh.c` != 5035 ]; then
- made=FALSE
- echo 'error transmitting "diff.vaxuba.dh.c" --'
- echo 'length should be 5035, not' `wc -c < diff.vaxuba.dh.c`
- else
- made=TRUE
- fi
- if [ $made = TRUE ]; then
- chmod 644 diff.vaxuba.dh.c
- echo -n ' '; ls -ld diff.vaxuba.dh.c
- fi
- echo 'Extracting diff.vaxuba.dz.c'
- sed 's/^X//' <<'//go.sysin dd *' >diff.vaxuba.dz.c
- RCS file: RCS/dz.c,v
- retrieving revision 1.1.1.3
- retrieving revision 1.4
- diff -c2 -r1.1.1.3 -r1.4
- *** /tmp/,RCSt1000449 Mon Dec 2 23:49:49 1985
- --- /tmp/,RCSt2000449 Mon Dec 2 23:49:52 1985
- ***************
- *** 52,56 ****
-
- int dzstart(), dzxint(), dzdma();
- ! int ttrstrt();
- struct tty dz_tty[NDZLINE];
- int dz_cnt = { NDZLINE };
- --- 52,56 ----
-
- int dzstart(), dzxint(), dzdma();
- ! int ttrstrt(), wakeup();
- struct tty dz_tty[NDZLINE];
- int dz_cnt = { NDZLINE };
- ***************
- *** 70,74 ****
- char dz_brk[NDZ];
- char dzsoftCAR[NDZ];
- ! char dz_lnen[NDZ]; /* saved line enable bits for DZ32 */
-
- /*
- --- 70,76 ----
- char dz_brk[NDZ];
- char dzsoftCAR[NDZ];
- ! char dz_inout[NDZ]; /* outgoing mode flags */
- ! char dz_flags[NDZ]; /* permanent copy of flags */
- ! char dz_lnen[NDZ]; /* saved line enable bits for DZ32 */
-
- /*
- ***************
- *** 130,134 ****
- pdp++, tp++;
- }
- ! dzsoftCAR[ui->ui_unit] = ui->ui_flags;
- if (dz_timer == 0) {
- dz_timer++;
- --- 132,136 ----
- pdp++, tp++;
- }
- ! dzsoftCAR[ui->ui_unit] = dz_flags[ui->ui_unit] = ui->ui_flags;
- if (dz_timer == 0) {
- dz_timer++;
- ***************
- *** 138,142 ****
- }
-
- - /*ARGSUSED*/
- dzopen(dev, flag)
- dev_t dev;
- --- 140,143 ----
- ***************
- *** 144,147 ****
- --- 145,149 ----
- register struct tty *tp;
- register int unit;
- + register int dz, bit;
-
- unit = minor(dev);
- ***************
- *** 157,165 ****
- /* tp->t_state |= TS_HUPCLS; */
- dzparam(unit);
- ! } else if (tp->t_state&TS_XCLUDE && u.u_uid != 0)
- return (EBUSY);
- (void) dzmctl(dev, DZ_ON, DMSET);
- (void) spl5();
- ! while ((tp->t_state & TS_CARR_ON) == 0) {
- tp->t_state |= TS_WOPEN;
- sleep((caddr_t)&tp->t_rawq, TTIPRI);
- --- 159,175 ----
- /* tp->t_state |= TS_HUPCLS; */
- dzparam(unit);
- ! } else if ((tp->t_state&TS_XCLUDE || flag < 0) && u.u_uid != 0)
- return (EBUSY);
- (void) dzmctl(dev, DZ_ON, DMSET);
- (void) spl5();
- ! dz = unit >> 3;
- ! bit = 1 << (unit & 7);
- ! if (flag < 0) {
- ! dz_inout[dz] |= bit;
- ! dzsoftCAR[dz] |= bit;
- ! }
- ! while ((tp->t_state & TS_CARR_ON) == 0 ||
- ! dz_inout[dz] & bit && flag >= 0) {
- ! (void) dzmctl(dev, DZ_ON, DMSET);
- tp->t_state |= TS_WOPEN;
- sleep((caddr_t)&tp->t_rawq, TTIPRI);
- ***************
- *** 168,173 ****
- return ((*linesw[tp->t_line].l_open)(dev, tp));
- }
- !
- /*ARGSUSED*/
- dzclose(dev, flag)
- dev_t dev;
- --- 178,190 ----
- return ((*linesw[tp->t_line].l_open)(dev, tp));
- }
- !
- /*ARGSUSED*/
- + dzoopen(dev, flag)
- + dev_t dev;
- + {
- +
- + return (dzopen(dev, -1));
- + }
- +
- dzclose(dev, flag)
- dev_t dev;
- ***************
- *** 187,195 ****
- else
- dzaddr->dzbrk = (dz_brk[dz] &= ~(1 << (unit&07)));
- ! if ((tp->t_state&(TS_HUPCLS|TS_WOPEN)) || (tp->t_state&TS_ISOPEN) == 0)
- (void) dzmctl(dev, DZ_OFF, DMSET);
- ttyclose(tp);
- }
-
- dzread(dev, uio)
- dev_t dev;
- --- 204,233 ----
- else
- dzaddr->dzbrk = (dz_brk[dz] &= ~(1 << (unit&07)));
- ! if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN)==0 || flag < 0) {
- (void) dzmctl(dev, DZ_OFF, DMSET);
- + timeout(wakeup, (caddr_t)&tp->t_state, hz);
- + sleep((caddr_t)&tp->t_state, TTOPRI);
- + }
- ttyclose(tp);
- + if (flag < 0) {
- + register int bit = 1 << (unit & 7);
- +
- + dz_inout[dz] &= ~bit;
- + if (dz_flags[dz] & bit)
- + dzsoftCAR[dz] |= bit;
- + else
- + dzsoftCAR[dz] &= ~bit;
- + wakeup((caddr_t)&tp->t_rawq);
- + }
- }
-
- + /*ARGSUSED*/
- + dzoclose(dev, flag)
- + dev_t dev;
- + {
- +
- + dzclose(dev, -1);
- + }
- +
- dzread(dev, uio)
- dev_t dev;
- ***************
- *** 575,581 ****
- register struct tty *tp;
- register car;
- ! int olddzsilos = dzsilos;
- int dztimer();
- !
- for (i = 0; i < dz_cnt ; i++) {
- dzaddr = dzpdma[i].p_addr;
- --- 613,619 ----
- register struct tty *tp;
- register car;
- ! int olddzsilos = dzsilos, realcar;
- int dztimer();
- !
- for (i = 0; i < dz_cnt ; i++) {
- dzaddr = dzpdma[i].p_addr;
- ***************
- *** 584,598 ****
- tp = &dz_tty[i];
- bit = 1<<(i&07);
- ! car = 0;
- ! if (dzsoftCAR[i>>3]&bit)
- ! car = 1;
- ! else if (dzaddr->dzcsr & DZ_32) {
- dzaddr->dzlcs = i&07;
- dzwait(dzaddr);
- ! car = dzaddr->dzlcs & DZ_CD;
- } else
- ! car = dzaddr->dzmsr&bit;
- if (car) {
- /* carrier present */
- if ((tp->t_state & TS_CARR_ON) == 0) {
- wakeup((caddr_t)&tp->t_rawq);
- --- 622,638 ----
- tp = &dz_tty[i];
- bit = 1<<(i&07);
- ! if (dzaddr->dzcsr & DZ_32) {
- dzaddr->dzlcs = i&07;
- dzwait(dzaddr);
- ! realcar = dzaddr->dzlcs & DZ_CD;
- } else
- ! realcar = dzaddr->dzmsr&bit;
- ! car = 0;
- ! if (realcar || dzsoftCAR[i>>3] & bit)
- ! car++;
- if (car) {
- /* carrier present */
- + if (realcar && dz_inout[i>>3] & bit)
- + dzsoftCAR[i >> 3] &= ~bit;
- if ((tp->t_state & TS_CARR_ON) == 0) {
- wakeup((caddr_t)&tp->t_rawq);
- ***************
- *** 599,604 ****
- tp->t_state |= TS_CARR_ON;
- }
- } else {
- ! if ((tp->t_state&TS_CARR_ON) &&
- (tp->t_flags&NOHANG) == 0) {
- /* carrier lost */
- --- 639,651 ----
- tp->t_state |= TS_CARR_ON;
- }
- + else if (tp->t_state&TS_TTSTOP && tp->t_flags&MDMBUF) {
- + tp->t_state &= ~TS_TTSTOP;
- + ttstart(tp);
- + }
- } else {
- ! if (tp->t_flags&MDMBUF) {
- ! tp->t_state |= TS_TTSTOP;
- ! dzstop(tp, 0);
- ! } else if ((tp->t_state&TS_CARR_ON) &&
- (tp->t_flags&NOHANG) == 0) {
- /* carrier lost */
- //go.sysin dd *
- if [ `wc -c < diff.vaxuba.dz.c` != 5358 ]; then
- made=FALSE
- echo 'error transmitting "diff.vaxuba.dz.c" --'
- echo 'length should be 5358, not' `wc -c < diff.vaxuba.dz.c`
- else
- made=TRUE
- fi
- if [ $made = TRUE ]; then
- chmod 644 diff.vaxuba.dz.c
- echo -n ' '; ls -ld diff.vaxuba.dz.c
- fi
-
-