interface.c revision 1219:f89f56c2d9ac
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22
23/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
24/*	  All Rights Reserved  	*/
25
26/*
27 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
28 * Use is subject to license terms.
29 */
30
31#pragma ident	"%Z%%M%	%I%	%E% SMI"
32
33/*
34 * interface( label )
35 *	provide alternate definitions for the I/O functions through global
36 *	interfaces.
37 */
38#include "mt.h"
39#include "uucp.h"
40#include <unistd.h>
41
42#ifdef TLI
43#include <tiuser.h>
44#endif /*  TLI  */
45
46static void	sethup(int);
47static int	restline(void);
48static int	usetup(int, int *, int *);
49static int	uteardown(int, int, int);
50
51static ssize_t	(*Read)() = read,
52	(*Write)() = write;
53static int	(*Ioctl)(int, int, ...) = ioctl,
54	(*Setup)() = usetup;
55
56#ifdef TLI
57static void tfaillog(int fd, const char *s);
58static void show_tlook(int);
59static ssize_t	tread(int, char *, unsigned);
60static ssize_t	twrite(int, char *, unsigned);
61static int tioctl(int, int, ...);
62static int tsetup(int, int *, int *); /* TLI setup without streams module */
63static int tssetup(int, int *, int *); /* TLI setup with streams module */
64static int tteardown(int, int, int); /* TLI teardown, works with either setup */
65#endif /*  TLI  */
66
67/*
68 *	The IN_label in Interface[] imply different caller routines:
69 *	e.g. tlicall().
70 *	If so, the names here and the names in callers.c must match.
71 */
72static struct Interface {
73	const	char	*IN_label;	/* interface name */
74	ssize_t	(*IN_read)();		/* read function */
75	ssize_t	(*IN_write)();		/* write function */
76	int	(*IN_ioctl)(int, int, ...);
77	int	(*IN_setup)();		/* setup function, called before */
78					/* first i/o operation */
79	int	(*IN_teardown)();	/* teardown function, called after */
80					/* last i/o operation */
81} Interface[] = {
82			/* vanilla UNIX */
83		{ "UNIX", read, write, ioctl, usetup, uteardown },
84#ifdef TLI
85			/* AT&T Transport Interface Library WITHOUT streams */
86		{ "TLI", tread, twrite, tioctl, tsetup, tteardown },
87#ifdef TLIS
88			/* AT&T Transport Interface Library WITH streams */
89		{ "TLIS", read, write, tioctl, tssetup, uteardown },
90#endif /*  TLIS  */
91#endif /*  TLI  */
92		{ 0, 0, 0, 0, 0, 0 }
93	};
94
95
96static int
97interface(const char *label)
98{
99	int	i;
100
101	for (i = 0;  Interface[i].IN_label;  ++i) {
102		if (strcmp(Interface[i].IN_label, label) == 0) {
103			Read = Interface[i].IN_read;
104			Write = Interface[i].IN_write;
105			Ioctl = Interface[i].IN_ioctl;
106			Setup = Interface[i].IN_setup;
107			DEBUG(5, "set interface %s\n", label);
108			return (0);
109		}
110	}
111	return (FAIL);
112}
113
114/*
115 *	usetup - vanilla unix setup routine
116 */
117static int
118usetup(int role, int *fdreadp, int *fdwritep)
119{
120	if (role == SLAVE) {
121		*fdreadp = 0;
122		*fdwritep = 1;
123		/* 2 has been re-opened to RMTDEBUG in main() */
124	}
125	return (SUCCESS);
126}
127
128/*
129 *	uteardown - vanilla unix teardown routine
130 */
131static int
132uteardown(int role, int fdread, int fdwrite)
133{
134	char *ttyn;
135
136	if (role == SLAVE) {
137		(void) restline();
138		sethup(0);
139	}
140	if (fdread != -1) {
141		ttyn = ttyname(fdread);
142		if (ttyn != NULL)
143			/* can fail, but who cares? */
144			(void) chmod(ttyn, Dev_mode);
145		(void) close(fdread);
146		(void) close(fdwrite);
147	}
148	return (SUCCESS);
149}
150
151#ifdef TLI
152/*
153 *	tread - tli read routine
154 */
155static ssize_t
156tread(int fd, char *buf, unsigned nbytes)
157{
158	int		rcvflags;
159
160	return ((ssize_t)t_rcv(fd, buf, nbytes, &rcvflags));
161}
162
163/*
164 *	twrite - tli write routine
165 */
166#define	N_CHECK	100
167static ssize_t
168twrite(int fd, char *buf, unsigned nbytes)
169{
170	int			i, ret;
171	static int		n_writ, got_info;
172	static struct t_info	info;
173
174	if (got_info == 0) {
175		if (t_getinfo(fd, &info) != 0) {
176			tfaillog(fd, "twrite: t_getinfo\n");
177			return (FAIL);
178		}
179		got_info = 1;
180	}
181
182	/* on every N_CHECKth call, check that are still in DATAXFER state */
183	if (++n_writ == N_CHECK) {
184		n_writ = 0;
185		if (t_getstate(fd) != T_DATAXFER)
186			return (FAIL);
187	}
188
189	if (info.tsdu <= 0 || nbytes <= info.tsdu)
190		return ((ssize_t)t_snd(fd, buf, nbytes, NULL));
191	/* if get here, then there is a limit on transmit size	*/
192	/* (info.tsdu > 0) and buf exceeds it			*/
193	i = ret = 0;
194	while (nbytes >= info.tsdu) {
195		if ((ret = t_snd(fd,  &buf[i], info.tsdu, NULL)) != info.tsdu)
196			return ((ssize_t)(ret >= 0 ? (i + ret) : ret));
197		i += info.tsdu;
198		nbytes -= info.tsdu;
199	}
200	if (nbytes != 0) {
201		if ((ret = t_snd(fd,  &buf[i], nbytes, NULL)) != nbytes)
202			return ((ssize_t)(ret >= 0 ? (i + ret) : ret));
203		i += nbytes;
204	}
205	return ((ssize_t)i);
206}
207
208/*
209 *	tioctl - stub for tli ioctl routine
210 */
211/* ARGSUSED */
212static int
213tioctl(int fd, int request, ...)
214{
215	return (SUCCESS);
216}
217
218/*
219 *	tsetup - tli setup routine
220 *	note blatant assumption that *fdreadp == *fdwritep == 0
221 */
222static int
223tsetup(int role, int *fdreadp, int *fdwritep)
224{
225	if (role == SLAVE) {
226		*fdreadp = 0;
227		*fdwritep = 1;
228		/* 2 has been re-opened to RMTDEBUG in main() */
229		errno = t_errno = 0;
230		if (t_sync(*fdreadp) == -1 || t_sync(*fdwritep) == -1) {
231			tfaillog(*fdreadp, "tsetup: t_sync\n");
232			return (FAIL);
233		}
234	}
235	return (SUCCESS);
236}
237
238/*
239 *	tteardown - tli shutdown routine
240 */
241/* ARGSUSED */
242static int
243tteardown(int role, int fdread, int fdwrite)
244{
245	(void) t_unbind(fdread);
246	(void) t_close(fdread);
247	return (SUCCESS);
248}
249
250#ifdef TLIS
251/*
252 *	tssetup - tli, with streams module, setup routine
253 *	note blatant assumption that *fdreadp == *fdwritep
254 */
255static int
256tssetup(int role, int *fdreadp, int *fdwritep)
257{
258	if (role == SLAVE) {
259		*fdreadp = 0;
260		*fdwritep = 1;
261		/* 2 has been re-opened to RMTDEBUG in main() */
262		DEBUG(5, "tssetup: SLAVE mode: leaving ok\n%s", "");
263		return (SUCCESS);
264	}
265
266	DEBUG(4, "tssetup: MASTER mode: leaving ok\n%s", "");
267	return (SUCCESS);
268}
269
270/*
271 *	Report why a TLI call failed.
272 */
273static void
274tfaillog(int fd, const char *s)
275{
276	char	fmt[ BUFSIZ ];
277
278	if (0 < t_errno && t_errno < t_nerr) {
279		(void) snprintf(fmt, sizeof (fmt), "%s: %%s\n", s);
280		DEBUG(5, fmt, t_errlist[t_errno]);
281		logent(s, t_errlist[t_errno]);
282		if (t_errno == TSYSERR) {
283			(void) strcpy(fmt, "tlicall: system error: %s\n");
284			DEBUG(5, fmt, strerror(errno));
285		} else if (t_errno == TLOOK) {
286			show_tlook(fd);
287		}
288	} else {
289		(void) snprintf(fmt, sizeof (fmt),
290					"unknown tli error %d", t_errno);
291		logent(s, fmt);
292		(void) snprintf(fmt, sizeof (fmt),
293					"%s: unknown tli error %d", s, t_errno);
294		DEBUG(5, fmt, 0);
295		(void) snprintf(fmt, sizeof (fmt), "%s: %%s\n", s);
296		DEBUG(5, fmt, strerror(errno));
297	}
298}
299
300static void
301show_tlook(int fd)
302{
303	int reason;
304	const char *msg;
305
306/*
307 * Find out the current state of the interface.
308 */
309	errno = t_errno = 0;
310	switch (reason = t_getstate(fd)) {
311	case T_UNBND:		msg = (const char *)"T_UNBIND";	break;
312	case T_IDLE:		msg = (const char *)"T_IDLE";	break;
313	case T_OUTCON:		msg = (const char *)"T_OUTCON";	break;
314	case T_INCON:		msg = (const char *)"T_INCON";	break;
315	case T_DATAXFER:	msg = (const char *)"T_DATAXFER"; break;
316	case T_OUTREL:		msg = (const char *)"T_OUTREL";	break;
317	case T_INREL:		msg = (const char *)"T_INREL";	break;
318	default:		msg = NULL;		break;
319	}
320	if (msg == NULL)
321		return;
322	DEBUG(5, "state is %s", msg);
323	switch (reason = t_look(fd)) {
324	case -1:		msg = (const char *)""; break;
325	case 0:			msg = (const char *)"NO ERROR"; break;
326	case T_LISTEN:		msg = (const char *)"T_LISTEN"; break;
327	case T_CONNECT:		msg = (const char *)"T_CONNECT"; break;
328	case T_DATA:		msg = (const char *)"T_DATA";	 break;
329	case T_EXDATA:		msg = (const char *)"T_EXDATA"; break;
330	case T_DISCONNECT:	msg = (const char *)"T_DISCONNECT"; break;
331	case T_ORDREL:		msg = (const char *)"T_ORDREL"; break;
332	case T_ERROR:		msg = (const char *)"T_ERROR"; break;
333	case T_UDERR:		msg = (const char *)"T_UDERR"; break;
334	default:		msg = (const char *)"UNKNOWN ERROR"; break;
335	}
336	DEBUG(4, " reason is %s\n", msg);
337
338	if (reason == T_DISCONNECT) {
339		struct t_discon	*dropped;
340		if (((dropped =
341			/* LINTED pointer cast */
342			(struct t_discon *)t_alloc(fd, T_DIS, T_ALL)) == 0) ||
343			(t_rcvdis(fd, dropped) == -1)) {
344			if (dropped)
345				(void) t_free((char *)dropped, T_DIS);
346			return;
347		}
348		DEBUG(5, "disconnect reason #%d\n", dropped->reason);
349		(void) t_free((char *)dropped, T_DIS);
350	}
351}
352#endif /*  TLIS  */
353#endif /*  TLI  */
354