10f3bdf5dSMark Murray /* $OpenBSD: hayes.c,v 1.8 2001/10/24 18:38:58 millert Exp $ */ 20f3bdf5dSMark Murray /* $NetBSD: hayes.c,v 1.6 1997/02/11 09:24:17 mrg Exp $ */ 30f3bdf5dSMark Murray 40f3bdf5dSMark Murray /* 50f3bdf5dSMark Murray * Copyright (c) 1983, 1993 60f3bdf5dSMark Murray * The Regents of the University of California. All rights reserved. 70f3bdf5dSMark Murray * 80f3bdf5dSMark Murray * Redistribution and use in source and binary forms, with or without 90f3bdf5dSMark Murray * modification, are permitted provided that the following conditions 100f3bdf5dSMark Murray * are met: 110f3bdf5dSMark Murray * 1. Redistributions of source code must retain the above copyright 120f3bdf5dSMark Murray * notice, this list of conditions and the following disclaimer. 130f3bdf5dSMark Murray * 2. Redistributions in binary form must reproduce the above copyright 140f3bdf5dSMark Murray * notice, this list of conditions and the following disclaimer in the 150f3bdf5dSMark Murray * documentation and/or other materials provided with the distribution. 160f3bdf5dSMark Murray * 3. All advertising materials mentioning features or use of this software 170f3bdf5dSMark Murray * must display the following acknowledgement: 180f3bdf5dSMark Murray * This product includes software developed by the University of 190f3bdf5dSMark Murray * California, Berkeley and its contributors. 200f3bdf5dSMark Murray * 4. Neither the name of the University nor the names of its contributors 210f3bdf5dSMark Murray * may be used to endorse or promote products derived from this software 220f3bdf5dSMark Murray * without specific prior written permission. 230f3bdf5dSMark Murray * 240f3bdf5dSMark Murray * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 250f3bdf5dSMark Murray * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 260f3bdf5dSMark Murray * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 270f3bdf5dSMark Murray * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 280f3bdf5dSMark Murray * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 290f3bdf5dSMark Murray * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 300f3bdf5dSMark Murray * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 310f3bdf5dSMark Murray * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 320f3bdf5dSMark Murray * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 330f3bdf5dSMark Murray * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 340f3bdf5dSMark Murray * SUCH DAMAGE. 350f3bdf5dSMark Murray */ 360f3bdf5dSMark Murray 370f3bdf5dSMark Murray #ifndef lint 380f3bdf5dSMark Murray #if 0 390f3bdf5dSMark Murray static char sccsid[] = "@(#)hayes.c 8.1 (Berkeley) 6/6/93"; 400f3bdf5dSMark Murray #endif 410f3bdf5dSMark Murray static char rcsid[] = "$OpenBSD: hayes.c,v 1.8 2001/10/24 18:38:58 millert Exp $"; 420f3bdf5dSMark Murray #endif /* not lint */ 430f3bdf5dSMark Murray 440f3bdf5dSMark Murray /* 450f3bdf5dSMark Murray * Routines for calling up on a Hayes Modem 460f3bdf5dSMark Murray * (based on the old VenTel driver). 470f3bdf5dSMark Murray * The modem is expected to be strapped for "echo". 480f3bdf5dSMark Murray * Also, the switches enabling the DTR and CD lines 490f3bdf5dSMark Murray * must be set correctly. 500f3bdf5dSMark Murray * NOTICE: 510f3bdf5dSMark Murray * The easy way to hang up a modem is always simply to 520f3bdf5dSMark Murray * clear the DTR signal. However, if the +++ sequence 530f3bdf5dSMark Murray * (which switches the modem back to local mode) is sent 540f3bdf5dSMark Murray * before modem is hung up, removal of the DTR signal 550f3bdf5dSMark Murray * has no effect (except that it prevents the modem from 560f3bdf5dSMark Murray * recognizing commands). 570f3bdf5dSMark Murray * (by Helge Skrivervik, Calma Company, Sunnyvale, CA. 1984) 580f3bdf5dSMark Murray */ 590f3bdf5dSMark Murray /* 600f3bdf5dSMark Murray * TODO: 610f3bdf5dSMark Murray * It is probably not a good idea to switch the modem 620f3bdf5dSMark Murray * state between 'verbose' and terse (status messages). 630f3bdf5dSMark Murray * This should be kicked out and we should use verbose 640f3bdf5dSMark Murray * mode only. This would make it consistent with normal 650f3bdf5dSMark Murray * interactive use thru the command 'tip dialer'. 660f3bdf5dSMark Murray */ 670f3bdf5dSMark Murray #include "tip.h" 680f3bdf5dSMark Murray 690f3bdf5dSMark Murray #include <termios.h> 700f3bdf5dSMark Murray #include <sys/ioctl.h> 710f3bdf5dSMark Murray 720f3bdf5dSMark Murray #define min(a,b) ((a < b) ? a : b) 730f3bdf5dSMark Murray 740f3bdf5dSMark Murray static void sigALRM(); 750f3bdf5dSMark Murray static int timeout = 0; 760f3bdf5dSMark Murray static jmp_buf timeoutbuf; 770f3bdf5dSMark Murray static char gobble(); 780f3bdf5dSMark Murray #define DUMBUFLEN 40 790f3bdf5dSMark Murray static char dumbuf[DUMBUFLEN]; 800f3bdf5dSMark Murray 810f3bdf5dSMark Murray #define DIALING 1 820f3bdf5dSMark Murray #define IDLE 2 830f3bdf5dSMark Murray #define CONNECTED 3 840f3bdf5dSMark Murray #define FAILED 4 850f3bdf5dSMark Murray static int state = IDLE; 860f3bdf5dSMark Murray 870f3bdf5dSMark Murray int 880f3bdf5dSMark Murray hay_dialer(num, acu) 890f3bdf5dSMark Murray char *num; 900f3bdf5dSMark Murray char *acu; 910f3bdf5dSMark Murray { 920f3bdf5dSMark Murray char *cp; 930f3bdf5dSMark Murray int connected = 0; 940f3bdf5dSMark Murray char dummy; 950f3bdf5dSMark Murray struct termios cntrl; 960f3bdf5dSMark Murray #ifdef ACULOG 970f3bdf5dSMark Murray char line[80]; 980f3bdf5dSMark Murray #endif 990f3bdf5dSMark Murray if (hay_sync() == 0) /* make sure we can talk to the modem */ 1000f3bdf5dSMark Murray return(0); 1010f3bdf5dSMark Murray if (boolean(value(VERBOSE))) 1020f3bdf5dSMark Murray printf("\ndialing..."); 1030f3bdf5dSMark Murray fflush(stdout); 1040f3bdf5dSMark Murray tcgetattr(FD, &cntrl); 1050f3bdf5dSMark Murray cntrl.c_cflag |= HUPCL; 1060f3bdf5dSMark Murray tcsetattr(FD, TCSANOW, &cntrl); 1070f3bdf5dSMark Murray tcflush(FD, TCIOFLUSH); 1080f3bdf5dSMark Murray write(FD, "ATv0\r", 5); /* tell modem to use short status codes */ 1090f3bdf5dSMark Murray gobble("\r"); 1100f3bdf5dSMark Murray gobble("\r"); 1110f3bdf5dSMark Murray write(FD, "ATTD", 4); /* send dial command */ 1120f3bdf5dSMark Murray for (cp = num; *cp; cp++) 1130f3bdf5dSMark Murray if (*cp == '=') 1140f3bdf5dSMark Murray *cp = ','; 1150f3bdf5dSMark Murray write(FD, num, strlen(num)); 1160f3bdf5dSMark Murray state = DIALING; 1170f3bdf5dSMark Murray write(FD, "\r", 1); 1180f3bdf5dSMark Murray connected = 0; 1190f3bdf5dSMark Murray if (gobble("\r")) { 1200f3bdf5dSMark Murray if ((dummy = gobble("01234")) != '1') 1210f3bdf5dSMark Murray error_rep(dummy); 1220f3bdf5dSMark Murray else 1230f3bdf5dSMark Murray connected = 1; 1240f3bdf5dSMark Murray } 1250f3bdf5dSMark Murray if (connected) 1260f3bdf5dSMark Murray state = CONNECTED; 1270f3bdf5dSMark Murray else { 1280f3bdf5dSMark Murray state = FAILED; 1290f3bdf5dSMark Murray return (connected); /* lets get out of here.. */ 1300f3bdf5dSMark Murray } 1310f3bdf5dSMark Murray tcflush(FD, TCIOFLUSH); 1320f3bdf5dSMark Murray #ifdef ACULOG 1330f3bdf5dSMark Murray if (timeout) { 1340f3bdf5dSMark Murray (void)sprintf(line, "%ld second dial timeout", 1350f3bdf5dSMark Murray number(value(DIALTIMEOUT))); 1360f3bdf5dSMark Murray logent(value(HOST), num, "hayes", line); 1370f3bdf5dSMark Murray } 1380f3bdf5dSMark Murray #endif 1390f3bdf5dSMark Murray if (timeout) 1400f3bdf5dSMark Murray hay_disconnect(); /* insurance */ 1410f3bdf5dSMark Murray return (connected); 1420f3bdf5dSMark Murray } 1430f3bdf5dSMark Murray 1440f3bdf5dSMark Murray 1450f3bdf5dSMark Murray void 1460f3bdf5dSMark Murray hay_disconnect() 1470f3bdf5dSMark Murray { 1480f3bdf5dSMark Murray /* first hang up the modem*/ 1490f3bdf5dSMark Murray #ifdef DEBUG 1500f3bdf5dSMark Murray printf("\rdisconnecting modem....\n\r"); 1510f3bdf5dSMark Murray #endif 1520f3bdf5dSMark Murray ioctl(FD, TIOCCDTR, 0); 1530f3bdf5dSMark Murray sleep(1); 1540f3bdf5dSMark Murray ioctl(FD, TIOCSDTR, 0); 1550f3bdf5dSMark Murray goodbye(); 1560f3bdf5dSMark Murray } 1570f3bdf5dSMark Murray 1580f3bdf5dSMark Murray void 1590f3bdf5dSMark Murray hay_abort() 1600f3bdf5dSMark Murray { 1610f3bdf5dSMark Murray 1620f3bdf5dSMark Murray write(FD, "\r", 1); /* send anything to abort the call */ 1630f3bdf5dSMark Murray hay_disconnect(); 1640f3bdf5dSMark Murray } 1650f3bdf5dSMark Murray 1660f3bdf5dSMark Murray static void 1670f3bdf5dSMark Murray sigALRM() 1680f3bdf5dSMark Murray { 1690f3bdf5dSMark Murray 1700f3bdf5dSMark Murray printf("\07timeout waiting for reply\n\r"); 1710f3bdf5dSMark Murray timeout = 1; 1720f3bdf5dSMark Murray longjmp(timeoutbuf, 1); 1730f3bdf5dSMark Murray } 1740f3bdf5dSMark Murray 1750f3bdf5dSMark Murray static char 1760f3bdf5dSMark Murray gobble(match) 1770f3bdf5dSMark Murray char *match; 1780f3bdf5dSMark Murray { 1790f3bdf5dSMark Murray char c; 1800f3bdf5dSMark Murray sig_t f; 1810f3bdf5dSMark Murray int i, status = 0; 1820f3bdf5dSMark Murray 1830f3bdf5dSMark Murray f = signal(SIGALRM, sigALRM); 1840f3bdf5dSMark Murray timeout = 0; 1850f3bdf5dSMark Murray #ifdef DEBUG 1860f3bdf5dSMark Murray printf("\ngobble: waiting for %s\n", match); 1870f3bdf5dSMark Murray #endif 1880f3bdf5dSMark Murray do { 1890f3bdf5dSMark Murray if (setjmp(timeoutbuf)) { 1900f3bdf5dSMark Murray signal(SIGALRM, f); 1910f3bdf5dSMark Murray return (0); 1920f3bdf5dSMark Murray } 1930f3bdf5dSMark Murray alarm(number(value(DIALTIMEOUT))); 1940f3bdf5dSMark Murray read(FD, &c, 1); 1950f3bdf5dSMark Murray alarm(0); 1960f3bdf5dSMark Murray c &= 0177; 1970f3bdf5dSMark Murray #ifdef DEBUG 1980f3bdf5dSMark Murray printf("%c 0x%x ", c, c); 1990f3bdf5dSMark Murray #endif 2000f3bdf5dSMark Murray for (i = 0; i < strlen(match); i++) 2010f3bdf5dSMark Murray if (c == match[i]) 2020f3bdf5dSMark Murray status = c; 2030f3bdf5dSMark Murray } while (status == 0); 2040f3bdf5dSMark Murray signal(SIGALRM, SIG_DFL); 2050f3bdf5dSMark Murray #ifdef DEBUG 2060f3bdf5dSMark Murray printf("\n"); 2070f3bdf5dSMark Murray #endif 2080f3bdf5dSMark Murray return (status); 2090f3bdf5dSMark Murray } 2100f3bdf5dSMark Murray 2110f3bdf5dSMark Murray static void 2120f3bdf5dSMark Murray error_rep(c) 2130f3bdf5dSMark Murray char c; 2140f3bdf5dSMark Murray { 2150f3bdf5dSMark Murray printf("\n\r"); 2160f3bdf5dSMark Murray switch (c) { 2170f3bdf5dSMark Murray 2180f3bdf5dSMark Murray case '0': 2190f3bdf5dSMark Murray printf("OK"); 2200f3bdf5dSMark Murray break; 2210f3bdf5dSMark Murray 2220f3bdf5dSMark Murray case '1': 2230f3bdf5dSMark Murray printf("CONNECT"); 2240f3bdf5dSMark Murray break; 2250f3bdf5dSMark Murray 2260f3bdf5dSMark Murray case '2': 2270f3bdf5dSMark Murray printf("RING"); 2280f3bdf5dSMark Murray break; 2290f3bdf5dSMark Murray 2300f3bdf5dSMark Murray case '3': 2310f3bdf5dSMark Murray printf("NO CARRIER"); 2320f3bdf5dSMark Murray break; 2330f3bdf5dSMark Murray 2340f3bdf5dSMark Murray case '4': 2350f3bdf5dSMark Murray printf("ERROR in input"); 2360f3bdf5dSMark Murray break; 2370f3bdf5dSMark Murray 2380f3bdf5dSMark Murray case '5': 2390f3bdf5dSMark Murray printf("CONNECT 1200"); 2400f3bdf5dSMark Murray break; 2410f3bdf5dSMark Murray 2420f3bdf5dSMark Murray default: 2430f3bdf5dSMark Murray printf("Unknown Modem error: %c (0x%x)", c, c); 2440f3bdf5dSMark Murray } 2450f3bdf5dSMark Murray printf("\n\r"); 2460f3bdf5dSMark Murray return; 2470f3bdf5dSMark Murray } 2480f3bdf5dSMark Murray 2490f3bdf5dSMark Murray /* 2500f3bdf5dSMark Murray * set modem back to normal verbose status codes. 2510f3bdf5dSMark Murray */ 2520f3bdf5dSMark Murray void 2530f3bdf5dSMark Murray goodbye() 2540f3bdf5dSMark Murray { 2550f3bdf5dSMark Murray int len; 2560f3bdf5dSMark Murray char c; 2570f3bdf5dSMark Murray 2580f3bdf5dSMark Murray tcflush(FD, TCIOFLUSH); 2590f3bdf5dSMark Murray if (hay_sync()) { 2600f3bdf5dSMark Murray sleep(1); 2610f3bdf5dSMark Murray #ifndef DEBUG 2620f3bdf5dSMark Murray tcflush(FD, TCIOFLUSH); 2630f3bdf5dSMark Murray #endif 2640f3bdf5dSMark Murray write(FD, "ATH0\r", 5); /* insurance */ 2650f3bdf5dSMark Murray #ifndef DEBUG 2660f3bdf5dSMark Murray c = gobble("03"); 2670f3bdf5dSMark Murray if (c != '0' && c != '3') { 2680f3bdf5dSMark Murray printf("cannot hang up modem\n\r"); 2690f3bdf5dSMark Murray printf("please use 'tip dialer' to make sure the line is hung up\n\r"); 2700f3bdf5dSMark Murray } 2710f3bdf5dSMark Murray #endif 2720f3bdf5dSMark Murray sleep(1); 2730f3bdf5dSMark Murray ioctl(FD, FIONREAD, &len); 2740f3bdf5dSMark Murray #ifdef DEBUG 2750f3bdf5dSMark Murray printf("goodbye1: len=%d -- ", len); 2760f3bdf5dSMark Murray rlen = read(FD, dumbuf, min(len, DUMBUFLEN)); 2770f3bdf5dSMark Murray dumbuf[rlen] = '\0'; 2780f3bdf5dSMark Murray printf("read (%d): %s\r\n", rlen, dumbuf); 2790f3bdf5dSMark Murray #endif 2800f3bdf5dSMark Murray write(FD, "ATv1\r", 5); 2810f3bdf5dSMark Murray sleep(1); 2820f3bdf5dSMark Murray #ifdef DEBUG 2830f3bdf5dSMark Murray ioctl(FD, FIONREAD, &len); 2840f3bdf5dSMark Murray printf("goodbye2: len=%d -- ", len); 2850f3bdf5dSMark Murray rlen = read(FD, dumbuf, min(len, DUMBUFLEN)); 2860f3bdf5dSMark Murray dumbuf[rlen] = '\0'; 2870f3bdf5dSMark Murray printf("read (%d): %s\r\n", rlen, dumbuf); 2880f3bdf5dSMark Murray #endif 2890f3bdf5dSMark Murray } 2900f3bdf5dSMark Murray tcflush(FD, TCIOFLUSH); 2910f3bdf5dSMark Murray ioctl(FD, TIOCCDTR, 0); /* clear DTR (insurance) */ 2920f3bdf5dSMark Murray close(FD); 2930f3bdf5dSMark Murray } 2940f3bdf5dSMark Murray 2950f3bdf5dSMark Murray #define MAXRETRY 5 2960f3bdf5dSMark Murray 2970f3bdf5dSMark Murray int 2980f3bdf5dSMark Murray hay_sync() 2990f3bdf5dSMark Murray { 3000f3bdf5dSMark Murray int len, retry = 0; 3010f3bdf5dSMark Murray 3020f3bdf5dSMark Murray while (retry++ <= MAXRETRY) { 3030f3bdf5dSMark Murray write(FD, "AT\r", 3); 3040f3bdf5dSMark Murray sleep(1); 3050f3bdf5dSMark Murray ioctl(FD, FIONREAD, &len); 3060f3bdf5dSMark Murray if (len) { 3070f3bdf5dSMark Murray len = read(FD, dumbuf, min(len, DUMBUFLEN)); 3080f3bdf5dSMark Murray if (strchr(dumbuf, '0') || 3090f3bdf5dSMark Murray (strchr(dumbuf, 'O') && strchr(dumbuf, 'K'))) 3100f3bdf5dSMark Murray return(1); 3110f3bdf5dSMark Murray #ifdef DEBUG 3120f3bdf5dSMark Murray dumbuf[len] = '\0'; 3130f3bdf5dSMark Murray printf("hay_sync: (\"%s\") %d\n\r", dumbuf, retry); 3140f3bdf5dSMark Murray #endif 3150f3bdf5dSMark Murray } 3160f3bdf5dSMark Murray ioctl(FD, TIOCCDTR, 0); 3170f3bdf5dSMark Murray ioctl(FD, TIOCSDTR, 0); 3180f3bdf5dSMark Murray } 3190f3bdf5dSMark Murray printf("Cannot synchronize with hayes...\n\r"); 3200f3bdf5dSMark Murray return(0); 3210f3bdf5dSMark Murray } 322