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 __FBSDID("$FreeBSD$"); 37 38 #ifndef lint 39 #if 0 40 static char sccsid[] = "@(#)hayes.c 8.1 (Berkeley) 6/6/93"; 41 static const char rcsid[] = "$OpenBSD: hayes.c,v 1.13 2006/03/17 19:17:13 moritz Exp $"; 42 #endif 43 #endif /* not lint */ 44 45 /* 46 * Routines for calling up on a Hayes Modem 47 * (based on the old VenTel driver). 48 * The modem is expected to be strapped for "echo". 49 * Also, the switches enabling the DTR and CD lines 50 * must be set correctly. 51 * NOTICE: 52 * The easy way to hang up a modem is always simply to 53 * clear the DTR signal. However, if the +++ sequence 54 * (which switches the modem back to local mode) is sent 55 * before modem is hung up, removal of the DTR signal 56 * has no effect (except that it prevents the modem from 57 * recognizing commands). 58 * (by Helge Skrivervik, Calma Company, Sunnyvale, CA. 1984) 59 */ 60 /* 61 * TODO: 62 * It is probably not a good idea to switch the modem 63 * state between 'verbose' and terse (status messages). 64 * This should be kicked out and we should use verbose 65 * mode only. This would make it consistent with normal 66 * interactive use thru the command 'tip dialer'. 67 */ 68 #include "tip.h" 69 70 #include <termios.h> 71 #include <sys/ioctl.h> 72 73 #define min(a,b) ((a < b) ? a : b) 74 75 static int dialtimeout = 0; 76 static jmp_buf timeoutbuf; 77 78 #define DUMBUFLEN 40 79 static char dumbuf[DUMBUFLEN]; 80 81 #define DIALING 1 82 #define IDLE 2 83 #define CONNECTED 3 84 #define FAILED 4 85 static int state = IDLE; 86 87 static void sigALRM(int); 88 static char gobble(char *); 89 static void error_rep(char); 90 static void goodbye(void); 91 static int hay_sync(void); 92 93 int 94 hay_dialer(char *num, char *acu) 95 { 96 char *cp; 97 int connected = 0; 98 char dummy; 99 struct termios cntrl; 100 #ifdef ACULOG 101 char line[80]; 102 #endif 103 if (hay_sync() == 0) /* make sure we can talk to the modem */ 104 return(0); 105 if (boolean(value(VERBOSE))) 106 printf("\ndialing..."); 107 fflush(stdout); 108 tcgetattr(FD, &cntrl); 109 cntrl.c_cflag |= HUPCL; 110 tcsetattr(FD, TCSANOW, &cntrl); 111 tcflush(FD, TCIOFLUSH); 112 write(FD, "ATv0\r", 5); /* tell modem to use short status codes */ 113 gobble("\r"); 114 gobble("\r"); 115 write(FD, "ATTD", 4); /* send dial command */ 116 for (cp = num; *cp; cp++) 117 if (*cp == '=') 118 *cp = ','; 119 write(FD, num, strlen(num)); 120 state = DIALING; 121 write(FD, "\r", 1); 122 connected = 0; 123 if (gobble("\r")) { 124 if ((dummy = gobble("01234")) != '1') 125 error_rep(dummy); 126 else 127 connected = 1; 128 } 129 if (connected) 130 state = CONNECTED; 131 else { 132 state = FAILED; 133 return (connected); /* lets get out of here.. */ 134 } 135 tcflush(FD, TCIOFLUSH); 136 #ifdef ACULOG 137 if (dialtimeout) { 138 (void)snprintf(line, sizeof line, "%ld second dial timeout", 139 number(value(DIALTIMEOUT))); 140 logent(value(HOST), num, "hayes", line); 141 } 142 #endif 143 if (dialtimeout) 144 hay_disconnect(); /* insurance */ 145 return (connected); 146 } 147 148 void 149 hay_disconnect(void) 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(void) 163 { 164 write(FD, "\r", 1); /* send anything to abort the call */ 165 hay_disconnect(); 166 } 167 168 /*ARGSUSED*/ 169 static void 170 sigALRM(int signo) 171 { 172 printf("\07timeout waiting for reply\n\r"); 173 dialtimeout = 1; 174 longjmp(timeoutbuf, 1); 175 } 176 177 static char 178 gobble(char *match) 179 { 180 char c; 181 sig_t f; 182 size_t i; 183 int status = 0; 184 185 f = signal(SIGALRM, sigALRM); 186 dialtimeout = 0; 187 #ifdef DEBUG 188 printf("\ngobble: waiting for %s\n", match); 189 #endif 190 do { 191 if (setjmp(timeoutbuf)) { 192 signal(SIGALRM, f); 193 return (0); 194 } 195 alarm(number(value(DIALTIMEOUT))); 196 read(FD, &c, 1); 197 alarm(0); 198 c &= 0177; 199 #ifdef DEBUG 200 printf("%c 0x%x ", c, c); 201 #endif 202 for (i = 0; i < strlen(match); i++) 203 if (c == match[i]) 204 status = c; 205 } while (status == 0); 206 signal(SIGALRM, SIG_DFL); 207 #ifdef DEBUG 208 printf("\n"); 209 #endif 210 return (status); 211 } 212 213 static void 214 error_rep(char c) 215 { 216 printf("\n\r"); 217 switch (c) { 218 219 case '0': 220 printf("OK"); 221 break; 222 223 case '1': 224 printf("CONNECT"); 225 break; 226 227 case '2': 228 printf("RING"); 229 break; 230 231 case '3': 232 printf("NO CARRIER"); 233 break; 234 235 case '4': 236 printf("ERROR in input"); 237 break; 238 239 case '5': 240 printf("CONNECT 1200"); 241 break; 242 243 default: 244 printf("Unknown Modem error: %c (0x%x)", c, c); 245 } 246 printf("\n\r"); 247 return; 248 } 249 250 /* 251 * set modem back to normal verbose status codes. 252 */ 253 static void 254 goodbye(void) 255 { 256 int len; 257 char c; 258 259 tcflush(FD, TCIOFLUSH); 260 if (hay_sync()) { 261 sleep(1); 262 #ifndef DEBUG 263 tcflush(FD, TCIOFLUSH); 264 #endif 265 write(FD, "ATH0\r", 5); /* insurance */ 266 #ifndef DEBUG 267 c = gobble("03"); 268 if (c != '0' && c != '3') { 269 printf("cannot hang up modem\n\r"); 270 printf("please use 'tip dialer' to make sure the line is hung up\n\r"); 271 } 272 #endif 273 sleep(1); 274 ioctl(FD, FIONREAD, &len); 275 #ifdef DEBUG 276 printf("goodbye1: len=%d -- ", len); 277 rlen = read(FD, dumbuf, min(len, DUMBUFLEN)); 278 dumbuf[rlen] = '\0'; 279 printf("read (%d): %s\r\n", rlen, dumbuf); 280 #endif 281 write(FD, "ATv1\r", 5); 282 sleep(1); 283 #ifdef DEBUG 284 ioctl(FD, FIONREAD, &len); 285 printf("goodbye2: len=%d -- ", len); 286 rlen = read(FD, dumbuf, min(len, DUMBUFLEN)); 287 dumbuf[rlen] = '\0'; 288 printf("read (%d): %s\r\n", rlen, dumbuf); 289 #endif 290 } 291 tcflush(FD, TCIOFLUSH); 292 ioctl(FD, TIOCCDTR, 0); /* clear DTR (insurance) */ 293 close(FD); 294 } 295 296 #define MAXRETRY 5 297 298 static int 299 hay_sync(void) 300 { 301 int len, retry = 0; 302 303 while (retry++ <= MAXRETRY) { 304 write(FD, "AT\r", 3); 305 sleep(1); 306 ioctl(FD, FIONREAD, &len); 307 if (len) { 308 len = read(FD, dumbuf, min(len, DUMBUFLEN)); 309 if (strchr(dumbuf, '0') || 310 (strchr(dumbuf, 'O') && strchr(dumbuf, 'K'))) 311 return(1); 312 #ifdef DEBUG 313 dumbuf[len] = '\0'; 314 printf("hay_sync: (\"%s\") %d\n\r", dumbuf, retry); 315 #endif 316 } 317 ioctl(FD, TIOCCDTR, 0); 318 ioctl(FD, TIOCSDTR, 0); 319 } 320 printf("Cannot synchronize with hayes...\n\r"); 321 return(0); 322 } 323