1161754Sru/* $OpenBSD: hayes.c,v 1.13 2006/03/17 19:17:13 moritz Exp $ */ 288276Smarkm/* $NetBSD: hayes.c,v 1.6 1997/02/11 09:24:17 mrg Exp $ */ 388276Smarkm 47527Sjkh/* 57527Sjkh * Copyright (c) 1983, 1993 67527Sjkh * The Regents of the University of California. All rights reserved. 77527Sjkh * 87527Sjkh * Redistribution and use in source and binary forms, with or without 97527Sjkh * modification, are permitted provided that the following conditions 107527Sjkh * are met: 117527Sjkh * 1. Redistributions of source code must retain the above copyright 127527Sjkh * notice, this list of conditions and the following disclaimer. 137527Sjkh * 2. Redistributions in binary form must reproduce the above copyright 147527Sjkh * notice, this list of conditions and the following disclaimer in the 157527Sjkh * documentation and/or other materials provided with the distribution. 16161754Sru * 3. Neither the name of the University nor the names of its contributors 177527Sjkh * may be used to endorse or promote products derived from this software 187527Sjkh * without specific prior written permission. 197527Sjkh * 207527Sjkh * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 217527Sjkh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 227527Sjkh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 237527Sjkh * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 247527Sjkh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 257527Sjkh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 267527Sjkh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 277527Sjkh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 287527Sjkh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 297527Sjkh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 307527Sjkh * SUCH DAMAGE. 317527Sjkh */ 327527Sjkh 3388276Smarkm#include <sys/cdefs.h> 3488276Smarkm__FBSDID("$FreeBSD: releng/10.3/usr.bin/tip/libacu/hayes.c 161781 2006-08-31 19:19:44Z ru $"); 3588276Smarkm 367527Sjkh#ifndef lint 3788276Smarkm#if 0 387527Sjkhstatic char sccsid[] = "@(#)hayes.c 8.1 (Berkeley) 6/6/93"; 39161754Srustatic const char rcsid[] = "$OpenBSD: hayes.c,v 1.13 2006/03/17 19:17:13 moritz Exp $"; 4088276Smarkm#endif 417527Sjkh#endif /* not lint */ 427527Sjkh 437527Sjkh/* 447527Sjkh * Routines for calling up on a Hayes Modem 457527Sjkh * (based on the old VenTel driver). 467527Sjkh * The modem is expected to be strapped for "echo". 477527Sjkh * Also, the switches enabling the DTR and CD lines 487527Sjkh * must be set correctly. 497527Sjkh * NOTICE: 507527Sjkh * The easy way to hang up a modem is always simply to 517527Sjkh * clear the DTR signal. However, if the +++ sequence 527527Sjkh * (which switches the modem back to local mode) is sent 537527Sjkh * before modem is hung up, removal of the DTR signal 547527Sjkh * has no effect (except that it prevents the modem from 557527Sjkh * recognizing commands). 5688276Smarkm * (by Helge Skrivervik, Calma Company, Sunnyvale, CA. 1984) 577527Sjkh */ 587527Sjkh/* 597527Sjkh * TODO: 607527Sjkh * It is probably not a good idea to switch the modem 617527Sjkh * state between 'verbose' and terse (status messages). 6288276Smarkm * This should be kicked out and we should use verbose 637527Sjkh * mode only. This would make it consistent with normal 647527Sjkh * interactive use thru the command 'tip dialer'. 657527Sjkh */ 667527Sjkh#include "tip.h" 677527Sjkh 6888276Smarkm#include <termios.h> 6988276Smarkm#include <sys/ioctl.h> 7088276Smarkm 717527Sjkh#define min(a,b) ((a < b) ? a : b) 727527Sjkh 73161754Srustatic int dialtimeout = 0; 747527Sjkhstatic jmp_buf timeoutbuf; 75161754Sru 767527Sjkh#define DUMBUFLEN 40 777527Sjkhstatic char dumbuf[DUMBUFLEN]; 787527Sjkh 797527Sjkh#define DIALING 1 807527Sjkh#define IDLE 2 817527Sjkh#define CONNECTED 3 827527Sjkh#define FAILED 4 837527Sjkhstatic int state = IDLE; 847527Sjkh 85161754Srustatic void sigALRM(int); 86161754Srustatic char gobble(char *); 87161754Srustatic void error_rep(char); 88161754Srustatic void goodbye(void); 89161754Srustatic int hay_sync(void); 90161754Sru 9188276Smarkmint 92161754Sruhay_dialer(char *num, char *acu) 937527Sjkh{ 9488276Smarkm char *cp; 9588276Smarkm int connected = 0; 967527Sjkh char dummy; 9788276Smarkm struct termios cntrl; 9888276Smarkm#ifdef ACULOG 997527Sjkh char line[80]; 1007527Sjkh#endif 1017527Sjkh if (hay_sync() == 0) /* make sure we can talk to the modem */ 1027527Sjkh return(0); 1037527Sjkh if (boolean(value(VERBOSE))) 1047527Sjkh printf("\ndialing..."); 1057527Sjkh fflush(stdout); 10688276Smarkm tcgetattr(FD, &cntrl); 10788276Smarkm cntrl.c_cflag |= HUPCL; 10888276Smarkm tcsetattr(FD, TCSANOW, &cntrl); 10988276Smarkm tcflush(FD, TCIOFLUSH); 1107527Sjkh write(FD, "ATv0\r", 5); /* tell modem to use short status codes */ 1117527Sjkh gobble("\r"); 1127527Sjkh gobble("\r"); 1137527Sjkh write(FD, "ATTD", 4); /* send dial command */ 11488276Smarkm for (cp = num; *cp; cp++) 11588276Smarkm if (*cp == '=') 11688276Smarkm *cp = ','; 1177527Sjkh write(FD, num, strlen(num)); 1187527Sjkh state = DIALING; 1197527Sjkh write(FD, "\r", 1); 1207527Sjkh connected = 0; 1217527Sjkh if (gobble("\r")) { 1227527Sjkh if ((dummy = gobble("01234")) != '1') 1237527Sjkh error_rep(dummy); 1247527Sjkh else 1257527Sjkh connected = 1; 1267527Sjkh } 1277527Sjkh if (connected) 1287527Sjkh state = CONNECTED; 1297527Sjkh else { 1307527Sjkh state = FAILED; 1317527Sjkh return (connected); /* lets get out of here.. */ 1327527Sjkh } 13388276Smarkm tcflush(FD, TCIOFLUSH); 13488276Smarkm#ifdef ACULOG 135161754Sru if (dialtimeout) { 136161754Sru (void)snprintf(line, sizeof line, "%ld second dial timeout", 1377527Sjkh number(value(DIALTIMEOUT))); 1387527Sjkh logent(value(HOST), num, "hayes", line); 1397527Sjkh } 1407527Sjkh#endif 141161754Sru if (dialtimeout) 1427527Sjkh hay_disconnect(); /* insurance */ 1437527Sjkh return (connected); 1447527Sjkh} 1457527Sjkh 14688276Smarkmvoid 147161754Sruhay_disconnect(void) 1487527Sjkh{ 1497527Sjkh /* first hang up the modem*/ 1507527Sjkh#ifdef DEBUG 1517527Sjkh printf("\rdisconnecting modem....\n\r"); 1527527Sjkh#endif 1537527Sjkh ioctl(FD, TIOCCDTR, 0); 1547527Sjkh sleep(1); 1557527Sjkh ioctl(FD, TIOCSDTR, 0); 1567527Sjkh goodbye(); 1577527Sjkh} 1587527Sjkh 15988276Smarkmvoid 160161754Sruhay_abort(void) 1617527Sjkh{ 1627527Sjkh write(FD, "\r", 1); /* send anything to abort the call */ 1637527Sjkh hay_disconnect(); 1647527Sjkh} 1657527Sjkh 166161754Sru/*ARGSUSED*/ 1677527Sjkhstatic void 168161754SrusigALRM(int signo) 1697527Sjkh{ 1707527Sjkh printf("\07timeout waiting for reply\n\r"); 171161754Sru dialtimeout = 1; 1727527Sjkh longjmp(timeoutbuf, 1); 1737527Sjkh} 1747527Sjkh 1757527Sjkhstatic char 176161754Srugobble(char *match) 1777527Sjkh{ 1787527Sjkh char c; 1797527Sjkh sig_t f; 180161781Sru size_t i; 181161781Sru int status = 0; 1827527Sjkh 1837527Sjkh f = signal(SIGALRM, sigALRM); 184161754Sru dialtimeout = 0; 1857527Sjkh#ifdef DEBUG 1867527Sjkh printf("\ngobble: waiting for %s\n", match); 1877527Sjkh#endif 1887527Sjkh do { 1897527Sjkh if (setjmp(timeoutbuf)) { 1907527Sjkh signal(SIGALRM, f); 1917527Sjkh return (0); 1927527Sjkh } 1937527Sjkh alarm(number(value(DIALTIMEOUT))); 1947527Sjkh read(FD, &c, 1); 1957527Sjkh alarm(0); 1967527Sjkh c &= 0177; 1977527Sjkh#ifdef DEBUG 1987527Sjkh printf("%c 0x%x ", c, c); 1997527Sjkh#endif 2007527Sjkh for (i = 0; i < strlen(match); i++) 2017527Sjkh if (c == match[i]) 2027527Sjkh status = c; 2037527Sjkh } while (status == 0); 2047527Sjkh signal(SIGALRM, SIG_DFL); 2057527Sjkh#ifdef DEBUG 2067527Sjkh printf("\n"); 2077527Sjkh#endif 2087527Sjkh return (status); 2097527Sjkh} 2107527Sjkh 21188276Smarkmstatic void 212161754Sruerror_rep(char c) 2137527Sjkh{ 2147527Sjkh printf("\n\r"); 2157527Sjkh switch (c) { 2167527Sjkh 2177527Sjkh case '0': 2187527Sjkh printf("OK"); 2197527Sjkh break; 2207527Sjkh 2217527Sjkh case '1': 2227527Sjkh printf("CONNECT"); 2237527Sjkh break; 224161754Sru 2257527Sjkh case '2': 2267527Sjkh printf("RING"); 2277527Sjkh break; 228161754Sru 2297527Sjkh case '3': 2307527Sjkh printf("NO CARRIER"); 2317527Sjkh break; 232161754Sru 2337527Sjkh case '4': 2347527Sjkh printf("ERROR in input"); 2357527Sjkh break; 236161754Sru 2377527Sjkh case '5': 2387527Sjkh printf("CONNECT 1200"); 2397527Sjkh break; 240161754Sru 2417527Sjkh default: 2427527Sjkh printf("Unknown Modem error: %c (0x%x)", c, c); 2437527Sjkh } 2447527Sjkh printf("\n\r"); 2457527Sjkh return; 2467527Sjkh} 2477527Sjkh 2487527Sjkh/* 2497527Sjkh * set modem back to normal verbose status codes. 2507527Sjkh */ 251113163Simpstatic void 252113163Simpgoodbye(void) 2537527Sjkh{ 25488276Smarkm int len; 2557527Sjkh char c; 2567527Sjkh 25788276Smarkm tcflush(FD, TCIOFLUSH); 2587527Sjkh if (hay_sync()) { 2597527Sjkh sleep(1); 2607527Sjkh#ifndef DEBUG 26188276Smarkm tcflush(FD, TCIOFLUSH); 2627527Sjkh#endif 2637527Sjkh write(FD, "ATH0\r", 5); /* insurance */ 2647527Sjkh#ifndef DEBUG 2657527Sjkh c = gobble("03"); 2667527Sjkh if (c != '0' && c != '3') { 2677527Sjkh printf("cannot hang up modem\n\r"); 2687527Sjkh printf("please use 'tip dialer' to make sure the line is hung up\n\r"); 2697527Sjkh } 2707527Sjkh#endif 2717527Sjkh sleep(1); 2727527Sjkh ioctl(FD, FIONREAD, &len); 2737527Sjkh#ifdef DEBUG 2747527Sjkh printf("goodbye1: len=%d -- ", len); 2757527Sjkh rlen = read(FD, dumbuf, min(len, DUMBUFLEN)); 2767527Sjkh dumbuf[rlen] = '\0'; 2777527Sjkh printf("read (%d): %s\r\n", rlen, dumbuf); 2787527Sjkh#endif 2797527Sjkh write(FD, "ATv1\r", 5); 2807527Sjkh sleep(1); 2817527Sjkh#ifdef DEBUG 2827527Sjkh ioctl(FD, FIONREAD, &len); 2837527Sjkh printf("goodbye2: len=%d -- ", len); 2847527Sjkh rlen = read(FD, dumbuf, min(len, DUMBUFLEN)); 2857527Sjkh dumbuf[rlen] = '\0'; 2867527Sjkh printf("read (%d): %s\r\n", rlen, dumbuf); 2877527Sjkh#endif 2887527Sjkh } 28988276Smarkm tcflush(FD, TCIOFLUSH); 2907527Sjkh ioctl(FD, TIOCCDTR, 0); /* clear DTR (insurance) */ 2917527Sjkh close(FD); 2927527Sjkh} 2937527Sjkh 2947527Sjkh#define MAXRETRY 5 2957527Sjkh 296161754Srustatic int 297161754Sruhay_sync(void) 2987527Sjkh{ 2997527Sjkh int len, retry = 0; 3007527Sjkh 3017527Sjkh while (retry++ <= MAXRETRY) { 3027527Sjkh write(FD, "AT\r", 3); 3037527Sjkh sleep(1); 3047527Sjkh ioctl(FD, FIONREAD, &len); 3057527Sjkh if (len) { 3067527Sjkh len = read(FD, dumbuf, min(len, DUMBUFLEN)); 30788276Smarkm if (strchr(dumbuf, '0') || 30888276Smarkm (strchr(dumbuf, 'O') && strchr(dumbuf, 'K'))) 3097527Sjkh return(1); 3107527Sjkh#ifdef DEBUG 3117527Sjkh dumbuf[len] = '\0'; 3127527Sjkh printf("hay_sync: (\"%s\") %d\n\r", dumbuf, retry); 3137527Sjkh#endif 3147527Sjkh } 3157527Sjkh ioctl(FD, TIOCCDTR, 0); 3167527Sjkh ioctl(FD, TIOCSDTR, 0); 3177527Sjkh } 3187527Sjkh printf("Cannot synchronize with hayes...\n\r"); 3197527Sjkh return(0); 3207527Sjkh} 321