1fa92e883SRuslan Ermilov /* $OpenBSD: hayes.c,v 1.13 2006/03/17 19:17:13 moritz Exp $ */ 20f3bdf5dSMark Murray /* $NetBSD: hayes.c,v 1.6 1997/02/11 09:24:17 mrg Exp $ */ 30f3bdf5dSMark Murray 4*8a16b7a1SPedro F. Giffuni /*- 5*8a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 6*8a16b7a1SPedro F. Giffuni * 718cc36fbSJordan K. Hubbard * Copyright (c) 1983, 1993 818cc36fbSJordan K. Hubbard * The Regents of the University of California. All rights reserved. 918cc36fbSJordan K. Hubbard * 1018cc36fbSJordan K. Hubbard * Redistribution and use in source and binary forms, with or without 1118cc36fbSJordan K. Hubbard * modification, are permitted provided that the following conditions 1218cc36fbSJordan K. Hubbard * are met: 1318cc36fbSJordan K. Hubbard * 1. Redistributions of source code must retain the above copyright 1418cc36fbSJordan K. Hubbard * notice, this list of conditions and the following disclaimer. 1518cc36fbSJordan K. Hubbard * 2. Redistributions in binary form must reproduce the above copyright 1618cc36fbSJordan K. Hubbard * notice, this list of conditions and the following disclaimer in the 1718cc36fbSJordan K. Hubbard * documentation and/or other materials provided with the distribution. 18fa92e883SRuslan Ermilov * 3. Neither the name of the University nor the names of its contributors 1918cc36fbSJordan K. Hubbard * may be used to endorse or promote products derived from this software 2018cc36fbSJordan K. Hubbard * without specific prior written permission. 2118cc36fbSJordan K. Hubbard * 2218cc36fbSJordan K. Hubbard * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2318cc36fbSJordan K. Hubbard * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2418cc36fbSJordan K. Hubbard * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2518cc36fbSJordan K. Hubbard * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2618cc36fbSJordan K. Hubbard * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2718cc36fbSJordan K. Hubbard * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2818cc36fbSJordan K. Hubbard * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2918cc36fbSJordan K. Hubbard * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3018cc36fbSJordan K. Hubbard * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3118cc36fbSJordan K. Hubbard * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3218cc36fbSJordan K. Hubbard * SUCH DAMAGE. 3318cc36fbSJordan K. Hubbard */ 3418cc36fbSJordan K. Hubbard 3565785b55SMark Murray #include <sys/cdefs.h> 3665785b55SMark Murray __FBSDID("$FreeBSD$"); 3765785b55SMark Murray 3818cc36fbSJordan K. Hubbard #ifndef lint 390f3bdf5dSMark Murray #if 0 4018cc36fbSJordan K. Hubbard static char sccsid[] = "@(#)hayes.c 8.1 (Berkeley) 6/6/93"; 41fa92e883SRuslan Ermilov static const char rcsid[] = "$OpenBSD: hayes.c,v 1.13 2006/03/17 19:17:13 moritz Exp $"; 4265785b55SMark Murray #endif 4318cc36fbSJordan K. Hubbard #endif /* not lint */ 4418cc36fbSJordan K. Hubbard 4518cc36fbSJordan K. Hubbard /* 4618cc36fbSJordan K. Hubbard * Routines for calling up on a Hayes Modem 4718cc36fbSJordan K. Hubbard * (based on the old VenTel driver). 4818cc36fbSJordan K. Hubbard * The modem is expected to be strapped for "echo". 4918cc36fbSJordan K. Hubbard * Also, the switches enabling the DTR and CD lines 5018cc36fbSJordan K. Hubbard * must be set correctly. 5118cc36fbSJordan K. Hubbard * NOTICE: 5218cc36fbSJordan K. Hubbard * The easy way to hang up a modem is always simply to 5318cc36fbSJordan K. Hubbard * clear the DTR signal. However, if the +++ sequence 5418cc36fbSJordan K. Hubbard * (which switches the modem back to local mode) is sent 5518cc36fbSJordan K. Hubbard * before modem is hung up, removal of the DTR signal 5618cc36fbSJordan K. Hubbard * has no effect (except that it prevents the modem from 5718cc36fbSJordan K. Hubbard * recognizing commands). 5818cc36fbSJordan K. Hubbard * (by Helge Skrivervik, Calma Company, Sunnyvale, CA. 1984) 5918cc36fbSJordan K. Hubbard */ 6018cc36fbSJordan K. Hubbard /* 6118cc36fbSJordan K. Hubbard * TODO: 6218cc36fbSJordan K. Hubbard * It is probably not a good idea to switch the modem 6318cc36fbSJordan K. Hubbard * state between 'verbose' and terse (status messages). 6418cc36fbSJordan K. Hubbard * This should be kicked out and we should use verbose 6518cc36fbSJordan K. Hubbard * mode only. This would make it consistent with normal 6618cc36fbSJordan K. Hubbard * interactive use thru the command 'tip dialer'. 6718cc36fbSJordan K. Hubbard */ 6818cc36fbSJordan K. Hubbard #include "tip.h" 6918cc36fbSJordan K. Hubbard 700f3bdf5dSMark Murray #include <termios.h> 710f3bdf5dSMark Murray #include <sys/ioctl.h> 720f3bdf5dSMark Murray 7318cc36fbSJordan K. Hubbard #define min(a,b) ((a < b) ? a : b) 7418cc36fbSJordan K. Hubbard 75fa92e883SRuslan Ermilov static int dialtimeout = 0; 7618cc36fbSJordan K. Hubbard static jmp_buf timeoutbuf; 77fa92e883SRuslan Ermilov 7818cc36fbSJordan K. Hubbard #define DUMBUFLEN 40 7918cc36fbSJordan K. Hubbard static char dumbuf[DUMBUFLEN]; 8018cc36fbSJordan K. Hubbard 8118cc36fbSJordan K. Hubbard #define DIALING 1 8218cc36fbSJordan K. Hubbard #define IDLE 2 8318cc36fbSJordan K. Hubbard #define CONNECTED 3 8418cc36fbSJordan K. Hubbard #define FAILED 4 8518cc36fbSJordan K. Hubbard static int state = IDLE; 8618cc36fbSJordan K. Hubbard 87fa92e883SRuslan Ermilov static void sigALRM(int); 88fa92e883SRuslan Ermilov static char gobble(char *); 89fa92e883SRuslan Ermilov static void error_rep(char); 90fa92e883SRuslan Ermilov static void goodbye(void); 91fa92e883SRuslan Ermilov static int hay_sync(void); 92fa92e883SRuslan Ermilov 930f3bdf5dSMark Murray int 94fa92e883SRuslan Ermilov hay_dialer(char *num, char *acu) 9518cc36fbSJordan K. Hubbard { 960f3bdf5dSMark Murray char *cp; 970f3bdf5dSMark Murray int connected = 0; 9818cc36fbSJordan K. Hubbard char dummy; 990f3bdf5dSMark Murray struct termios cntrl; 1000f3bdf5dSMark Murray #ifdef ACULOG 10118cc36fbSJordan K. Hubbard char line[80]; 10218cc36fbSJordan K. Hubbard #endif 10318cc36fbSJordan K. Hubbard if (hay_sync() == 0) /* make sure we can talk to the modem */ 10418cc36fbSJordan K. Hubbard return(0); 10518cc36fbSJordan K. Hubbard if (boolean(value(VERBOSE))) 10618cc36fbSJordan K. Hubbard printf("\ndialing..."); 10718cc36fbSJordan K. Hubbard fflush(stdout); 1080f3bdf5dSMark Murray tcgetattr(FD, &cntrl); 1090f3bdf5dSMark Murray cntrl.c_cflag |= HUPCL; 1100f3bdf5dSMark Murray tcsetattr(FD, TCSANOW, &cntrl); 1110f3bdf5dSMark Murray tcflush(FD, TCIOFLUSH); 11218cc36fbSJordan K. Hubbard write(FD, "ATv0\r", 5); /* tell modem to use short status codes */ 11318cc36fbSJordan K. Hubbard gobble("\r"); 11418cc36fbSJordan K. Hubbard gobble("\r"); 11518cc36fbSJordan K. Hubbard write(FD, "ATTD", 4); /* send dial command */ 1160f3bdf5dSMark Murray for (cp = num; *cp; cp++) 1170f3bdf5dSMark Murray if (*cp == '=') 1180f3bdf5dSMark Murray *cp = ','; 11918cc36fbSJordan K. Hubbard write(FD, num, strlen(num)); 12018cc36fbSJordan K. Hubbard state = DIALING; 12118cc36fbSJordan K. Hubbard write(FD, "\r", 1); 12218cc36fbSJordan K. Hubbard connected = 0; 12318cc36fbSJordan K. Hubbard if (gobble("\r")) { 12418cc36fbSJordan K. Hubbard if ((dummy = gobble("01234")) != '1') 12518cc36fbSJordan K. Hubbard error_rep(dummy); 12618cc36fbSJordan K. Hubbard else 12718cc36fbSJordan K. Hubbard connected = 1; 12818cc36fbSJordan K. Hubbard } 12918cc36fbSJordan K. Hubbard if (connected) 13018cc36fbSJordan K. Hubbard state = CONNECTED; 13118cc36fbSJordan K. Hubbard else { 13218cc36fbSJordan K. Hubbard state = FAILED; 13318cc36fbSJordan K. Hubbard return (connected); /* lets get out of here.. */ 13418cc36fbSJordan K. Hubbard } 1350f3bdf5dSMark Murray tcflush(FD, TCIOFLUSH); 1360f3bdf5dSMark Murray #ifdef ACULOG 137fa92e883SRuslan Ermilov if (dialtimeout) { 138fa92e883SRuslan Ermilov (void)snprintf(line, sizeof line, "%ld second dial timeout", 13918cc36fbSJordan K. Hubbard number(value(DIALTIMEOUT))); 14018cc36fbSJordan K. Hubbard logent(value(HOST), num, "hayes", line); 14118cc36fbSJordan K. Hubbard } 14218cc36fbSJordan K. Hubbard #endif 143fa92e883SRuslan Ermilov if (dialtimeout) 14418cc36fbSJordan K. Hubbard hay_disconnect(); /* insurance */ 14518cc36fbSJordan K. Hubbard return (connected); 14618cc36fbSJordan K. Hubbard } 14718cc36fbSJordan K. Hubbard 1480f3bdf5dSMark Murray void 149fa92e883SRuslan Ermilov hay_disconnect(void) 15018cc36fbSJordan K. Hubbard { 15118cc36fbSJordan K. Hubbard /* first hang up the modem*/ 15218cc36fbSJordan K. Hubbard #ifdef DEBUG 15318cc36fbSJordan K. Hubbard printf("\rdisconnecting modem....\n\r"); 15418cc36fbSJordan K. Hubbard #endif 15518cc36fbSJordan K. Hubbard ioctl(FD, TIOCCDTR, 0); 15618cc36fbSJordan K. Hubbard sleep(1); 15718cc36fbSJordan K. Hubbard ioctl(FD, TIOCSDTR, 0); 15818cc36fbSJordan K. Hubbard goodbye(); 15918cc36fbSJordan K. Hubbard } 16018cc36fbSJordan K. Hubbard 1610f3bdf5dSMark Murray void 162fa92e883SRuslan Ermilov hay_abort(void) 16318cc36fbSJordan K. Hubbard { 16418cc36fbSJordan K. Hubbard write(FD, "\r", 1); /* send anything to abort the call */ 16518cc36fbSJordan K. Hubbard hay_disconnect(); 16618cc36fbSJordan K. Hubbard } 16718cc36fbSJordan K. Hubbard 168fa92e883SRuslan Ermilov /*ARGSUSED*/ 16918cc36fbSJordan K. Hubbard static void 170fa92e883SRuslan Ermilov sigALRM(int signo) 17118cc36fbSJordan K. Hubbard { 17218cc36fbSJordan K. Hubbard printf("\07timeout waiting for reply\n\r"); 173fa92e883SRuslan Ermilov dialtimeout = 1; 17418cc36fbSJordan K. Hubbard longjmp(timeoutbuf, 1); 17518cc36fbSJordan K. Hubbard } 17618cc36fbSJordan K. Hubbard 17718cc36fbSJordan K. Hubbard static char 178fa92e883SRuslan Ermilov gobble(char *match) 17918cc36fbSJordan K. Hubbard { 18018cc36fbSJordan K. Hubbard char c; 18118cc36fbSJordan K. Hubbard sig_t f; 18207bb01e3SRuslan Ermilov size_t i; 18307bb01e3SRuslan Ermilov int status = 0; 18418cc36fbSJordan K. Hubbard 18518cc36fbSJordan K. Hubbard f = signal(SIGALRM, sigALRM); 186fa92e883SRuslan Ermilov dialtimeout = 0; 18718cc36fbSJordan K. Hubbard #ifdef DEBUG 18818cc36fbSJordan K. Hubbard printf("\ngobble: waiting for %s\n", match); 18918cc36fbSJordan K. Hubbard #endif 19018cc36fbSJordan K. Hubbard do { 19118cc36fbSJordan K. Hubbard if (setjmp(timeoutbuf)) { 19218cc36fbSJordan K. Hubbard signal(SIGALRM, f); 19318cc36fbSJordan K. Hubbard return (0); 19418cc36fbSJordan K. Hubbard } 19518cc36fbSJordan K. Hubbard alarm(number(value(DIALTIMEOUT))); 19618cc36fbSJordan K. Hubbard read(FD, &c, 1); 19718cc36fbSJordan K. Hubbard alarm(0); 19818cc36fbSJordan K. Hubbard c &= 0177; 19918cc36fbSJordan K. Hubbard #ifdef DEBUG 20018cc36fbSJordan K. Hubbard printf("%c 0x%x ", c, c); 20118cc36fbSJordan K. Hubbard #endif 20218cc36fbSJordan K. Hubbard for (i = 0; i < strlen(match); i++) 20318cc36fbSJordan K. Hubbard if (c == match[i]) 20418cc36fbSJordan K. Hubbard status = c; 20518cc36fbSJordan K. Hubbard } while (status == 0); 20618cc36fbSJordan K. Hubbard signal(SIGALRM, SIG_DFL); 20718cc36fbSJordan K. Hubbard #ifdef DEBUG 20818cc36fbSJordan K. Hubbard printf("\n"); 20918cc36fbSJordan K. Hubbard #endif 21018cc36fbSJordan K. Hubbard return (status); 21118cc36fbSJordan K. Hubbard } 21218cc36fbSJordan K. Hubbard 2130f3bdf5dSMark Murray static void 214fa92e883SRuslan Ermilov error_rep(char c) 21518cc36fbSJordan K. Hubbard { 21618cc36fbSJordan K. Hubbard printf("\n\r"); 21718cc36fbSJordan K. Hubbard switch (c) { 21818cc36fbSJordan K. Hubbard 21918cc36fbSJordan K. Hubbard case '0': 22018cc36fbSJordan K. Hubbard printf("OK"); 22118cc36fbSJordan K. Hubbard break; 22218cc36fbSJordan K. Hubbard 22318cc36fbSJordan K. Hubbard case '1': 22418cc36fbSJordan K. Hubbard printf("CONNECT"); 22518cc36fbSJordan K. Hubbard break; 22618cc36fbSJordan K. Hubbard 22718cc36fbSJordan K. Hubbard case '2': 22818cc36fbSJordan K. Hubbard printf("RING"); 22918cc36fbSJordan K. Hubbard break; 23018cc36fbSJordan K. Hubbard 23118cc36fbSJordan K. Hubbard case '3': 23218cc36fbSJordan K. Hubbard printf("NO CARRIER"); 23318cc36fbSJordan K. Hubbard break; 23418cc36fbSJordan K. Hubbard 23518cc36fbSJordan K. Hubbard case '4': 23618cc36fbSJordan K. Hubbard printf("ERROR in input"); 23718cc36fbSJordan K. Hubbard break; 23818cc36fbSJordan K. Hubbard 23918cc36fbSJordan K. Hubbard case '5': 24018cc36fbSJordan K. Hubbard printf("CONNECT 1200"); 24118cc36fbSJordan K. Hubbard break; 24218cc36fbSJordan K. Hubbard 24318cc36fbSJordan K. Hubbard default: 24418cc36fbSJordan K. Hubbard printf("Unknown Modem error: %c (0x%x)", c, c); 24518cc36fbSJordan K. Hubbard } 24618cc36fbSJordan K. Hubbard printf("\n\r"); 24718cc36fbSJordan K. Hubbard return; 24818cc36fbSJordan K. Hubbard } 24918cc36fbSJordan K. Hubbard 25018cc36fbSJordan K. Hubbard /* 25118cc36fbSJordan K. Hubbard * set modem back to normal verbose status codes. 25218cc36fbSJordan K. Hubbard */ 253229c0017SWarner Losh static void 254229c0017SWarner Losh goodbye(void) 25518cc36fbSJordan K. Hubbard { 2560f3bdf5dSMark Murray int len; 25718cc36fbSJordan K. Hubbard char c; 25818cc36fbSJordan K. Hubbard 2590f3bdf5dSMark Murray tcflush(FD, TCIOFLUSH); 26018cc36fbSJordan K. Hubbard if (hay_sync()) { 26118cc36fbSJordan K. Hubbard sleep(1); 26218cc36fbSJordan K. Hubbard #ifndef DEBUG 2630f3bdf5dSMark Murray tcflush(FD, TCIOFLUSH); 26418cc36fbSJordan K. Hubbard #endif 26518cc36fbSJordan K. Hubbard write(FD, "ATH0\r", 5); /* insurance */ 26618cc36fbSJordan K. Hubbard #ifndef DEBUG 26718cc36fbSJordan K. Hubbard c = gobble("03"); 26818cc36fbSJordan K. Hubbard if (c != '0' && c != '3') { 26918cc36fbSJordan K. Hubbard printf("cannot hang up modem\n\r"); 27018cc36fbSJordan K. Hubbard printf("please use 'tip dialer' to make sure the line is hung up\n\r"); 27118cc36fbSJordan K. Hubbard } 27218cc36fbSJordan K. Hubbard #endif 27318cc36fbSJordan K. Hubbard sleep(1); 27418cc36fbSJordan K. Hubbard ioctl(FD, FIONREAD, &len); 27518cc36fbSJordan K. Hubbard #ifdef DEBUG 27618cc36fbSJordan K. Hubbard printf("goodbye1: len=%d -- ", len); 27718cc36fbSJordan K. Hubbard rlen = read(FD, dumbuf, min(len, DUMBUFLEN)); 27818cc36fbSJordan K. Hubbard dumbuf[rlen] = '\0'; 27918cc36fbSJordan K. Hubbard printf("read (%d): %s\r\n", rlen, dumbuf); 28018cc36fbSJordan K. Hubbard #endif 28118cc36fbSJordan K. Hubbard write(FD, "ATv1\r", 5); 28218cc36fbSJordan K. Hubbard sleep(1); 28318cc36fbSJordan K. Hubbard #ifdef DEBUG 28418cc36fbSJordan K. Hubbard ioctl(FD, FIONREAD, &len); 28518cc36fbSJordan K. Hubbard printf("goodbye2: len=%d -- ", len); 28618cc36fbSJordan K. Hubbard rlen = read(FD, dumbuf, min(len, DUMBUFLEN)); 28718cc36fbSJordan K. Hubbard dumbuf[rlen] = '\0'; 28818cc36fbSJordan K. Hubbard printf("read (%d): %s\r\n", rlen, dumbuf); 28918cc36fbSJordan K. Hubbard #endif 29018cc36fbSJordan K. Hubbard } 2910f3bdf5dSMark Murray tcflush(FD, TCIOFLUSH); 29218cc36fbSJordan K. Hubbard ioctl(FD, TIOCCDTR, 0); /* clear DTR (insurance) */ 29318cc36fbSJordan K. Hubbard close(FD); 29418cc36fbSJordan K. Hubbard } 29518cc36fbSJordan K. Hubbard 29618cc36fbSJordan K. Hubbard #define MAXRETRY 5 29718cc36fbSJordan K. Hubbard 298fa92e883SRuslan Ermilov static int 299fa92e883SRuslan Ermilov hay_sync(void) 30018cc36fbSJordan K. Hubbard { 30118cc36fbSJordan K. Hubbard int len, retry = 0; 30218cc36fbSJordan K. Hubbard 30318cc36fbSJordan K. Hubbard while (retry++ <= MAXRETRY) { 30418cc36fbSJordan K. Hubbard write(FD, "AT\r", 3); 30518cc36fbSJordan K. Hubbard sleep(1); 30618cc36fbSJordan K. Hubbard ioctl(FD, FIONREAD, &len); 30718cc36fbSJordan K. Hubbard if (len) { 30818cc36fbSJordan K. Hubbard len = read(FD, dumbuf, min(len, DUMBUFLEN)); 3090f3bdf5dSMark Murray if (strchr(dumbuf, '0') || 3100f3bdf5dSMark Murray (strchr(dumbuf, 'O') && strchr(dumbuf, 'K'))) 31118cc36fbSJordan K. Hubbard return(1); 31218cc36fbSJordan K. Hubbard #ifdef DEBUG 31318cc36fbSJordan K. Hubbard dumbuf[len] = '\0'; 31418cc36fbSJordan K. Hubbard printf("hay_sync: (\"%s\") %d\n\r", dumbuf, retry); 31518cc36fbSJordan K. Hubbard #endif 31618cc36fbSJordan K. Hubbard } 31718cc36fbSJordan K. Hubbard ioctl(FD, TIOCCDTR, 0); 31818cc36fbSJordan K. Hubbard ioctl(FD, TIOCSDTR, 0); 31918cc36fbSJordan K. Hubbard } 32018cc36fbSJordan K. Hubbard printf("Cannot synchronize with hayes...\n\r"); 32118cc36fbSJordan K. Hubbard return(0); 32218cc36fbSJordan K. Hubbard } 323