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