1 /* $NetBSD: hayes.c,v 1.10 2004/04/23 22:11:44 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1983, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 #if 0 35 static char sccsid[] = "@(#)hayes.c 8.1 (Berkeley) 6/6/93"; 36 #endif 37 __RCSID("$NetBSD: hayes.c,v 1.10 2004/04/23 22:11:44 christos Exp $"); 38 #endif /* not lint */ 39 40 /* 41 * Routines for calling up on a Hayes Modem 42 * (based on the old VenTel driver). 43 * The modem is expected to be strapped for "echo". 44 * Also, the switches enabling the DTR and CD lines 45 * must be set correctly. 46 * NOTICE: 47 * The easy way to hang up a modem is always simply to 48 * clear the DTR signal. However, if the +++ sequence 49 * (which switches the modem back to local mode) is sent 50 * before modem is hung up, removal of the DTR signal 51 * has no effect (except that it prevents the modem from 52 * recognizing commands). 53 * (by Helge Skrivervik, Calma Company, Sunnyvale, CA. 1984) 54 */ 55 /* 56 * TODO: 57 * It is probably not a good idea to switch the modem 58 * state between 'verbose' and terse (status messages). 59 * This should be kicked out and we should use verbose 60 * mode only. This would make it consistent with normal 61 * interactive use thru the command 'tip dialer'. 62 */ 63 #include "tip.h" 64 65 #define min(a,b) ((a < b) ? a : b) 66 67 static int timeout = 0; 68 static jmp_buf timeoutbuf; 69 #define DUMBUFLEN 40 70 static char dumbuf[DUMBUFLEN]; 71 72 #define DIALING 1 73 #define IDLE 2 74 #define CONNECTED 3 75 #define FAILED 4 76 static int state = IDLE; 77 78 static void error_rep __P((char)); 79 static char gobble __P((const char *)); 80 static void goodbye __P((void)); 81 static int hay_sync __P((void)); 82 static void sigALRM __P((int)); 83 84 int 85 hay_dialer(num, acu) 86 char *num; 87 char *acu; 88 { 89 char *cp; 90 int connected = 0; 91 char dummy; 92 struct termios cntrl; 93 #ifdef ACULOG 94 char line[80]; 95 #endif 96 if (hay_sync() == 0) /* make sure we can talk to the modem */ 97 return(0); 98 if (boolean(value(VERBOSE))) 99 printf("\ndialing..."); 100 fflush(stdout); 101 tcgetattr(FD, &cntrl); 102 cntrl.c_cflag |= HUPCL; 103 tcsetattr(FD, TCSANOW, &cntrl); 104 tcflush(FD, TCIOFLUSH); 105 write(FD, "ATv0\r", 5); /* tell modem to use short status codes */ 106 gobble("\r"); 107 gobble("\r"); 108 write(FD, "ATTD", 4); /* send dial command */ 109 for (cp = num; *cp; cp++) 110 if (*cp == '=') 111 *cp = ','; 112 write(FD, num, strlen(num)); 113 state = DIALING; 114 write(FD, "\r", 1); 115 connected = 0; 116 if (gobble("\r")) { 117 if ((dummy = gobble("01234")) != '1') 118 error_rep(dummy); 119 else 120 connected = 1; 121 } 122 if (connected) 123 state = CONNECTED; 124 else { 125 state = FAILED; 126 return (connected); /* lets get out of here.. */ 127 } 128 tcflush(FD, TCIOFLUSH); 129 #ifdef ACULOG 130 if (timeout) { 131 (void)snprintf(line, sizeof line, "%d second dial timeout", 132 (int)number(value(DIALTIMEOUT))); 133 logent(value(HOST), num, "hayes", line); 134 } 135 #endif 136 if (timeout) 137 hay_disconnect(); /* insurance */ 138 return (connected); 139 } 140 141 142 void 143 hay_disconnect() 144 { 145 146 /* first hang up the modem*/ 147 #ifdef DEBUG 148 printf("\rdisconnecting modem....\n\r"); 149 #endif 150 ioctl(FD, TIOCCDTR, 0); 151 sleep(1); 152 ioctl(FD, TIOCSDTR, 0); 153 goodbye(); 154 } 155 156 void 157 hay_abort() 158 { 159 160 write(FD, "\r", 1); /* send anything to abort the call */ 161 hay_disconnect(); 162 } 163 164 static void 165 sigALRM(dummy) 166 int dummy; 167 { 168 169 printf("\07timeout waiting for reply\n\r"); 170 timeout = 1; 171 longjmp(timeoutbuf, 1); 172 } 173 174 static char 175 gobble(match) 176 const char *match; 177 { 178 char c; 179 sig_t f; 180 int i, status = 0; 181 182 #if __GNUC__ /* XXX pacify gcc */ 183 (void)&status; 184 #endif 185 186 f = signal(SIGALRM, sigALRM); 187 timeout = 0; 188 #ifdef DEBUG 189 printf("\ngobble: waiting for %s\n", match); 190 #endif 191 do { 192 if (setjmp(timeoutbuf)) { 193 signal(SIGALRM, f); 194 return (0); 195 } 196 alarm(number(value(DIALTIMEOUT))); 197 read(FD, &c, 1); 198 alarm(0); 199 c &= 0177; 200 #ifdef DEBUG 201 printf("%c 0x%x ", c, c); 202 #endif 203 for (i = 0; i < strlen(match); i++) 204 if (c == match[i]) 205 status = c; 206 } while (status == 0); 207 signal(SIGALRM, SIG_DFL); 208 #ifdef DEBUG 209 printf("\n"); 210 #endif 211 return (status); 212 } 213 214 static void 215 error_rep(c) 216 char c; 217 { 218 219 printf("\n\r"); 220 switch (c) { 221 222 case '0': 223 printf("OK"); 224 break; 225 226 case '1': 227 printf("CONNECT"); 228 break; 229 230 case '2': 231 printf("RING"); 232 break; 233 234 case '3': 235 printf("NO CARRIER"); 236 break; 237 238 case '4': 239 printf("ERROR in input"); 240 break; 241 242 case '5': 243 printf("CONNECT 1200"); 244 break; 245 246 default: 247 printf("Unknown Modem error: %c (0x%x)", c, c); 248 } 249 printf("\n\r"); 250 return; 251 } 252 253 /* 254 * set modem back to normal verbose status codes. 255 */ 256 void 257 goodbye() 258 { 259 int len; 260 char c; 261 262 tcflush(FD, TCIOFLUSH); 263 if (hay_sync()) { 264 sleep(1); 265 #ifndef DEBUG 266 tcflush(FD, TCIOFLUSH); 267 #endif 268 write(FD, "ATH0\r", 5); /* insurance */ 269 #ifndef DEBUG 270 c = gobble("03"); 271 if (c != '0' && c != '3') { 272 printf("cannot hang up modem\n\r"); 273 printf("please use 'tip dialer' to make sure the line is hung up\n\r"); 274 } 275 #endif 276 sleep(1); 277 ioctl(FD, FIONREAD, &len); 278 #ifdef DEBUG 279 printf("goodbye1: len=%d -- ", len); 280 rlen = read(FD, dumbuf, min(len, DUMBUFLEN)); 281 dumbuf[rlen] = '\0'; 282 printf("read (%d): %s\r\n", rlen, dumbuf); 283 #endif 284 write(FD, "ATv1\r", 5); 285 sleep(1); 286 #ifdef DEBUG 287 ioctl(FD, FIONREAD, &len); 288 printf("goodbye2: len=%d -- ", len); 289 rlen = read(FD, dumbuf, min(len, DUMBUFLEN)); 290 dumbuf[rlen] = '\0'; 291 printf("read (%d): %s\r\n", rlen, dumbuf); 292 #endif 293 } 294 tcflush(FD, TCIOFLUSH); 295 ioctl(FD, TIOCCDTR, 0); /* clear DTR (insurance) */ 296 close(FD); 297 } 298 299 #define MAXRETRY 5 300 301 int 302 hay_sync() 303 { 304 int len, retry = 0; 305 306 while (retry++ <= MAXRETRY) { 307 write(FD, "AT\r", 3); 308 sleep(1); 309 ioctl(FD, FIONREAD, &len); 310 if (len) { 311 len = read(FD, dumbuf, min(len, DUMBUFLEN)); 312 if (strchr(dumbuf, '0') || 313 (strchr(dumbuf, 'O') && strchr(dumbuf, 'K'))) 314 return(1); 315 #ifdef DEBUG 316 dumbuf[len] = '\0'; 317 printf("hay_sync: (\"%s\") %d\n\r", dumbuf, retry); 318 #endif 319 } 320 ioctl(FD, TIOCCDTR, 0); 321 ioctl(FD, TIOCSDTR, 0); 322 } 323 printf("Cannot synchronize with hayes...\n\r"); 324 return(0); 325 } 326