xref: /illumos-gate/usr/src/cmd/bnu/interface.c (revision 3b296559)
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 2014 Gary Mills
24  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
25  * Use is subject to license terms.
26  */
27 
28 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
29 /*	  All Rights Reserved  	*/
30 
31 /*
32  *	interface(label)
33  *	provide alternate definitions for the I/O functions through global
34  *	interfaces.
35  */
36 #include	"uucp.h"
37 
38 #ifdef TLI
39 #include	<tiuser.h>
40 char *t_alloc();
41 int t_bind(), t_close(), t_connect(), t_free(), t_look(), t_open(), t_rcvdis();
42 int t_getinfo(), t_getstate(), t_look(), t_rcv(), t_snd(), t_sync(), t_unbind();
43 #endif /*  TLI  */
44 
45 #ifdef DATAKIT
46 #include	"dk.h"
47 
48 static int	dksetup();
49 static int	dkteardown();
50 #endif	/* DATAKIT */
51 
52 EXTERN void	sethup();
53 EXTERN int	restline();
54 #if defined(__STDC__)
55 extern int	ioctl(int, int, ...);
56 #else
57 extern int	ioctl();
58 #endif
59 static int	usetup(), uteardown();
60 
61 GLOBAL ssize_t	(*Read)() = read,
62 	(*Write)() = write;
63 #if defined(__STDC__)
64 GLOBAL int	(*Ioctl)(int, int, ...) = ioctl,
65 #else
66 GLOBAL int	(*Ioctl)() = ioctl,
67 #endif
68 	(*Setup)() = usetup,
69 	(*Teardown)() = uteardown;
70 
71 #ifdef TLI
72 EXTERN void tfaillog(), show_tlook();
73 static ssize_t	tread(), twrite();	/* TLI i/o */
74 #ifdef __STDC__
75 static int	tioctl(int, int, ...),
76 #else
77 static int	tioctl(),		/* TLI i/o control */
78 #endif
79 		tsetup(),	/* TLI setup without streams module */
80 		tssetup(),	/* TLI setup with streams module */
81 		tteardown();	/* TLI teardown, works with either setup */
82 #endif /*  TLI  */
83 /*
84  *	The IN_label in Interface[] imply different caller routines:
85  *	e.g. tlicall().
86  *	If so, the names here and the names in callers.c must match.
87  */
88 
89 static
90 struct Interface {
91 	char	*IN_label;		/* interface name */
92 	ssize_t	(*IN_read)();		/* read function */
93 	ssize_t	(*IN_write)();		/* write function */
94 #ifdef __STDC__
95 	int	(*IN_ioctl)(int, int, ...);
96 #else
97 	int	(*IN_ioctl)();		/* ioctl function */
98 #endif
99 	int	(*IN_setup)();		/* setup function, called before */
100 					/* first i/o operation */
101 	int	(*IN_teardown)();	/* teardown function, called after */
102 					/* last i/o operation */
103 } Interface[] = {
104 			/* vanilla UNIX */
105 		{ "UNIX", read, write, ioctl, usetup, uteardown },
106 #ifdef TCP
107 			/* TCP over sockets or UNET */
108 		{ "TCP", read, write, ioctl, usetup, uteardown },
109 #endif /* TCP */
110 #ifdef SYTEK
111 			/* Sytek network */
112 		{ "Sytek", read, write, ioctl, usetup, uteardown },
113 #endif /* Sytek network */
114 #ifdef DIAL801
115 			/* 801 auto dialers */
116 		{ "801", read, write, ioctl, usetup, uteardown },
117 #endif /* DIAL801 */
118 #ifdef DIAL801
119 			/* 212 auto dialers */
120 		{ "212", read, write, ioctl, usetup, uteardown },
121 #endif /* DIAL801 */
122 #ifdef TLI
123 			/* AT&T Transport Interface Library WITHOUT streams */
124 		{ "TLI", tread, twrite, tioctl, tsetup, tteardown },
125 #ifdef TLIS
126 			/* AT&T Transport Interface Library WITH streams */
127 		{ "TLIS", read, write, tioctl, tssetup, uteardown },
128 #endif /*  TLIS  */
129 #endif /*  TLI  */
130 #ifdef DATAKIT
131 		{ "DK", read, write, ioctl, dksetup, dkteardown },
132 #endif /* DATAKIT */
133 #ifdef UNET
134 		{ "Unetserver", read, write, ioctl, usetup, uteardown },
135 #endif
136 		{ 0, 0, 0, 0, 0, 0 }
137 	};
138 
139 
140 GLOBAL int
interface(label)141 interface(label)
142 char	*label;
143 {
144 	register int	i;
145 
146 	for (i = 0;  Interface[i].IN_label;  ++i) {
147 		if (0 == strcmp(Interface[i].IN_label, label)) {
148 			Read = Interface[i].IN_read;
149 			Write = Interface[i].IN_write;
150 			Ioctl = Interface[i].IN_ioctl;
151 			Setup = Interface[i].IN_setup;
152 			Teardown = Interface[i].IN_teardown;
153 			DEBUG(5, "set interface %s\n", label);
154 			return (0);
155 		}
156 	}
157 	return (FAIL);
158 }
159 
160 /*
161  *	usetup - vanilla unix setup routine
162  */
163 static int
usetup(int role,int * fdreadp,int * fdwritep)164 usetup(int role, int *fdreadp, int *fdwritep)
165 {
166 	if (role == SLAVE)
167 	{
168 		*fdreadp = 0;
169 		*fdwritep = 1;
170 		/* 2 has been re-opened to RMTDEBUG in main() */
171 	}
172 	return (SUCCESS);
173 }
174 
175 /*
176  *	uteardown - vanilla unix teardown routine
177  */
178 static int
uteardown(int role,int fdread,int fdwrite)179 uteardown(int role, int fdread, int fdwrite)
180 {
181 	int ret;
182 	char *ttyn;
183 
184 	if (role == SLAVE) {
185 		ret = restline();
186 		DEBUG(4, "ret restline - %d\n", ret);
187 		if (fdread != -1)
188 			sethup(fdread);
189 	}
190 	if (fdread != -1) {
191 		ttyn = ttyname(fdread);
192 		if (ttyn != NULL && Dev_mode != 0)
193 			chmod(ttyn, Dev_mode);	/* can fail, but who cares? */
194 		(void) close(fdread);
195 		(void) close(fdwrite);
196 	}
197 	return (SUCCESS);
198 }
199 
200 #ifdef DATAKIT
201 /*
202  *	dksetup - DATAKIT setup routine
203  *
204  * Put line in block mode.
205  */
206 
207 static int
dksetup(role,fdreadp,fdwritep)208 dksetup(role, fdreadp, fdwritep)
209 
210 int	role;
211 int 	*fdreadp;
212 int 	*fdwritep;
213 
214 {
215 	static short dkrmode[3] = { DKR_BLOCK | DKR_TIME, 0, 0 };
216 	int	ret;
217 
218 	(void) usetup(role, fdreadp, fdwritep);
219 	if ((ret = (*Ioctl)(*fdreadp, DIOCRMODE, dkrmode)) < 0) {
220 		DEBUG(4, "dksetup: failed to set block mode. ret=%d,\n", ret);
221 		DEBUG(4, "read fd=%d, ", *fdreadp);
222 		DEBUG(4, "errno=%d\n", errno);
223 		return (FAIL);
224 	}
225 	return (SUCCESS);
226 }
227 
228 /*
229  *	dkteardown  -  DATAKIT teardown routine
230  */
231 static int
dkteardown(role,fdread,fdwrite)232 dkteardown(role, fdread, fdwrite)
233 int	role, fdread, fdwrite;
234 {
235 	char	*ttyn;
236 
237 	if (role == MASTER) {
238 		ttyn = ttyname(fdread);
239 		if (ttyn != NULL && Dev_mode != 0)
240 			chmod(ttyn, Dev_mode);	/* can fail, but who cares? */
241 	}
242 
243 	/*	must flush fd's for datakit	*/
244 	/*	else close can hang		*/
245 	if (ioctl(fdread, DIOCFLUSH, NULL) != 0)
246 		DEBUG(4, "dkteardown: DIOCFLUSH of input fd %d failed",
247 		    fdread);
248 	if (ioctl(fdwrite, DIOCFLUSH, NULL) != 0)
249 		DEBUG(4, "dkteardown: DIOCFLUSH of output fd %d failed",
250 		    fdwrite);
251 
252 	(void) close(fdread);
253 	(void) close(fdwrite);
254 	return (SUCCESS);
255 }
256 #endif /* DATAKIT */
257 
258 
259 #ifdef TLI
260 /*
261  *	tread - tli read routine
262  */
263 static ssize_t
tread(fd,buf,nbytes)264 tread(fd, buf, nbytes)
265 int		fd;
266 char		*buf;
267 unsigned	nbytes;
268 {
269 	int		rcvflags;
270 
271 	return ((ssize_t)t_rcv(fd, buf, nbytes, &rcvflags));
272 }
273 
274 /*
275  *	twrite - tli write routine
276  */
277 #define	N_CHECK	100
278 static ssize_t
twrite(fd,buf,nbytes)279 twrite(fd, buf, nbytes)
280 int		fd;
281 char		*buf;
282 unsigned	nbytes;
283 {
284 	register int		i, ret;
285 	static int		n_writ, got_info;
286 	static struct t_info	info;
287 
288 	if (got_info == 0) {
289 		if (t_getinfo(fd, &info) != 0) {
290 			tfaillog(fd, "twrite: t_getinfo\n");
291 			return (FAIL);
292 		}
293 		got_info = 1;
294 	}
295 
296 	/* on every N_CHECKth call, check that are still in DATAXFER state */
297 	if (++n_writ == N_CHECK) {
298 		n_writ = 0;
299 		if (t_getstate(fd) != T_DATAXFER)
300 			return (FAIL);
301 	}
302 
303 	if (info.tsdu <= 0 || nbytes <= info.tsdu)
304 		return (t_snd(fd, buf, nbytes, 0));
305 
306 	/* if get here, then there is a limit on transmit size	*/
307 	/* (info.tsdu > 0) and buf exceeds it			*/
308 	i = ret = 0;
309 	while (nbytes >= info.tsdu) {
310 		if ((ret = t_snd(fd,  &buf[i], info.tsdu, 0)) != info.tsdu)
311 			return ((ret >= 0 ? (i + ret) : ret));
312 		i += info.tsdu;
313 		nbytes -= info.tsdu;
314 	}
315 	if (nbytes != 0) {
316 		if ((ret = t_snd(fd,  &buf[i], nbytes, 0)) != nbytes)
317 			return ((ssize_t)(ret >= 0 ? (i + ret) : ret));
318 		i += nbytes;
319 	}
320 	return ((ssize_t)i);
321 }
322 
323 
324 /*
325  *	tioctl - stub for tli ioctl routine
326  */
327 static int
tioctl(int fd __unused,int request __unused,...)328 tioctl(int fd __unused, int request __unused, ...)
329 {
330 	return (SUCCESS);
331 }
332 
333 /*
334  *	tsetup - tli setup routine
335  *	note blatant assumption that *fdreadp == *fdwritep == 0
336  */
337 static int
tsetup(int role,int * fdreadp,int * fdwritep)338 tsetup(int role, int *fdreadp, int *fdwritep)
339 {
340 
341 	if (role == SLAVE) {
342 		*fdreadp = 0;
343 		*fdwritep = 1;
344 		/* 2 has been re-opened to RMTDEBUG in main() */
345 		errno = t_errno = 0;
346 		if (t_sync(*fdreadp) == -1 || t_sync(*fdwritep) == -1) {
347 			tfaillog(*fdreadp, "tsetup: t_sync\n");
348 			return (FAIL);
349 		}
350 	}
351 	return (SUCCESS);
352 }
353 
354 /*
355  *	tteardown - tli shutdown routine
356  */
357 static int
tteardown(int role __unused,int fdread,int fdwrite __unused)358 tteardown(int role __unused, int fdread, int fdwrite __unused)
359 {
360 	(void) t_unbind(fdread);
361 	(void) t_close(fdread);
362 	return (SUCCESS);
363 }
364 
365 #ifdef TLIS
366 /*
367  *	tssetup - tli, with streams module, setup routine
368  *	note blatant assumption that *fdreadp == *fdwritep
369  */
370 static int
tssetup(role,fdreadp,fdwritep)371 tssetup(role, fdreadp, fdwritep)
372 int	role;
373 int	*fdreadp;
374 int	*fdwritep;
375 {
376 	if (role == SLAVE) {
377 		*fdreadp = 0;
378 		*fdwritep = 1;
379 		/* 2 has been re-opened to RMTDEBUG in main() */
380 		DEBUG(5, "tssetup: SLAVE mode: leaving ok\n%s", "");
381 		return (SUCCESS);
382 	}
383 
384 	DEBUG(4, "tssetup: MASTER mode: leaving ok\n%s", "");
385 	return (SUCCESS);
386 }
387 
388 /*
389  *	Report why a TLI call failed.
390  */
391 GLOBAL void
tfaillog(fd,s)392 tfaillog(fd, s)
393 int	fd;
394 char	*s;
395 {
396 	char	fmt[ BUFSIZ ];
397 
398 	if (0 < t_errno && t_errno < t_nerr) {
399 		sprintf(fmt, "%s: %%s\n", s);
400 		DEBUG(5, fmt, t_errlist[t_errno]);
401 		logent(s, t_errlist[t_errno]);
402 		if (t_errno == TSYSERR) {
403 			strcpy(fmt, "tlicall: system error: %s\n");
404 			DEBUG(5, fmt, strerror(errno));
405 		} else if (t_errno == TLOOK) {
406 			show_tlook(fd);
407 		}
408 	} else {
409 		sprintf(fmt, "unknown tli error %d", t_errno);
410 		logent(s, fmt);
411 		sprintf(fmt, "%s: unknown tli error %d", s, t_errno);
412 		DEBUG(5, fmt, 0);
413 		sprintf(fmt, "%s: %%s\n", s);
414 		DEBUG(5, fmt, strerror(errno));
415 	}
416 }
417 
418 GLOBAL void
show_tlook(fd)419 show_tlook(fd)
420 int fd;
421 {
422 	register int reason;
423 	register char *msg;
424 	extern int	t_errno;
425 /*
426  * Find out the current state of the interface.
427  */
428 	errno = t_errno = 0;
429 	switch (reason = t_getstate(fd)) {
430 	case T_UNBND:		msg = "T_UNBIND";	break;
431 	case T_IDLE:		msg = "T_IDLE";		break;
432 	case T_OUTCON:		msg = "T_OUTCON";	break;
433 	case T_INCON:		msg = "T_INCON";	break;
434 	case T_DATAXFER:	msg = "T_DATAXFER";	break;
435 	case T_OUTREL:		msg = "T_OUTREL";	break;
436 	case T_INREL:		msg = "T_INREL";	break;
437 	default:		msg = NULL;		break;
438 	}
439 	if (msg == NULL)
440 		return;
441 
442 	DEBUG(5, "state is %s", msg);
443 	switch (reason = t_look(fd)) {
444 	case -1:		msg = ""; break;
445 	case 0:			msg = "NO ERROR"; break;
446 	case T_LISTEN:		msg = "T_LISTEN"; break;
447 	case T_CONNECT:		msg = "T_CONNECT"; break;
448 	case T_DATA:		msg = "T_DATA";	 break;
449 	case T_EXDATA:		msg = "T_EXDATA"; break;
450 	case T_DISCONNECT:	msg = "T_DISCONNECT"; break;
451 	case T_ORDREL:		msg = "T_ORDREL"; break;
452 	case T_UDERR:		msg = "T_UDERR"; break;
453 	default:		msg = "UNKNOWN ERROR"; break;
454 	}
455 	DEBUG(4, " reason is %s\n", msg);
456 
457 	if (reason == T_DISCONNECT)
458 	{
459 		struct t_discon	*dropped;
460 		if (((dropped =
461 		    (struct t_discon *)t_alloc(fd, T_DIS, T_ALL)) == 0) ||
462 		    (t_rcvdis(fd, dropped) == -1)) {
463 			if (dropped)
464 				t_free((char *)dropped, T_DIS);
465 			return;
466 		}
467 		DEBUG(5, "disconnect reason #%d\n", dropped->reason);
468 		t_free((char *)dropped, T_DIS);
469 	}
470 }
471 
472 #endif /*  TLIS  */
473 
474 #endif /*  TLI  */
475