xref: /csrg-svn/contrib/usr.x25/x29d/x29d.c (revision 45293)
145223Ssklower /*
245223Ssklower  * X.29 server
345223Ssklower  *
445223Ssklower  * Frank Pronk (...!ubc-vision!pronk)
545223Ssklower  * April, September 1984
645223Ssklower  *
745223Ssklower  * Laboratory for Computational Vision
845223Ssklower  * University of British Columbia
945223Ssklower  * Copyright (c)
1045223Ssklower  */
1145223Ssklower 
1245223Ssklower #include <sys/param.h>
1345223Ssklower #include <sys/socket.h>
1445223Ssklower #include <sys/stat.h>
1545223Ssklower #include <sys/wait.h>
1645223Ssklower 
1745223Ssklower #include <netccitt/x25.h>
1845223Ssklower 
1945223Ssklower #include <errno.h>
2045223Ssklower #include <netdb.h>
2145223Ssklower #include <signal.h>
22*45293Ssklower #include <sys/ioctl.h>
23*45293Ssklower #include <sys/termios.h>
24*45293Ssklower #include <paths.h>
2545223Ssklower 
2645223Ssklower #include "../h/x29.h"
2745223Ssklower 
2845223Ssklower #define BUFSIZ		1024
2945223Ssklower #define MAXARGS		10	/* maximum size of server argument list */
3045223Ssklower 
3145223Ssklower #define X25NET		0	/* no ITI parameters */
3245223Ssklower #define CCITT1978	1	/* 1978 CCITT standard parameter set */
3345223Ssklower #define CCITT1980	2	/* 1980 CCITT standard parameter set */
3445223Ssklower 
3545223Ssklower 
3645223Ssklower char	pibuf[BUFSIZ], fibuf[BUFSIZ];
3745223Ssklower int	pty, net;
3845223Ssklower extern	char **environ;
3945223Ssklower extern	int errno;
40*45293Ssklower char	line[MAXPATHLEN];
4145223Ssklower char	console[] = "/dev/console";
4245223Ssklower short	packet_size;
43*45293Ssklower short	debug;
4445223Ssklower char	*tracefn;		/* trace file name */
4545223Ssklower char	*server;
4645223Ssklower short	send_banner;
4745223Ssklower struct	sockaddr_x25 sock;
4845223Ssklower 
4945223Ssklower int	reapchild();
5045223Ssklower struct	net *lookup ();
5145223Ssklower 
5245223Ssklower char	ccitt1978_prof[] = {		/* initial profile */
5345223Ssklower 	Q_BIT,	X29_SET_AND_READ_PARMS,
5445223Ssklower 	X29_ECHO_CODE,			1,	/* echo on */
5545223Ssklower 	X29_FORWARDING_SIGNAL_CODE,	126,	/* forward on all cntl */
5645223Ssklower 	X29_IDLE_TIMER_CODE,		0,	/* off */
5745223Ssklower 	X29_AUX_DEV_CONTROL_CODE,	0,	/* off */
5845223Ssklower 	X29_RECEIVE_NET_MSGS_CODE,	1,	/* xmit network msgs */
5945223Ssklower 	X29_BREAK_PROCEDURE_CODE,	21,
6045223Ssklower 	X29_PADDING_CODE,		0,	/* off */
6145223Ssklower 	X29_LINE_FOLDING_CODE,		0,	/* off */
6245223Ssklower 	X29_TRANSMISSION_SPEED_CODE,	0,
6345223Ssklower 	X29_XON_XOFF_CODE,		1,	/* enable XON/XOFF */
6445223Ssklower };
6545223Ssklower 
6645223Ssklower char	ccitt1980_prof[] = {		/* initial profile */
6745223Ssklower 	Q_BIT,	X29_SET_AND_READ_PARMS,
6845223Ssklower 	X29_ECHO_CODE,			1,	/* echo on */
6945223Ssklower 	X29_FORWARDING_SIGNAL_CODE,	126,	/* forward on all cntl */
7045223Ssklower 	X29_IDLE_TIMER_CODE,		0,	/* off */
7145223Ssklower 	X29_AUX_DEV_CONTROL_CODE,	0,	/* off */
7245223Ssklower 	X29_RECEIVE_NET_MSGS_CODE,	1,	/* xmit network msgs */
7345223Ssklower 	X29_BREAK_PROCEDURE_CODE,	21,
7445223Ssklower 	X29_PADDING_CODE,		0,	/* off */
7545223Ssklower 	X29_LINE_FOLDING_CODE,		0,	/* off */
7645223Ssklower 	X29_TRANSMISSION_SPEED_CODE,	0,
7745223Ssklower 	X29_XON_XOFF_CODE,		1,	/* enable XON/XOFF */
7845223Ssklower 
7945223Ssklower 	X29_LF_AFTER_CR,		4,	/* lf after cr from terminal */
8045223Ssklower 	X29_EDITING,			1,	/* on */
8145223Ssklower 	X29_CHARACTER_DELETE,		CERASE,
8245223Ssklower 	X29_LINE_DELETE,		CKILL,
8345223Ssklower 	X29_LINE_DISPLAY,		CRPRNT,
8445223Ssklower };
8545223Ssklower 
8645223Ssklower char	datapac_prof[] = {		/* Canadian X.25 network */
8745223Ssklower 	Q_BIT,	X29_SET_AND_READ_PARMS,
8845223Ssklower 	X29_ECHO_CODE,			1,	/* echo on */
8945223Ssklower 	X29_FORWARDING_SIGNAL_CODE,	126,	/* forward on all cntl */
9045223Ssklower 	X29_IDLE_TIMER_CODE,		0,	/* off */
9145223Ssklower 	X29_AUX_DEV_CONTROL_CODE,	0,	/* off */
9245223Ssklower 	X29_RECEIVE_NET_MSGS_CODE,	1,	/* xmit network msgs */
9345223Ssklower 	X29_BREAK_PROCEDURE_CODE,	21,
9445223Ssklower 	X29_PADDING_CODE,		0,	/* off */
9545223Ssklower 	X29_LINE_FOLDING_CODE,		0,	/* off */
9645223Ssklower 	X29_TRANSMISSION_SPEED_CODE,	0,
9745223Ssklower 	X29_XON_XOFF_CODE,		1,	/* enable XON/XOFF */
9845223Ssklower 
9945223Ssklower 	X29_LF_AFTER_CR,		4,	/* lf after cr from terminal */
10045223Ssklower 	X29_EDITING,			1,	/* on */
10145223Ssklower 	X29_CHARACTER_DELETE,		CERASE,
10245223Ssklower 	X29_LINE_DELETE,		CKILL,
10345223Ssklower 	X29_LINE_DISPLAY,		CRPRNT,
10445223Ssklower 
10545223Ssklower 	/*
10645223Ssklower 	 * This rubbish can be removed when Datapac
10745223Ssklower 	 * adopts the 1980 standard parameter set.
10845223Ssklower 	 */
10945223Ssklower 
11045223Ssklower 	0,				0,	/* national parameter marker */
11145223Ssklower 	123,				0,	/* parity off */
11245223Ssklower };
11345223Ssklower 
11445223Ssklower struct	net {
11545223Ssklower 	char	*n_name;	/* generic name */
11645223Ssklower 	short	n_type;		/* see defines above */
11745223Ssklower 	char	*n_profile;	/* initial profile */
11845223Ssklower 	short	n_proflen;	/* length of n_profile */
11945223Ssklower } *netp, nets[] = {
12045223Ssklower 	"x.25",		X25NET,		0,		0,
12145223Ssklower 	"1978",		CCITT1978,	ccitt1978_prof,	sizeof(ccitt1978_prof),
12245223Ssklower 	"ccitt1978",	CCITT1978,	ccitt1978_prof,	sizeof(ccitt1978_prof),
12345223Ssklower 	"1980",		CCITT1980,	ccitt1980_prof,	sizeof(ccitt1980_prof),
12445223Ssklower 	"ccitt1980",	CCITT1980,	ccitt1980_prof,	sizeof(ccitt1980_prof),
12545223Ssklower 	"datapac",	CCITT1980,	datapac_prof,	sizeof(datapac_prof),
12645223Ssklower 	0,		0,		0,		0
12745223Ssklower };
12845223Ssklower 
12945223Ssklower main(argc, argv)
13045223Ssklower register char **argv;
13145223Ssklower {
13245223Ssklower 	register int s, pid;
13345223Ssklower 	register char *p;
13445223Ssklower 
13545223Ssklower 	/*
13645223Ssklower 	 * If this host doesn't support X.25, give up.
13745223Ssklower 	 */
13845223Ssklower 	s = socket(AF_CCITT, SOCK_STREAM, 0);
13945223Ssklower 	if (s < 0 && errno == EPROTONOSUPPORT)
14045223Ssklower 		fatal(2, "X.25 is not supported on this machine");
14145223Ssklower 	close(s);
14245223Ssklower 	netp = lookup ("ccitt1978");
14345223Ssklower 	sock.x25_family = AF_CCITT;
144*45293Ssklower 	sock.x25_len = sizeof(sock);
14545223Ssklower 	sock.x25_opts.op_flags = X25_MQBIT;
14645223Ssklower 	sock.x25_udata[0] = ITI_CALL;
14745223Ssklower 	sock.x25_udlen = 4;
14845223Ssklower 
14945223Ssklower 	for (argv++; argc > 1; argc--, argv++)
15045223Ssklower 		if (**argv == '-')
15145223Ssklower 			for (p = *argv+1; *p; p++)
15245223Ssklower 			switch (*p) {
15345223Ssklower 			case 'b':
15445223Ssklower 				send_banner++;
15545223Ssklower 				break;
15645223Ssklower 
15745223Ssklower 			case 'c':
15845223Ssklower 				if (argc > 1) {
15945223Ssklower 					argc--; argv++;
16045223Ssklower 					if ((netp = lookup (*argv)) == 0)
16145223Ssklower 						fatal(1, "Unknown network type");
16245223Ssklower 				}
16345223Ssklower 				break;
16445223Ssklower 
16545223Ssklower 			case 'p':
16645223Ssklower 				if (argc > 1) {
16745223Ssklower 					argc--; argv++;
16845223Ssklower 					strcpy (sock.x25_udata, *argv);
16945223Ssklower 				}
17045223Ssklower 				break;
17145223Ssklower 
17245223Ssklower 			case 'r':
17345223Ssklower 				sock.x25_opts.op_flags |= X25_REVERSE_CHARGE;
17445223Ssklower 				break;
17545223Ssklower 
176*45293Ssklower 			case 'd':
177*45293Ssklower 				debug++;
178*45293Ssklower 				break;
179*45293Ssklower 
18045223Ssklower 			case 't':
18145223Ssklower 				if (argc > 1) {
18245223Ssklower 					argc--; argv++;
18345223Ssklower 					tracefn = *argv;
18445223Ssklower 				}
18545223Ssklower 				else fatal(1, "missing trace file");
18645223Ssklower 				break;
18745223Ssklower 
18845223Ssklower 			default:
18945223Ssklower 				fatal (1, "usage: x29d -b -c nettype -p protocol -r -t trace_file server");
19045223Ssklower 			}
19145223Ssklower 		else
19245223Ssklower 			server = *argv;
19345223Ssklower 	if (server == 0)
19445223Ssklower 		fatal (1, "no server specified");
195*45293Ssklower 	if (debug == 0)
196*45293Ssklower 		daemon(0, 0);
19745223Ssklower 
19845223Ssklower 	while((s = socket(AF_CCITT, SOCK_STREAM, 0)) < 0)
19945223Ssklower 		sleep(60);
20045223Ssklower 	while (bind(s, (caddr_t)&sock, sizeof (sock)) < 0)
20145223Ssklower 		sleep(60);
20245223Ssklower 	signal(SIGCHLD, reapchild);
20345223Ssklower 	listen(s, 5);
20445223Ssklower 
20545223Ssklower 	for (;;) {
20645223Ssklower 		struct sockaddr_x25 from;
20745223Ssklower 		int fromlen = sizeof (from);
20845223Ssklower 
20945223Ssklower 		if ((net = accept(s, (caddr_t)&from, &fromlen)) < 0) {
21045223Ssklower 			if (errno != EINTR)
21145223Ssklower 				sleep (60);
21245223Ssklower 			continue;
21345223Ssklower 		}
21445223Ssklower 		while ((pid = fork()) < 0)
21545223Ssklower 			sleep(60);
21645223Ssklower 		if (pid == 0) {
21745223Ssklower 			signal(SIGCHLD, SIG_DFL);
21845223Ssklower 			doit(&from);
21945223Ssklower 		}
22045223Ssklower 		close(net);
22145223Ssklower 	}
22245223Ssklower 	/*NOTREACHED*/
22345223Ssklower }
22445223Ssklower 
22545223Ssklower struct net *
22645223Ssklower lookup (name)
22745223Ssklower char *name;
22845223Ssklower {
22945223Ssklower 	register struct net *np;
23045223Ssklower 
23145223Ssklower 	for (np = nets; np->n_name; np++)
23245223Ssklower 		if (strcmp (np->n_name, name) == 0)
23345223Ssklower 			return (np);
23445223Ssklower 	return (0);
23545223Ssklower }
23645223Ssklower 
23745223Ssklower reapchild()
23845223Ssklower {
23945223Ssklower 	union wait status;
24045223Ssklower 
24145223Ssklower 	while (wait3(&status, WNOHANG, 0) > 0)
24245223Ssklower 		;
24345223Ssklower }
24445223Ssklower 
24545223Ssklower char	*envinit[] = { "TERM=ccitt", 0 };
24645223Ssklower int	cleanup();
247*45293Ssklower struct termios term;
24845223Ssklower 
24945223Ssklower /*
25045223Ssklower  * Get a pty, scan input lines.
25145223Ssklower  */
25245223Ssklower doit(who)
25345223Ssklower struct sockaddr_x25 *who;
25445223Ssklower {
25545223Ssklower 	register char *cp;
256*45293Ssklower 	int i, p, t;
25745223Ssklower 
25845223Ssklower 	packet_size = 1 << who->x25_opts.op_psize;
259*45293Ssklower 	i = forkpty(&pty, line, &term, 0);
260*45293Ssklower 	if (i > 0)
261*45293Ssklower 		x29d();
262*45293Ssklower 	if (i < 0)
26345223Ssklower 		fatalperror("fork", errno);
26445223Ssklower 	environ = envinit;
26545223Ssklower 	call_server (who);
26645223Ssklower 	/*NOTREACHED*/
26745223Ssklower }
26845223Ssklower 
26945223Ssklower call_server (who)
27045223Ssklower struct sockaddr_x25 *who;
27145223Ssklower {
27245223Ssklower 	register struct hostent *hp = 0;
27345223Ssklower 	register char *p, **ap;
27445223Ssklower 	char *args[MAXARGS];
27545223Ssklower 	struct stat st;
27645223Ssklower 	struct hostent *getx25hostbyaddr();
27745223Ssklower 	int ccitt = 0;
27845223Ssklower 
27945223Ssklower 	p = server;
28045223Ssklower 	while (*p && *p != ' ' && *p != '\t')	/* split program from args */
28145223Ssklower 		p++;
28245223Ssklower 	if (*p)
28345223Ssklower 		*p++ = '\0';
28445223Ssklower 	ap = args;
28545223Ssklower 	while (*p) {
28645223Ssklower 		while (*p == ' ' || *p == '\t')
28745223Ssklower 			p++;
28845223Ssklower 		if (ap < &args[MAXARGS-2])
28945223Ssklower 			*ap++ = p;
29045223Ssklower 		if (strcmp(p, "-ccitt") == 0)
29145223Ssklower 			ccitt = 1;
29245223Ssklower 		while (*p && *p != ' ' && *p != '\t')
29345223Ssklower 			p++;
29445223Ssklower 		if (*p)
29545223Ssklower 			*p++ = '\0';
29645223Ssklower 	}
29745223Ssklower 	if (stat (server, &st) < 0)
29845223Ssklower 		fatalperror (server, errno);
29945223Ssklower 	/*
30045223Ssklower 	 * For security: if running as root, switch to user
30145223Ssklower 	 * and group id of server.  This prevents privately
30245223Ssklower 	 * maintainted or bogus servers from getting super-
30345223Ssklower 	 * user permissions.
30445223Ssklower 	 */
30545223Ssklower 	if (getuid() == 0) {
30645223Ssklower 		setgid (st.st_gid);
30745223Ssklower 		setuid (st.st_uid);
30845223Ssklower 	}
30945223Ssklower 	if (hp = getx25hostbyaddr (who->x25_addr))
31045223Ssklower 		*ap++ = hp->h_name;
31145223Ssklower 	else
31245223Ssklower 		*ap++ = (char *)who->x25_addr;
31345223Ssklower 	/*
31445223Ssklower 	 * If the -ccitt flag was given, add another argument
31545223Ssklower 	 * to tell login if charging is being reversed or not.
31645223Ssklower 	 */
31745223Ssklower 	if (ccitt)
31845223Ssklower 		*ap++ = (who->x25_opts.op_flags & X25_REVERSE_CHARGE) ? "y" : "n";
31945223Ssklower 	*ap = 0;
32045223Ssklower 	execv (server, args);
32145223Ssklower 	fatalperror (server, errno);
32245223Ssklower 	/*NOTREACHED*/
32345223Ssklower }
32445223Ssklower 
32545223Ssklower fatal(f, msg)
32645223Ssklower 	int f;
32745223Ssklower 	char *msg;
32845223Ssklower {
32945223Ssklower 	register char *p;
33045223Ssklower 	char buf[BUFSIZ], *index();
33145223Ssklower 
33245223Ssklower 	p = buf;
33345223Ssklower 	if (f == net)
33445223Ssklower 		*p++ = 0;
33545223Ssklower 	strcpy(p, "x29d: ");
33645223Ssklower 	strcat(p, msg);
33745223Ssklower 	strcat(p, "\n");
33845223Ssklower 	(void) write(f, p, (index(p, '\n')-p)+1);
33945223Ssklower 	exit(1);
34045223Ssklower }
34145223Ssklower 
34245223Ssklower fatalperror(msg, err)
34345223Ssklower char *msg;
34445223Ssklower {
34545223Ssklower 	char buf[BUFSIZ];
34645223Ssklower 	extern char *sys_errlist[];
34745223Ssklower 
34845223Ssklower 	strcpy(buf, msg);
34945223Ssklower 	strcat(buf, ": ");
35045223Ssklower 	strcat(buf, sys_errlist[err]);
35145223Ssklower 	fatal(net, buf);
35245223Ssklower }
35345223Ssklower 
35445223Ssklower /*
35545223Ssklower  * Main loop.  Select from pty and network, and
35645223Ssklower  * hand data to iti receiver.
35745223Ssklower  */
35845223Ssklower x29d()
35945223Ssklower {
36045223Ssklower 	register int pcc, fcc, cc;
36145223Ssklower 	register char *fbp;
36245223Ssklower 	int pgrp, x25_interrupt(), on = 1;
36345223Ssklower 	char hostname[32];
36445223Ssklower 
36545223Ssklower 	ioctl(net, FIONBIO, (char *)&on);
36645223Ssklower 	ioctl(pty, FIONBIO, (char *)&on);
36745223Ssklower 	ioctl(pty, TIOCPKT, (char *)&on);
368*45293Ssklower #define TIOCREMECHO 5 /*  to make compile */
36945223Ssklower 	ioctl(pty, TIOCREMECHO, (char *)&on);	/* enable special pty mode */
37045223Ssklower 	signal(SIGPIPE, SIG_IGN);	/* why not cleanup?  --kwl */
37145223Ssklower 	signal(SIGTSTP, SIG_IGN);
37245223Ssklower 	signal(SIGCHLD, cleanup);
37345223Ssklower 	signal(SIGHUP, cleanup);
37445223Ssklower 
37545223Ssklower 	signal(SIGTTOU, SIG_IGN);
37645223Ssklower 	signal(SIGURG, x25_interrupt);	/* for out-of-band data */
37745223Ssklower 
37845223Ssklower 	if (netp->n_proflen)
37945223Ssklower 		(void) write(net, netp->n_profile, netp->n_proflen);
38045223Ssklower 
38145223Ssklower 	/*
38245223Ssklower 	 * Show banner that getty never gave.
38345223Ssklower 	 */
38445223Ssklower 	if (send_banner) {
38545223Ssklower 		gethostname(hostname, sizeof (hostname));
38645223Ssklower #ifdef BSD4_3
38745223Ssklower 		strcpy(pibuf+1, "\r\n\r\n4.3 BSD UNIX (");
38845223Ssklower #else
38945223Ssklower 		strcpy(pibuf+1, "\r\n\r\n4.2 BSD UNIX (");
39045223Ssklower #endif
39145223Ssklower 		strcat(pibuf+1, hostname);
39245223Ssklower 		strcat(pibuf+1, ")\r\n\r\n");
39345223Ssklower 		pcc = strlen(pibuf+1) + 1;
39445223Ssklower 	} else
39545223Ssklower 		pcc = 0;
39645223Ssklower 
39745223Ssklower 	fcc = 0;
39845223Ssklower 	for (;;) {
39945223Ssklower 		int ibits, obits;
40045223Ssklower 
40145223Ssklower 		ibits = obits = 0;
40245223Ssklower 		/*
40345223Ssklower 		 * Never look for input if there's still
40445223Ssklower 		 * stuff in the corresponding output buffer
40545223Ssklower 		 */
40645223Ssklower 		if (fcc >= 0)			/* net connection alive? */
40745223Ssklower 			if (fcc && pcc >= 0)	/* output pending? */
40845223Ssklower 				obits |= (1 << pty);
40945223Ssklower 			else
41045223Ssklower 				if (pcc >= 0)	/* pty still alive? */
41145223Ssklower 					ibits |= (1 << net);
41245223Ssklower 		if (pcc >= 0)			/* pty connection alive? */
41345223Ssklower 			if (pcc && fcc >= 0)	/* output pending? */
41445223Ssklower 				obits |= (1 << net);
41545223Ssklower 			else
41645223Ssklower 				if (fcc >= 0)	/* net still alive? */
41745223Ssklower 					ibits |= (1 << pty);
41845223Ssklower 		if(ibits == 0 && obits == 0)
41945223Ssklower 			break;
42045223Ssklower 		(void) select(16, &ibits, &obits, (int *)0, 0);
42145223Ssklower 		if (ibits == 0 && obits == 0) {
42245223Ssklower 			sleep(5);
42345223Ssklower 			continue;
42445223Ssklower 		}
42545223Ssklower 
42645223Ssklower 		/*
42745223Ssklower 		 * Something to read from the network...
42845223Ssklower 		 */
42945223Ssklower 		if (ibits & (1 << net)) {
43045223Ssklower 			fcc = read(net, fibuf, BUFSIZ);
43145223Ssklower 			fbp = fibuf+1;
43245223Ssklower 			if (fcc < 0 && errno == EWOULDBLOCK)
43345223Ssklower 				fcc = 0;
43445223Ssklower 			else if(fcc <= 0)
43545223Ssklower 				fcc = -1;
43645223Ssklower 			else {
43745223Ssklower 				if (tracefn)
43845223Ssklower 					x29d_trace("netread", fibuf, fcc);
43945223Ssklower 				if(fibuf[0] & Q_BIT) {
44045223Ssklower 					x29_qbit(fcc);
44145223Ssklower 					fcc = 0;
44245223Ssklower 				} else
44345223Ssklower 					fcc--;
44445223Ssklower 			}
44545223Ssklower 		}
44645223Ssklower 
44745223Ssklower 		/*
44845223Ssklower 		 * Something to read from the pty...
44945223Ssklower 		 */
45045223Ssklower 		if (ibits & (1 << pty)) {
45145223Ssklower 			pcc = read(pty, pibuf, packet_size+1);
45245223Ssklower 			if (pcc < 0 && errno == EWOULDBLOCK)
45345223Ssklower 				pcc = 0;
45445223Ssklower 			else if (pcc <= 0)
45545223Ssklower 				pcc = -1;
45645223Ssklower 			else if(pibuf[0] != 0) {	/* non-data packet */
45745223Ssklower 				if (pibuf[0] & TIOCPKT_IOCTL)
45845223Ssklower 					pcc = set_x29_parameters();
45945223Ssklower 				else
46045223Ssklower 					pcc = 0;
46145223Ssklower 			} else				/* data packet */
46245223Ssklower 				pibuf[0] = 0;
46345223Ssklower 		}
46445223Ssklower 
46545223Ssklower 		if ((obits & (1<<net)) && pcc > 0)
46645223Ssklower 			if((cc = write(net, pibuf, pcc)) == pcc) {
46745223Ssklower 				if(tracefn)
46845223Ssklower 					x29d_trace("netwrite", pibuf, pcc);
46945223Ssklower 				pcc = 0;
47045223Ssklower 			} else {
47145223Ssklower 				extern char *sys_errlist[];
47245223Ssklower 
47345223Ssklower 				if(tracefn)
47445223Ssklower 					x29d_trace("netwrite",
47545223Ssklower 						sys_errlist[errno],
47645223Ssklower 						strlen(sys_errlist[errno]));
47745223Ssklower 
47845223Ssklower 			}
47945223Ssklower 
48045223Ssklower 		if ((obits & (1 << pty)) && fcc > 0) {
48145223Ssklower 			cc = write(pty, fbp, fcc);
48245223Ssklower 			if (cc > 0) {
48345223Ssklower 				fcc -= cc;
48445223Ssklower 				fbp += cc;
48545223Ssklower 			}
48645223Ssklower 		}
48745223Ssklower 	}
48845223Ssklower 	cleanup();
48945223Ssklower }
49045223Ssklower 
49145223Ssklower 
49245223Ssklower /*
49345223Ssklower  * Send interrupt to process on other side of pty.
49445223Ssklower  * If it is in raw mode, just write NULL;
49545223Ssklower  * otherwise, write intr char.
49645223Ssklower  */
49745223Ssklower 
49845223Ssklower x25_interrupt()
49945223Ssklower {
500*45293Ssklower 	struct termios tt;
50145223Ssklower 	int zero = 0;
50245223Ssklower 
50345223Ssklower 	signal(SIGURG, x25_interrupt);
504*45293Ssklower 	tcgetattr(pty, &tt);
505*45293Ssklower 	if (tt.c_lflag & ISIG) {
506*45293Ssklower 		tcsetattr(pty, TCSAFLUSH, &tt);
507*45293Ssklower 		(void) write(pty, &tt.c_cc[VINTR], 1);
508*45293Ssklower 	} else
50945223Ssklower 		(void) write(pty, "\0", 1);
51045223Ssklower }
51145223Ssklower 
51245223Ssklower cleanup()
51345223Ssklower {
514*45293Ssklower 	char *p;
51545223Ssklower 
516*45293Ssklower 	p = line + sizeof(_PATH_DEV) - 1;
517*45293Ssklower 	if (logout(p))
518*45293Ssklower 		logwtmp(p, "", "");
519*45293Ssklower 	(void)chmod(line, 0666);
520*45293Ssklower 	(void)chown(line, 0, 0);
521*45293Ssklower 	*p = 'p';
522*45293Ssklower 	(void)chmod(line, 0666);
523*45293Ssklower 	(void)chown(line, 0, 0);
524*45293Ssklower 	shutdown(net, 2);
52545223Ssklower 	exit(1);
52645223Ssklower }
52745223Ssklower 
52845223Ssklower /*
52945223Ssklower  * Map unix tty modes and special characters
53045223Ssklower  * into x29 parameters.
53145223Ssklower  */
53245223Ssklower 
53345223Ssklower set_x29_parameters()
53445223Ssklower {
53545223Ssklower 	register char *p;
53645223Ssklower 	register int f;
537*45293Ssklower 	struct termios b;
53845223Ssklower 
53945223Ssklower 	if (netp->n_type == X25NET)
54045223Ssklower 		return (0);
541*45293Ssklower 	tcgetattr(pty, &b);
54245223Ssklower 	p = pibuf;
54345223Ssklower 	*p++ = Q_BIT;
54445223Ssklower 	*p++ = X29_SET_PARMS;
545*45293Ssklower 	/* *p++ = X29_ESCAPE_TO_CMD_CODE; *p++ = (f & (RAW|CBREAK)) == 0;*/
546*45293Ssklower 	*p++ = X29_ESCAPE_TO_CMD_CODE; *p++ = (b.c_lflag & ICANON) != 0;
54745223Ssklower 
548*45293Ssklower 	*p++ = X29_ECHO_CODE; *p++ = (b.c_lflag & ECHO) != 0;
549*45293Ssklower 	*p++ = X29_FORWARDING_SIGNAL_CODE;
550*45293Ssklower 			*p++ = (b.c_lflag & ISIG) ? 0 : 126;
551*45293Ssklower 
55245223Ssklower 	/*
55345223Ssklower 	 * The value of 10 (0.5 seconds) for the idle timer when
55445223Ssklower 	 * in raw or cbreak mode is a compromise value.  For good
55545223Ssklower 	 * interactive response this value should be as low as
55645223Ssklower 	 * possible; for reasonable efficiency with file transfers
55745223Ssklower 	 * this value should be at fairly high.  This number should
55845223Ssklower 	 * be changed to suit local requirements.
55945223Ssklower 	 */
56045223Ssklower 
561*45293Ssklower 	/**p++ = X29_IDLE_TIMER_CODE;	*p++ = (f & (RAW|CBREAK)) ? 10 : 0;*/
562*45293Ssklower 	*p++ = X29_IDLE_TIMER_CODE; *p++ = (b.c_lflag & ICANON)  ? 0 : 10;
563*45293Ssklower 
564*45293Ssklower 	/**p++ = X29_AUX_DEV_CONTROL_CODE;*p++ = (f & TANDEM) != 0;*/
565*45293Ssklower 	*p++ = X29_AUX_DEV_CONTROL_CODE;*p++ = (b.c_iflag & IXOFF) != 0;
566*45293Ssklower 	*p++ = X29_XON_XOFF_CODE;	*p++ = (b.c_iflag & IXON) != 0;
56745223Ssklower 	if(netp->n_type == CCITT1980) {
568*45293Ssklower 		*p++ = X29_LF_AFTER_CR;
569*45293Ssklower 		/* *p++ = (f & (RAW|CBREAK) || (f & ECHO) == 0) ? 0 : 4; */
570*45293Ssklower 		*p++ = (0 == (b.c_lflag & ICANON) || 0 == (b.c_lflag & ECHO)) ?
571*45293Ssklower 			0 : 4;
57245223Ssklower 
573*45293Ssklower 		*p++ = X29_EDITING; *p++ = (b.c_lflag & ICANON) != 0;
574*45293Ssklower #define ctlchar(x) \
575*45293Ssklower   (0 == (b.c_lflag & ICANON) || b.c_cc[x] == _POSIX_VDISABLE) ? 0 : b.c_cc[x]
576*45293Ssklower 		*p++ = X29_CHARACTER_DELETE; *p++ = ctlchar(VERASE);
577*45293Ssklower 		*p++ = X29_LINE_DELETE; *p++ = ctlchar(VKILL);
578*45293Ssklower 		*p++ = X29_LINE_DISPLAY; *p++ = ctlchar(VREPRINT);
57945223Ssklower 	}
58045223Ssklower 	return (p - pibuf);
58145223Ssklower }
58245223Ssklower 
58345223Ssklower /*
58445223Ssklower  * Process Q BIT (control) packets from the net.
58545223Ssklower  * The only message that we are interested in are
58645223Ssklower  * those indicating output is being discarded.
58745223Ssklower  */
58845223Ssklower 
58945223Ssklower x29_qbit(n)
59045223Ssklower {
59145223Ssklower 	register char *p;
59245223Ssklower 
59345223Ssklower 	switch (fibuf[1]) {
59445223Ssklower 	case X29_SET_PARMS:
59545223Ssklower 	case X29_SET_AND_READ_PARMS:
59645223Ssklower 	case X29_PARAMETER_INDICATION:
59745223Ssklower 	case X29_INDICATION_OF_BREAK:
59845223Ssklower 		for(p = &fibuf[2]; p < fibuf+n; p++) {
59945223Ssklower 			if(*p == X29_TRANSMISSION_SPEED_CODE) {
60045223Ssklower 				static char speeds[] = {
60145223Ssklower 					B110, B0, B300, B1200, B600,
60245223Ssklower 					B0, B0, B0, B0, B0, B0, B0,
60345223Ssklower 					B2400, B4800, B9600, EXTA };
604*45293Ssklower 				struct termios b;
60545223Ssklower 
60645223Ssklower 				if(*++p >= 0 && *p < sizeof(speeds)) {
607*45293Ssklower 					tcgetattr(pty, &b);
608*45293Ssklower 					cfsetspeed(&b, speeds[*p]);
609*45293Ssklower 					tcsetattr(pty, TCSANOW, &b);
61045223Ssklower 				}
61145223Ssklower 			} else if(*p == X29_DISCARD_OUTPUT_CODE && *++p != 0) {
61245223Ssklower 				char message[4];
61345223Ssklower 
61445223Ssklower 				/*
61545223Ssklower 				 * Always re-enable normal output
61645223Ssklower 				 */
61745223Ssklower 				message[0] = Q_BIT;
61845223Ssklower 				message[1] = X29_SET_PARMS;
61945223Ssklower 				message[2] = X29_DISCARD_OUTPUT_CODE;
62045223Ssklower 				message[3] = 0;
62145223Ssklower 				(void) write(net, message, sizeof(message));
62245223Ssklower 				if(tracefn)
62345223Ssklower 					x29d_trace("netwrite", message, 4);
62445223Ssklower 			}
62545223Ssklower 		}
62645223Ssklower 		return;
62745223Ssklower 
62845223Ssklower 	default: {
62945223Ssklower 			register char *p2;
63045223Ssklower 			char buf[BUFSIZ*4];
63145223Ssklower 			static int fd;
63245223Ssklower 
63345223Ssklower 			/*
63445223Ssklower 			 * Bad news - we received an x29 error message or
63545223Ssklower 			 * some other unknown packet.  Dump the contents
63645223Ssklower 			 * of the packet on the console.
63745223Ssklower 			 */
63845223Ssklower 			p = buf;
63945223Ssklower 			for(p2 = "x29d: unknown q-bit packet: "; *p++ = *p2++; );
64045223Ssklower 			for(p2 = fibuf+1; p2 < fibuf+n; p2++)
64145223Ssklower 				if(*p2 >= ' ' && *p2 < 0177)
64245223Ssklower 					*p++ = *p2;
64345223Ssklower 				else {
64445223Ssklower 					*p++ = '\\';
64545223Ssklower 					*p++ = ((*p2 & 0300) >> 6) + '0';
64645223Ssklower 					*p++ = ((*p2 & 070) >> 3) + '0';
64745223Ssklower 					*p++ = (*p2 & 07) + '0';
64845223Ssklower 				}
64945223Ssklower 			*p++ = '\n';
65045223Ssklower 			if(fd <= 0)
65145223Ssklower 				fd = open(console, 1);
65245223Ssklower 			(void) write(fd, buf, p-buf);
65345223Ssklower 		}
65445223Ssklower 	}
65545223Ssklower }
65645223Ssklower 
65745223Ssklower x29d_trace(s, bp, n)
65845223Ssklower char *s, *bp;
65945223Ssklower {
66045223Ssklower 	static int fd;
66145223Ssklower 	char buf[BUFSIZ*4];
66245223Ssklower 	register char *p1, *p2;
66345223Ssklower 
66445223Ssklower 	for(p1 = buf; *s; *p1++ = *s++);
66545223Ssklower 	*p1++ = ':';
66645223Ssklower 	*p1++ = ' ';
66745223Ssklower 	for(p2=bp; p2 < bp+n; p2++)
66845223Ssklower 		if(*p2 >= ' ' && *p2 < 0177)
66945223Ssklower 			*p1++ = *p2;
67045223Ssklower 		else {
67145223Ssklower 			*p1++ = '\\';
67245223Ssklower 			*p1++ = ((*p2 & 0300) >> 6) + '0';
67345223Ssklower 			*p1++ = ((*p2 & 070) >> 3) + '0';
67445223Ssklower 			*p1++ = (*p2 & 07) + '0';
67545223Ssklower 		}
67645223Ssklower 	*p1++ = '\n';
67745223Ssklower 	if(fd <= 0)
67845223Ssklower 		fd = creat(tracefn, 0666);
67945223Ssklower 	(void) write(fd, buf, p1-buf);
68045223Ssklower }
681