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