1 /* $OpenBSD: t3000.c,v 1.14 2006/03/17 19:17:13 moritz Exp $ */ 2 /* $NetBSD: t3000.c,v 1.5 1997/02/11 09:24:18 mrg Exp $ */ 3 4 /*- 5 * SPDX-License-Identifier: BSD-3-Clause 6 * 7 * Copyright (c) 1992, 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 /* 36 * Routines for calling up on a Telebit T3000 modem. 37 * Derived from Courier driver. 38 */ 39 #include "tip.h" 40 41 #include <sys/ioctl.h> 42 #include <stdio.h> 43 44 #define MAXRETRY 5 45 46 static int dialtimeout = 0; 47 static int connected = 0; 48 static jmp_buf timeoutbuf; 49 50 static void sigALRM(int); 51 static int t3000_swallow(char *); 52 static int t3000_connect(void); 53 static int t3000_sync(void); 54 static void t3000_write(int, char *, int); 55 static void t3000_nap(void); 56 #ifdef DEBUG 57 static void t3000_verbose_read(void); 58 #endif 59 60 int 61 t3000_dialer(char *num, char *acu) 62 { 63 char *cp; 64 struct termios cntrl; 65 #ifdef ACULOG 66 char line[80]; 67 #endif 68 69 if (boolean(value(VERBOSE))) 70 printf("Using \"%s\"\n", acu); 71 72 tcgetattr(FD, &cntrl); 73 cntrl.c_cflag |= HUPCL; 74 tcsetattr(FD, TCSANOW, &cntrl); 75 /* 76 * Get in synch. 77 */ 78 if (!t3000_sync()) { 79 badsynch: 80 printf("can't synchronize with t3000\n"); 81 #ifdef ACULOG 82 logent(value(HOST), num, "t3000", "can't synch up"); 83 #endif 84 return (0); 85 } 86 t3000_write(FD, "AT E0\r", 6); /* turn off echoing */ 87 sleep(1); 88 #ifdef DEBUG 89 if (boolean(value(VERBOSE))) 90 t3000_verbose_read(); 91 #endif 92 tcflush(FD, TCIOFLUSH); 93 t3000_write(FD, "AT E0 H0 Q0 X4 V1\r", 18); 94 if (!t3000_swallow("\r\nOK\r\n")) 95 goto badsynch; 96 fflush(stdout); 97 t3000_write(FD, "AT D", 4); 98 for (cp = num; *cp; cp++) 99 if (*cp == '=') 100 *cp = ','; 101 t3000_write(FD, num, strlen(num)); 102 t3000_write(FD, "\r", 1); 103 connected = t3000_connect(); 104 #ifdef ACULOG 105 if (dialtimeout) { 106 (void)snprintf(line, sizeof line, "%ld second dial timeout", 107 number(value(DIALTIMEOUT))); 108 logent(value(HOST), num, "t3000", line); 109 } 110 #endif 111 if (dialtimeout) 112 t3000_disconnect(); 113 return (connected); 114 } 115 116 void 117 t3000_disconnect(void) 118 { 119 /* first hang up the modem*/ 120 ioctl(FD, TIOCCDTR, 0); 121 sleep(1); 122 ioctl(FD, TIOCSDTR, 0); 123 t3000_sync(); /* reset */ 124 close(FD); 125 } 126 127 void 128 t3000_abort(void) 129 { 130 t3000_write(FD, "\r", 1); /* send anything to abort the call */ 131 t3000_disconnect(); 132 } 133 134 /*ARGSUSED*/ 135 static void 136 sigALRM(int signo) 137 { 138 printf("\07timeout waiting for reply\n"); 139 dialtimeout = 1; 140 longjmp(timeoutbuf, 1); 141 } 142 143 static int 144 t3000_swallow(char *match) 145 { 146 sig_t f; 147 char c; 148 149 f = signal(SIGALRM, sigALRM); 150 dialtimeout = 0; 151 do { 152 if (*match =='\0') { 153 signal(SIGALRM, f); 154 return (1); 155 } 156 if (setjmp(timeoutbuf)) { 157 signal(SIGALRM, f); 158 return (0); 159 } 160 alarm(number(value(DIALTIMEOUT))); 161 read(FD, &c, 1); 162 alarm(0); 163 c &= 0177; 164 #ifdef DEBUG 165 if (boolean(value(VERBOSE))) 166 putchar(c); 167 #endif 168 } while (c == *match++); 169 #ifdef DEBUG 170 if (boolean(value(VERBOSE))) 171 fflush(stdout); 172 #endif 173 signal(SIGALRM, SIG_DFL); 174 return (0); 175 } 176 177 #ifndef B19200 /* XXX */ 178 #define B19200 EXTA 179 #define B38400 EXTB 180 #endif 181 182 struct tbaud_msg { 183 char *msg; 184 int baud; 185 int baud2; 186 } tbaud_msg[] = { 187 { "", B300, 0 }, 188 { " 1200", B1200, 0 }, 189 { " 2400", B2400, 0 }, 190 { " 4800", B4800, 0 }, 191 { " 9600", B9600, 0 }, 192 { " 14400", B19200, B9600 }, 193 { " 19200", B19200, B9600 }, 194 { " 38400", B38400, B9600 }, 195 { " 57600", B38400, B9600 }, 196 { " 7512", B9600, 0 }, 197 { " 1275", B2400, 0 }, 198 { " 7200", B9600, 0 }, 199 { " 12000", B19200, B9600 }, 200 { 0, 0, 0 }, 201 }; 202 203 static int 204 t3000_connect(void) 205 { 206 char c; 207 int nc, nl, n; 208 char dialer_buf[64]; 209 struct tbaud_msg *bm; 210 sig_t f; 211 212 if (t3000_swallow("\r\n") == 0) 213 return (0); 214 f = signal(SIGALRM, sigALRM); 215 again: 216 nc = 0; nl = sizeof(dialer_buf)-1; 217 bzero(dialer_buf, sizeof(dialer_buf)); 218 dialtimeout = 0; 219 for (nc = 0, nl = sizeof(dialer_buf)-1 ; nl > 0 ; nc++, nl--) { 220 if (setjmp(timeoutbuf)) 221 break; 222 alarm(number(value(DIALTIMEOUT))); 223 n = read(FD, &c, 1); 224 alarm(0); 225 if (n <= 0) 226 break; 227 c &= 0x7f; 228 if (c == '\r') { 229 if (t3000_swallow("\n") == 0) 230 break; 231 if (!dialer_buf[0]) 232 goto again; 233 if (strcmp(dialer_buf, "RINGING") == 0 && 234 boolean(value(VERBOSE))) { 235 #ifdef DEBUG 236 printf("%s\r\n", dialer_buf); 237 #endif 238 goto again; 239 } 240 if (strncmp(dialer_buf, "CONNECT", 241 sizeof("CONNECT")-1) != 0) 242 break; 243 for (bm = tbaud_msg ; bm->msg ; bm++) 244 if (strcmp(bm->msg, 245 dialer_buf+sizeof("CONNECT")-1) == 0) { 246 struct termios cntrl; 247 248 tcgetattr(FD, &cntrl); 249 cfsetospeed(&cntrl, bm->baud); 250 cfsetispeed(&cntrl, bm->baud); 251 tcsetattr(FD, TCSAFLUSH, &cntrl); 252 signal(SIGALRM, f); 253 #ifdef DEBUG 254 if (boolean(value(VERBOSE))) 255 printf("%s\r\n", dialer_buf); 256 #endif 257 return (1); 258 } 259 break; 260 } 261 dialer_buf[nc] = c; 262 #ifdef notdef 263 if (boolean(value(VERBOSE))) 264 putchar(c); 265 #endif 266 } 267 printf("%s\r\n", dialer_buf); 268 signal(SIGALRM, f); 269 return (0); 270 } 271 272 /* 273 * This convoluted piece of code attempts to get 274 * the t3000 in sync. 275 */ 276 static int 277 t3000_sync(void) 278 { 279 int already = 0; 280 int len; 281 char buf[40]; 282 283 while (already++ < MAXRETRY) { 284 tcflush(FD, TCIOFLUSH); 285 t3000_write(FD, "\rAT Z\r", 6); /* reset modem */ 286 bzero(buf, sizeof(buf)); 287 sleep(2); 288 ioctl(FD, FIONREAD, &len); 289 #if 1 290 if (len == 0) len = 1; 291 #endif 292 if (len) { 293 len = read(FD, buf, sizeof(buf)); 294 #ifdef DEBUG 295 buf[len] = '\0'; 296 printf("t3000_sync: (\"%s\")\n\r", buf); 297 #endif 298 if (strchr(buf, '0') || 299 (strchr(buf, 'O') && strchr(buf, 'K'))) 300 return(1); 301 } 302 /* 303 * If not strapped for DTR control, 304 * try to get command mode. 305 */ 306 sleep(1); 307 t3000_write(FD, "+++", 3); 308 sleep(1); 309 /* 310 * Toggle DTR to force anyone off that might have left 311 * the modem connected. 312 */ 313 ioctl(FD, TIOCCDTR, 0); 314 sleep(1); 315 ioctl(FD, TIOCSDTR, 0); 316 } 317 t3000_write(FD, "\rAT Z\r", 6); 318 return (0); 319 } 320 321 static void 322 t3000_write(int fd, char *cp, int n) 323 { 324 #ifdef notdef 325 if (boolean(value(VERBOSE))) 326 write(1, cp, n); 327 #endif 328 tcdrain(fd); 329 t3000_nap(); 330 for ( ; n-- ; cp++) { 331 write(fd, cp, 1); 332 tcdrain(fd); 333 t3000_nap(); 334 } 335 } 336 337 #ifdef DEBUG 338 static void 339 t3000_verbose_read(void) 340 { 341 int n = 0; 342 char buf[BUFSIZ]; 343 344 if (ioctl(FD, FIONREAD, &n) < 0) 345 return; 346 if (n <= 0) 347 return; 348 if (read(FD, buf, n) != n) 349 return; 350 write(1, buf, n); 351 } 352 #endif 353 354 /* Give the t3000 50 milliseconds between characters */ 355 static void 356 t3000_nap(void) 357 { 358 struct timespec ts; 359 360 ts.tv_sec = 0; 361 ts.tv_nsec = 50 * 1000000; 362 363 nanosleep(&ts, NULL); 364 } 365