1156952Sume/* $OpenBSD: hayes.c,v 1.13 2006/03/17 19:17:13 moritz Exp $ */ 2156952Sume/* $NetBSD: hayes.c,v 1.6 1997/02/11 09:24:17 mrg Exp $ */ 3156952Sume 4156952Sume/* 5156952Sume * Copyright (c) 1983, 1993 6156952Sume * The Regents of the University of California. All rights reserved. 7156952Sume * 8156952Sume * Redistribution and use in source and binary forms, with or without 9156952Sume * modification, are permitted provided that the following conditions 10156952Sume * are met: 11156952Sume * 1. Redistributions of source code must retain the above copyright 12156952Sume * notice, this list of conditions and the following disclaimer. 13156952Sume * 2. Redistributions in binary form must reproduce the above copyright 14156952Sume * notice, this list of conditions and the following disclaimer in the 15156952Sume * documentation and/or other materials provided with the distribution. 16156952Sume * 3. Neither the name of the University nor the names of its contributors 17156952Sume * may be used to endorse or promote products derived from this software 18156952Sume * without specific prior written permission. 19156952Sume * 20156952Sume * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21156952Sume * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22156952Sume * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23156952Sume * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24156952Sume * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25156952Sume * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26156952Sume * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27156952Sume * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28156952Sume * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29156952Sume * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30156952Sume * SUCH DAMAGE. 31156952Sume */ 32156952Sume 33156952Sume#include <sys/cdefs.h> 34156952Sume__FBSDID("$FreeBSD$"); 35156952Sume 36156952Sume#ifndef lint 37156952Sume#if 0 38156952Sumestatic char sccsid[] = "@(#)hayes.c 8.1 (Berkeley) 6/6/93"; 39156952Sumestatic const char rcsid[] = "$OpenBSD: hayes.c,v 1.13 2006/03/17 19:17:13 moritz Exp $"; 40156952Sume#endif 41156952Sume#endif /* not lint */ 42156952Sume 43156952Sume/* 44156952Sume * Routines for calling up on a Hayes Modem 45156952Sume * (based on the old VenTel driver). 46156952Sume * The modem is expected to be strapped for "echo". 47156952Sume * Also, the switches enabling the DTR and CD lines 48156952Sume * must be set correctly. 49156952Sume * NOTICE: 50156952Sume * The easy way to hang up a modem is always simply to 51156952Sume * clear the DTR signal. However, if the +++ sequence 52156952Sume * (which switches the modem back to local mode) is sent 53156952Sume * before modem is hung up, removal of the DTR signal 54156952Sume * has no effect (except that it prevents the modem from 55156952Sume * recognizing commands). 56156952Sume * (by Helge Skrivervik, Calma Company, Sunnyvale, CA. 1984) 57156952Sume */ 58156952Sume/* 59156952Sume * TODO: 60156952Sume * It is probably not a good idea to switch the modem 61156952Sume * state between 'verbose' and terse (status messages). 62156952Sume * This should be kicked out and we should use verbose 63156952Sume * mode only. This would make it consistent with normal 64156952Sume * interactive use thru the command 'tip dialer'. 65156952Sume */ 66156952Sume#include "tip.h" 67156952Sume 68156952Sume#include <termios.h> 69156952Sume#include <sys/ioctl.h> 70156952Sume 71156952Sume#define min(a,b) ((a < b) ? a : b) 72156952Sume 73156952Sumestatic int dialtimeout = 0; 74156952Sumestatic jmp_buf timeoutbuf; 75156952Sume 76156952Sume#define DUMBUFLEN 40 77156952Sumestatic char dumbuf[DUMBUFLEN]; 78156952Sume 79156952Sume#define DIALING 1 80156952Sume#define IDLE 2 81156952Sume#define CONNECTED 3 82156952Sume#define FAILED 4 83156952Sumestatic int state = IDLE; 84156952Sume 85156952Sumestatic void sigALRM(int); 86156952Sumestatic char gobble(char *); 87156952Sumestatic void error_rep(char); 88156952Sumestatic void goodbye(void); 89156952Sumestatic int hay_sync(void); 90156952Sume 91156952Sumeint 92156952Sumehay_dialer(char *num, char *acu) 93156952Sume{ 94156952Sume char *cp; 95156952Sume int connected = 0; 96156952Sume char dummy; 97156952Sume struct termios cntrl; 98156952Sume#ifdef ACULOG 99156952Sume char line[80]; 100156952Sume#endif 101156952Sume if (hay_sync() == 0) /* make sure we can talk to the modem */ 102156952Sume return(0); 103156952Sume if (boolean(value(VERBOSE))) 104156952Sume printf("\ndialing..."); 105156952Sume fflush(stdout); 106156952Sume tcgetattr(FD, &cntrl); 107156952Sume cntrl.c_cflag |= HUPCL; 108156952Sume tcsetattr(FD, TCSANOW, &cntrl); 109156952Sume tcflush(FD, TCIOFLUSH); 110156952Sume write(FD, "ATv0\r", 5); /* tell modem to use short status codes */ 111156952Sume gobble("\r"); 112156952Sume gobble("\r"); 113156952Sume write(FD, "ATTD", 4); /* send dial command */ 114156952Sume for (cp = num; *cp; cp++) 115156952Sume if (*cp == '=') 116156952Sume *cp = ','; 117156952Sume write(FD, num, strlen(num)); 118156952Sume state = DIALING; 119156952Sume write(FD, "\r", 1); 120156952Sume connected = 0; 121156952Sume if (gobble("\r")) { 122156952Sume if ((dummy = gobble("01234")) != '1') 123156952Sume error_rep(dummy); 124156952Sume else 125156952Sume connected = 1; 126156952Sume } 127156952Sume if (connected) 128156952Sume state = CONNECTED; 129156952Sume else { 130156952Sume state = FAILED; 131156952Sume return (connected); /* lets get out of here.. */ 132156952Sume } 133156952Sume tcflush(FD, TCIOFLUSH); 134156952Sume#ifdef ACULOG 135156952Sume if (dialtimeout) { 136156952Sume (void)snprintf(line, sizeof line, "%ld second dial timeout", 137156952Sume number(value(DIALTIMEOUT))); 138156952Sume logent(value(HOST), num, "hayes", line); 139156952Sume } 140156952Sume#endif 141156952Sume if (dialtimeout) 142156952Sume hay_disconnect(); /* insurance */ 143156952Sume return (connected); 144156952Sume} 145156952Sume 146156952Sumevoid 147156952Sumehay_disconnect(void) 148156952Sume{ 149156952Sume /* first hang up the modem*/ 150156952Sume#ifdef DEBUG 151156952Sume printf("\rdisconnecting modem....\n\r"); 152156952Sume#endif 153156952Sume ioctl(FD, TIOCCDTR, 0); 154156952Sume sleep(1); 155156952Sume ioctl(FD, TIOCSDTR, 0); 156156952Sume goodbye(); 157156952Sume} 158156952Sume 159156952Sumevoid 160156952Sumehay_abort(void) 161156952Sume{ 162156952Sume write(FD, "\r", 1); /* send anything to abort the call */ 163156952Sume hay_disconnect(); 164156952Sume} 165156952Sume 166156952Sume/*ARGSUSED*/ 167156952Sumestatic void 168156952SumesigALRM(int signo) 169156952Sume{ 170156952Sume printf("\07timeout waiting for reply\n\r"); 171156952Sume dialtimeout = 1; 172156952Sume longjmp(timeoutbuf, 1); 173156952Sume} 174156952Sume 175156952Sumestatic char 176156952Sumegobble(char *match) 177156952Sume{ 178156952Sume char c; 179156952Sume sig_t f; 180156952Sume size_t i; 181156952Sume int status = 0; 182156952Sume 183156952Sume f = signal(SIGALRM, sigALRM); 184156952Sume dialtimeout = 0; 185156952Sume#ifdef DEBUG 186156952Sume printf("\ngobble: waiting for %s\n", match); 187156952Sume#endif 188156952Sume do { 189156952Sume if (setjmp(timeoutbuf)) { 190156952Sume signal(SIGALRM, f); 191156952Sume return (0); 192156952Sume } 193156952Sume alarm(number(value(DIALTIMEOUT))); 194156952Sume read(FD, &c, 1); 195156952Sume alarm(0); 196156952Sume c &= 0177; 197156952Sume#ifdef DEBUG 198156952Sume printf("%c 0x%x ", c, c); 199156952Sume#endif 200156952Sume for (i = 0; i < strlen(match); i++) 201156952Sume if (c == match[i]) 202156952Sume status = c; 203156952Sume } while (status == 0); 204156952Sume signal(SIGALRM, SIG_DFL); 205156952Sume#ifdef DEBUG 206156952Sume printf("\n"); 207156952Sume#endif 208156952Sume return (status); 209156952Sume} 210156952Sume 211156952Sumestatic void 212156952Sumeerror_rep(char c) 213156952Sume{ 214156952Sume printf("\n\r"); 215156952Sume switch (c) { 216156952Sume 217156952Sume case '0': 218156952Sume printf("OK"); 219156952Sume break; 220156952Sume 221156952Sume case '1': 222156952Sume printf("CONNECT"); 223156952Sume break; 224156952Sume 225156952Sume case '2': 226156952Sume printf("RING"); 227156952Sume break; 228156952Sume 229156952Sume case '3': 230156952Sume printf("NO CARRIER"); 231156952Sume break; 232156952Sume 233156952Sume case '4': 234156952Sume printf("ERROR in input"); 235156952Sume break; 236156952Sume 237156952Sume case '5': 238156952Sume printf("CONNECT 1200"); 239156952Sume break; 240156952Sume 241156952Sume default: 242156952Sume printf("Unknown Modem error: %c (0x%x)", c, c); 243156952Sume } 244156952Sume printf("\n\r"); 245156952Sume return; 246156952Sume} 247156952Sume 248156952Sume/* 249156952Sume * set modem back to normal verbose status codes. 250156952Sume */ 251156952Sumestatic void 252156952Sumegoodbye(void) 253156952Sume{ 254156952Sume int len; 255156952Sume char c; 256156952Sume 257156952Sume tcflush(FD, TCIOFLUSH); 258156952Sume if (hay_sync()) { 259156952Sume sleep(1); 260156952Sume#ifndef DEBUG 261156952Sume tcflush(FD, TCIOFLUSH); 262156952Sume#endif 263156952Sume write(FD, "ATH0\r", 5); /* insurance */ 264156952Sume#ifndef DEBUG 265156952Sume c = gobble("03"); 266156952Sume if (c != '0' && c != '3') { 267156952Sume printf("cannot hang up modem\n\r"); 268156952Sume printf("please use 'tip dialer' to make sure the line is hung up\n\r"); 269156952Sume } 270156952Sume#endif 271156952Sume sleep(1); 272156952Sume ioctl(FD, FIONREAD, &len); 273156952Sume#ifdef DEBUG 274156952Sume printf("goodbye1: len=%d -- ", len); 275156952Sume rlen = read(FD, dumbuf, min(len, DUMBUFLEN)); 276156952Sume dumbuf[rlen] = '\0'; 277156952Sume printf("read (%d): %s\r\n", rlen, dumbuf); 278156952Sume#endif 279156952Sume write(FD, "ATv1\r", 5); 280156952Sume sleep(1); 281156952Sume#ifdef DEBUG 282156952Sume ioctl(FD, FIONREAD, &len); 283156952Sume printf("goodbye2: len=%d -- ", len); 284156952Sume rlen = read(FD, dumbuf, min(len, DUMBUFLEN)); 285156952Sume dumbuf[rlen] = '\0'; 286156952Sume printf("read (%d): %s\r\n", rlen, dumbuf); 287156952Sume#endif 288156952Sume } 289156952Sume tcflush(FD, TCIOFLUSH); 290156952Sume ioctl(FD, TIOCCDTR, 0); /* clear DTR (insurance) */ 291156952Sume close(FD); 292156952Sume} 293156952Sume 294156952Sume#define MAXRETRY 5 295156952Sume 296156952Sumestatic int 297156952Sumehay_sync(void) 298156952Sume{ 299156952Sume int len, retry = 0; 300156952Sume 301156952Sume while (retry++ <= MAXRETRY) { 302156952Sume write(FD, "AT\r", 3); 303156952Sume sleep(1); 304156952Sume ioctl(FD, FIONREAD, &len); 305156952Sume if (len) { 306156952Sume len = read(FD, dumbuf, min(len, DUMBUFLEN)); 307156952Sume if (strchr(dumbuf, '0') || 308156952Sume (strchr(dumbuf, 'O') && strchr(dumbuf, 'K'))) 309156952Sume return(1); 310156952Sume#ifdef DEBUG 311156952Sume dumbuf[len] = '\0'; 312156952Sume printf("hay_sync: (\"%s\") %d\n\r", dumbuf, retry); 313156952Sume#endif 314156952Sume } 315156952Sume ioctl(FD, TIOCCDTR, 0); 316156952Sume ioctl(FD, TIOCSDTR, 0); 317156952Sume } 318156952Sume printf("Cannot synchronize with hayes...\n\r"); 319156952Sume return(0); 320156952Sume} 321156952Sume