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