Relay-Version: version B 2.10.3 beta 11/15/85; site seismo.CSS.GOV Posting-Version: version B 2.10.2 9/3/84; site panda.UUCP Path: seismo!harvard!talcott!panda!sources-request From: sources-request@panda.UUCP Newsgroups: mod.sources Subject: dial-out mods for 4.3BSD Message-ID: <1231@panda.UUCP> Date: 26 Dec 85 03:52:43 GMT Sender: jpn@panda.UUCP Lines: 1427 Approved: jpn@panda.UUCP Mod.sources: Volume 3, Issue 71 Submitted by: Chris Torek [ 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 #include #include #include #include #ifdef lint #include #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 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 * . * * 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<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<t_state |= TS_WOPEN; + sleep((caddr_t)&tp->t_rawq, TTIPRI); + } while ((tp->t_state&TS_CARR_ON) == 0 || + (dh_inout[dm]&(1<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<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