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