xref: /csrg-svn/contrib/usr.x25/x29d/x29d.c (revision 48847)
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>
2245293Ssklower #include <sys/ioctl.h>
2345293Ssklower #include <sys/termios.h>
2445293Ssklower #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;
4045293Ssklower char	line[MAXPATHLEN];
4145223Ssklower char	console[] = "/dev/console";
4245223Ssklower short	packet_size;
4345293Ssklower short	debug;
4445223Ssklower char	*tracefn;		/* trace file name */
4545223Ssklower char	*server;
4645223Ssklower short	send_banner;
4745294Ssklower struct	termios pt, old_pt;
4845223Ssklower struct	sockaddr_x25 sock;
4945223Ssklower 
5045223Ssklower int	reapchild();
5145223Ssklower struct	net *lookup ();
5245223Ssklower 
5345223Ssklower char	ccitt1978_prof[] = {		/* initial profile */
5445223Ssklower 	Q_BIT,	X29_SET_AND_READ_PARMS,
5545223Ssklower 	X29_ECHO_CODE,			1,	/* echo on */
5645223Ssklower 	X29_FORWARDING_SIGNAL_CODE,	126,	/* forward on all cntl */
5745223Ssklower 	X29_IDLE_TIMER_CODE,		0,	/* off */
5845223Ssklower 	X29_AUX_DEV_CONTROL_CODE,	0,	/* off */
5945223Ssklower 	X29_RECEIVE_NET_MSGS_CODE,	1,	/* xmit network msgs */
6045223Ssklower 	X29_BREAK_PROCEDURE_CODE,	21,
6145223Ssklower 	X29_PADDING_CODE,		0,	/* off */
6245223Ssklower 	X29_LINE_FOLDING_CODE,		0,	/* off */
6345223Ssklower 	X29_TRANSMISSION_SPEED_CODE,	0,
6445223Ssklower 	X29_XON_XOFF_CODE,		1,	/* enable XON/XOFF */
6545223Ssklower };
6645223Ssklower 
6745223Ssklower char	ccitt1980_prof[] = {		/* initial profile */
6845223Ssklower 	Q_BIT,	X29_SET_AND_READ_PARMS,
6945223Ssklower 	X29_ECHO_CODE,			1,	/* echo on */
7045223Ssklower 	X29_FORWARDING_SIGNAL_CODE,	126,	/* forward on all cntl */
7145223Ssklower 	X29_IDLE_TIMER_CODE,		0,	/* off */
7245223Ssklower 	X29_AUX_DEV_CONTROL_CODE,	0,	/* off */
7345223Ssklower 	X29_RECEIVE_NET_MSGS_CODE,	1,	/* xmit network msgs */
7445223Ssklower 	X29_BREAK_PROCEDURE_CODE,	21,
7545223Ssklower 	X29_PADDING_CODE,		0,	/* off */
7645223Ssklower 	X29_LINE_FOLDING_CODE,		0,	/* off */
7745223Ssklower 	X29_TRANSMISSION_SPEED_CODE,	0,
7845223Ssklower 	X29_XON_XOFF_CODE,		1,	/* enable XON/XOFF */
7945223Ssklower 
8045223Ssklower 	X29_LF_AFTER_CR,		4,	/* lf after cr from terminal */
8145223Ssklower 	X29_EDITING,			1,	/* on */
8245223Ssklower 	X29_CHARACTER_DELETE,		CERASE,
8345223Ssklower 	X29_LINE_DELETE,		CKILL,
8445223Ssklower 	X29_LINE_DISPLAY,		CRPRNT,
8545223Ssklower };
8645223Ssklower 
8745223Ssklower char	datapac_prof[] = {		/* Canadian X.25 network */
8845223Ssklower 	Q_BIT,	X29_SET_AND_READ_PARMS,
8945223Ssklower 	X29_ECHO_CODE,			1,	/* echo on */
9045223Ssklower 	X29_FORWARDING_SIGNAL_CODE,	126,	/* forward on all cntl */
9145223Ssklower 	X29_IDLE_TIMER_CODE,		0,	/* off */
9245223Ssklower 	X29_AUX_DEV_CONTROL_CODE,	0,	/* off */
9345223Ssklower 	X29_RECEIVE_NET_MSGS_CODE,	1,	/* xmit network msgs */
9445223Ssklower 	X29_BREAK_PROCEDURE_CODE,	21,
9545223Ssklower 	X29_PADDING_CODE,		0,	/* off */
9645223Ssklower 	X29_LINE_FOLDING_CODE,		0,	/* off */
9745223Ssklower 	X29_TRANSMISSION_SPEED_CODE,	0,
9845223Ssklower 	X29_XON_XOFF_CODE,		1,	/* enable XON/XOFF */
9945223Ssklower 
10045223Ssklower 	X29_LF_AFTER_CR,		4,	/* lf after cr from terminal */
10145223Ssklower 	X29_EDITING,			1,	/* on */
10245223Ssklower 	X29_CHARACTER_DELETE,		CERASE,
10345223Ssklower 	X29_LINE_DELETE,		CKILL,
10445223Ssklower 	X29_LINE_DISPLAY,		CRPRNT,
10545223Ssklower 
10645223Ssklower 	/*
10745223Ssklower 	 * This rubbish can be removed when Datapac
10845223Ssklower 	 * adopts the 1980 standard parameter set.
10945223Ssklower 	 */
11045223Ssklower 
11145223Ssklower 	0,				0,	/* national parameter marker */
11245223Ssklower 	123,				0,	/* parity off */
11345223Ssklower };
11445223Ssklower 
11545223Ssklower struct	net {
11645223Ssklower 	char	*n_name;	/* generic name */
11745223Ssklower 	short	n_type;		/* see defines above */
11845223Ssklower 	char	*n_profile;	/* initial profile */
11945223Ssklower 	short	n_proflen;	/* length of n_profile */
12045223Ssklower } *netp, nets[] = {
12145223Ssklower 	"x.25",		X25NET,		0,		0,
12245223Ssklower 	"1978",		CCITT1978,	ccitt1978_prof,	sizeof(ccitt1978_prof),
12345223Ssklower 	"ccitt1978",	CCITT1978,	ccitt1978_prof,	sizeof(ccitt1978_prof),
12445223Ssklower 	"1980",		CCITT1980,	ccitt1980_prof,	sizeof(ccitt1980_prof),
12545223Ssklower 	"ccitt1980",	CCITT1980,	ccitt1980_prof,	sizeof(ccitt1980_prof),
12645223Ssklower 	"datapac",	CCITT1980,	datapac_prof,	sizeof(datapac_prof),
12745223Ssklower 	0,		0,		0,		0
12845223Ssklower };
12945223Ssklower 
main(argc,argv)13045223Ssklower main(argc, argv)
13145223Ssklower register char **argv;
13245223Ssklower {
13345223Ssklower 	register int s, pid;
13445223Ssklower 	register char *p;
13545223Ssklower 
13645223Ssklower 	/*
13745223Ssklower 	 * If this host doesn't support X.25, give up.
13845223Ssklower 	 */
13945223Ssklower 	s = socket(AF_CCITT, SOCK_STREAM, 0);
14045223Ssklower 	if (s < 0 && errno == EPROTONOSUPPORT)
14145223Ssklower 		fatal(2, "X.25 is not supported on this machine");
14245223Ssklower 	close(s);
14345223Ssklower 	netp = lookup ("ccitt1978");
14445223Ssklower 	sock.x25_family = AF_CCITT;
14545293Ssklower 	sock.x25_len = sizeof(sock);
14645223Ssklower 	sock.x25_opts.op_flags = X25_MQBIT;
14745223Ssklower 	sock.x25_udata[0] = ITI_CALL;
14845223Ssklower 	sock.x25_udlen = 4;
14945223Ssklower 
15045223Ssklower 	for (argv++; argc > 1; argc--, argv++)
15145223Ssklower 		if (**argv == '-')
15245223Ssklower 			for (p = *argv+1; *p; p++)
15345223Ssklower 			switch (*p) {
15445223Ssklower 			case 'b':
15545223Ssklower 				send_banner++;
15645223Ssklower 				break;
15745223Ssklower 
15845223Ssklower 			case 'c':
15945223Ssklower 				if (argc > 1) {
16045223Ssklower 					argc--; argv++;
16145223Ssklower 					if ((netp = lookup (*argv)) == 0)
16245223Ssklower 						fatal(1, "Unknown network type");
16345223Ssklower 				}
16445223Ssklower 				break;
16545223Ssklower 
16645223Ssklower 			case 'p':
16745223Ssklower 				if (argc > 1) {
16845223Ssklower 					argc--; argv++;
16945223Ssklower 					strcpy (sock.x25_udata, *argv);
17045223Ssklower 				}
17145223Ssklower 				break;
17245223Ssklower 
17345223Ssklower 			case 'r':
17445223Ssklower 				sock.x25_opts.op_flags |= X25_REVERSE_CHARGE;
17545223Ssklower 				break;
17645223Ssklower 
17745293Ssklower 			case 'd':
17845293Ssklower 				debug++;
17945293Ssklower 				break;
18045293Ssklower 
18145223Ssklower 			case 't':
18245223Ssklower 				if (argc > 1) {
18345223Ssklower 					argc--; argv++;
18445223Ssklower 					tracefn = *argv;
18545223Ssklower 				}
18645223Ssklower 				else fatal(1, "missing trace file");
18745223Ssklower 				break;
18845223Ssklower 
18945223Ssklower 			default:
19045223Ssklower 				fatal (1, "usage: x29d -b -c nettype -p protocol -r -t trace_file server");
19145223Ssklower 			}
19245223Ssklower 		else
19345223Ssklower 			server = *argv;
19445223Ssklower 	if (server == 0)
19545223Ssklower 		fatal (1, "no server specified");
19645293Ssklower 	if (debug == 0)
19745293Ssklower 		daemon(0, 0);
19845223Ssklower 
19945294Ssklower 	while ((s = socket(AF_CCITT, SOCK_STREAM, 0)) < 0)
20045223Ssklower 		sleep(60);
20145223Ssklower 	while (bind(s, (caddr_t)&sock, sizeof (sock)) < 0)
20245223Ssklower 		sleep(60);
20345223Ssklower 	signal(SIGCHLD, reapchild);
20445223Ssklower 	listen(s, 5);
20545223Ssklower 
20645223Ssklower 	for (;;) {
207*48847Ssklower 		struct sockaddr_x25 from;
20845223Ssklower 		int fromlen = sizeof (from);
20945223Ssklower 
21045223Ssklower 		if ((net = accept(s, (caddr_t)&from, &fromlen)) < 0) {
21145223Ssklower 			if (errno != EINTR)
21245223Ssklower 				sleep (60);
21345223Ssklower 			continue;
21445223Ssklower 		}
21545223Ssklower 		while ((pid = fork()) < 0)
21645223Ssklower 			sleep(60);
21745223Ssklower 		if (pid == 0) {
21845223Ssklower 			signal(SIGCHLD, SIG_DFL);
21945223Ssklower 			doit(&from);
22045223Ssklower 		}
22145223Ssklower 		close(net);
22245223Ssklower 	}
22345223Ssklower 	/*NOTREACHED*/
22445223Ssklower }
22545223Ssklower 
22645223Ssklower struct net *
lookup(name)22745223Ssklower lookup (name)
22845223Ssklower char *name;
22945223Ssklower {
23045223Ssklower 	register struct net *np;
23145223Ssklower 
23245223Ssklower 	for (np = nets; np->n_name; np++)
23345223Ssklower 		if (strcmp (np->n_name, name) == 0)
23445223Ssklower 			return (np);
23545223Ssklower 	return (0);
23645223Ssklower }
23745223Ssklower 
reapchild()23845223Ssklower reapchild()
23945223Ssklower {
24045223Ssklower 	union wait status;
24145223Ssklower 
24245223Ssklower 	while (wait3(&status, WNOHANG, 0) > 0)
24345223Ssklower 		;
24445223Ssklower }
24545223Ssklower 
24645223Ssklower char	*envinit[] = { "TERM=ccitt", 0 };
24745223Ssklower int	cleanup();
24845293Ssklower struct termios term;
24945223Ssklower 
25045223Ssklower /*
25145223Ssklower  * Get a pty, scan input lines.
25245223Ssklower  */
25345223Ssklower doit(who)
25445223Ssklower struct sockaddr_x25 *who;
25545223Ssklower {
25645223Ssklower 	register char *cp;
25745293Ssklower 	int i, p, t;
25845223Ssklower 
25945223Ssklower 	packet_size = 1 << who->x25_opts.op_psize;
26045293Ssklower 	i = forkpty(&pty, line, &term, 0);
26145293Ssklower 	if (i > 0)
26245293Ssklower 		x29d();
26345293Ssklower 	if (i < 0)
26445223Ssklower 		fatalperror("fork", errno);
26545223Ssklower 	environ = envinit;
26645223Ssklower 	call_server (who);
26745223Ssklower 	/*NOTREACHED*/
26845223Ssklower }
26945223Ssklower 
27045223Ssklower call_server (who)
27145223Ssklower struct sockaddr_x25 *who;
27245223Ssklower {
27345223Ssklower 	register struct hostent *hp = 0;
27445223Ssklower 	register char *p, **ap;
27545223Ssklower 	char *args[MAXARGS];
27645223Ssklower 	struct stat st;
27745223Ssklower 	struct hostent *getx25hostbyaddr();
27845223Ssklower 	int ccitt = 0;
27945223Ssklower 
28045223Ssklower 	p = server;
28145223Ssklower 	while (*p && *p != ' ' && *p != '\t')	/* split program from args */
28245223Ssklower 		p++;
28345223Ssklower 	if (*p)
28445223Ssklower 		*p++ = '\0';
28545223Ssklower 	ap = args;
28645223Ssklower 	while (*p) {
28745223Ssklower 		while (*p == ' ' || *p == '\t')
28845223Ssklower 			p++;
28945223Ssklower 		if (ap < &args[MAXARGS-2])
29045223Ssklower 			*ap++ = p;
29145223Ssklower 		if (strcmp(p, "-ccitt") == 0)
29245223Ssklower 			ccitt = 1;
29345223Ssklower 		while (*p && *p != ' ' && *p != '\t')
29445223Ssklower 			p++;
29545223Ssklower 		if (*p)
29645223Ssklower 			*p++ = '\0';
29745223Ssklower 	}
29845223Ssklower 	if (stat (server, &st) < 0)
29945223Ssklower 		fatalperror (server, errno);
30045223Ssklower 	/*
30145223Ssklower 	 * For security: if running as root, switch to user
30245223Ssklower 	 * and group id of server.  This prevents privately
30345223Ssklower 	 * maintainted or bogus servers from getting super-
30445223Ssklower 	 * user permissions.
30545223Ssklower 	 */
30645223Ssklower 	if (getuid() == 0) {
30745223Ssklower 		setgid (st.st_gid);
30845223Ssklower 		setuid (st.st_uid);
30945223Ssklower 	}
31045223Ssklower 	if (hp = getx25hostbyaddr (who->x25_addr))
31145223Ssklower 		*ap++ = hp->h_name;
31245223Ssklower 	else
31345223Ssklower 		*ap++ = (char *)who->x25_addr;
31445223Ssklower 	/*
31545223Ssklower 	 * If the -ccitt flag was given, add another argument
31645223Ssklower 	 * to tell login if charging is being reversed or not.
31745223Ssklower 	 */
31845223Ssklower 	if (ccitt)
31945223Ssklower 		*ap++ = (who->x25_opts.op_flags & X25_REVERSE_CHARGE) ? "y" : "n";
32045223Ssklower 	*ap = 0;
32145223Ssklower 	execv (server, args);
32245223Ssklower 	fatalperror (server, errno);
32345223Ssklower 	/*NOTREACHED*/
32445223Ssklower }
32545223Ssklower 
fatal(f,msg)32645223Ssklower fatal(f, msg)
32745223Ssklower 	int f;
32845223Ssklower 	char *msg;
32945223Ssklower {
33045223Ssklower 	register char *p;
33145223Ssklower 	char buf[BUFSIZ], *index();
33245223Ssklower 
33345223Ssklower 	p = buf;
33445223Ssklower 	if (f == net)
33545223Ssklower 		*p++ = 0;
33645223Ssklower 	strcpy(p, "x29d: ");
33745223Ssklower 	strcat(p, msg);
33845223Ssklower 	strcat(p, "\n");
33945223Ssklower 	(void) write(f, p, (index(p, '\n')-p)+1);
34045223Ssklower 	exit(1);
34145223Ssklower }
34245223Ssklower 
fatalperror(msg,err)34345223Ssklower fatalperror(msg, err)
34445223Ssklower char *msg;
34545223Ssklower {
34645223Ssklower 	char buf[BUFSIZ];
34745223Ssklower 	extern char *sys_errlist[];
34845223Ssklower 
34945223Ssklower 	strcpy(buf, msg);
35045223Ssklower 	strcat(buf, ": ");
35145223Ssklower 	strcat(buf, sys_errlist[err]);
35245223Ssklower 	fatal(net, buf);
35345223Ssklower }
35445223Ssklower 
35545223Ssklower /*
35645223Ssklower  * Main loop.  Select from pty and network, and
35745223Ssklower  * hand data to iti receiver.
35845223Ssklower  */
x29d()35945223Ssklower x29d()
36045223Ssklower {
36145223Ssklower 	register int pcc, fcc, cc;
36245223Ssklower 	register char *fbp;
36345223Ssklower 	int pgrp, x25_interrupt(), on = 1;
36445223Ssklower 	char hostname[32];
36545223Ssklower 
36645223Ssklower 	ioctl(net, FIONBIO, (char *)&on);
36745223Ssklower 	ioctl(pty, FIONBIO, (char *)&on);
36845294Ssklower 	/*ioctl(pty, TIOCREMECHO, (char *)&on);	/* enable special pty mode */
36945294Ssklower 	/* new equivalent is no processing in pty, no echo, but let
37045294Ssklower 	   user set modes and have either remote end do line mode processing
37145294Ssklower 	   or do it in daemon */
37245294Ssklower 	ioctl(pty, TIOCEXT, (char *)&on);
37345223Ssklower 	ioctl(pty, TIOCPKT, (char *)&on);
37445294Ssklower 	ioctl(pty, TIOCGETA, (char *)&pt);
37545223Ssklower 	signal(SIGPIPE, SIG_IGN);	/* why not cleanup?  --kwl */
37645223Ssklower 	signal(SIGTSTP, SIG_IGN);
37745223Ssklower 	signal(SIGCHLD, cleanup);
37845223Ssklower 	signal(SIGHUP, cleanup);
37945223Ssklower 
38045223Ssklower 	signal(SIGTTOU, SIG_IGN);
38145223Ssklower 	signal(SIGURG, x25_interrupt);	/* for out-of-band data */
38245223Ssklower 
38345223Ssklower 	if (netp->n_proflen)
38445223Ssklower 		(void) write(net, netp->n_profile, netp->n_proflen);
38545223Ssklower 
38645223Ssklower 	/*
38745223Ssklower 	 * Show banner that getty never gave.
38845223Ssklower 	 */
38945223Ssklower 	if (send_banner) {
39045223Ssklower 		gethostname(hostname, sizeof (hostname));
39145223Ssklower #ifdef BSD4_3
39245223Ssklower 		strcpy(pibuf+1, "\r\n\r\n4.3 BSD UNIX (");
39345223Ssklower #else
39445223Ssklower 		strcpy(pibuf+1, "\r\n\r\n4.2 BSD UNIX (");
39545223Ssklower #endif
39645223Ssklower 		strcat(pibuf+1, hostname);
39745223Ssklower 		strcat(pibuf+1, ")\r\n\r\n");
39845223Ssklower 		pcc = strlen(pibuf+1) + 1;
39945223Ssklower 	} else
40045223Ssklower 		pcc = 0;
40145223Ssklower 
40245223Ssklower 	fcc = 0;
40345223Ssklower 	for (;;) {
40445223Ssklower 		int ibits, obits;
40545223Ssklower 
40645223Ssklower 		ibits = obits = 0;
40745223Ssklower 		/*
40845223Ssklower 		 * Never look for input if there's still
40945223Ssklower 		 * stuff in the corresponding output buffer
41045223Ssklower 		 */
41145223Ssklower 		if (fcc >= 0)			/* net connection alive? */
41245223Ssklower 			if (fcc && pcc >= 0)	/* output pending? */
41345223Ssklower 				obits |= (1 << pty);
41445223Ssklower 			else
41545223Ssklower 				if (pcc >= 0)	/* pty still alive? */
41645223Ssklower 					ibits |= (1 << net);
41745223Ssklower 		if (pcc >= 0)			/* pty connection alive? */
41845223Ssklower 			if (pcc && fcc >= 0)	/* output pending? */
41945223Ssklower 				obits |= (1 << net);
42045223Ssklower 			else
42145223Ssklower 				if (fcc >= 0)	/* net still alive? */
42245223Ssklower 					ibits |= (1 << pty);
42345294Ssklower 		if (ibits == 0 && obits == 0)
42445223Ssklower 			break;
42545223Ssklower 		(void) select(16, &ibits, &obits, (int *)0, 0);
42645223Ssklower 		if (ibits == 0 && obits == 0) {
42745223Ssklower 			sleep(5);
42845223Ssklower 			continue;
42945223Ssklower 		}
43045223Ssklower 
43145223Ssklower 		/*
43245223Ssklower 		 * Something to read from the network...
43345223Ssklower 		 */
43445294Ssklower 		if (fcc == 0 && (ibits & (1 << net))) {
43545223Ssklower 			fcc = read(net, fibuf, BUFSIZ);
43645223Ssklower 			fbp = fibuf+1;
43745223Ssklower 			if (fcc < 0 && errno == EWOULDBLOCK)
43845223Ssklower 				fcc = 0;
43945294Ssklower 			else if (fcc <= 0)
44045223Ssklower 				fcc = -1;
44145223Ssklower 			else {
44245223Ssklower 				if (tracefn)
44345223Ssklower 					x29d_trace("netread", fibuf, fcc);
44445294Ssklower 				if (fibuf[0] & Q_BIT) {
44545223Ssklower 					x29_qbit(fcc);
44645223Ssklower 					fcc = 0;
44745223Ssklower 				} else
44845223Ssklower 					fcc--;
44945223Ssklower 			}
45045223Ssklower 		}
45145223Ssklower 
45245223Ssklower 		/*
45345223Ssklower 		 * Something to read from the pty...
45445223Ssklower 		 */
45545223Ssklower 		if (ibits & (1 << pty)) {
45645223Ssklower 			pcc = read(pty, pibuf, packet_size+1);
45745223Ssklower 			if (pcc < 0 && errno == EWOULDBLOCK)
45845223Ssklower 				pcc = 0;
45945223Ssklower 			else if (pcc <= 0)
46045223Ssklower 				pcc = -1;
46145294Ssklower 			else if (pibuf[0] != 0) {	/* non-data packet */
46245294Ssklower 				if (pibuf[0] & TIOCPKT_IOCTL) {
46345294Ssklower 					if (--pcc > sizeof(pt))
46445294Ssklower 						pcc = sizeof(pt);
46545294Ssklower 					old_pt = pt;
46645294Ssklower 					bcopy(pibuf + 1, (char *)&pt, pcc);
46745223Ssklower 					pcc = set_x29_parameters();
46845294Ssklower 				} else
46945223Ssklower 					pcc = 0;
47045223Ssklower 			} else				/* data packet */
47145223Ssklower 				pibuf[0] = 0;
47245223Ssklower 		}
47345223Ssklower 
47445223Ssklower 		if ((obits & (1<<net)) && pcc > 0)
47545294Ssklower 			if ((cc = write(net, pibuf, pcc)) == pcc) {
47645294Ssklower 				if (tracefn)
47745223Ssklower 					x29d_trace("netwrite", pibuf, pcc);
47845223Ssklower 				pcc = 0;
47945223Ssklower 			} else {
48045223Ssklower 				extern char *sys_errlist[];
48145223Ssklower 
48245294Ssklower 				if (tracefn)
48345223Ssklower 					x29d_trace("netwrite",
48445223Ssklower 						sys_errlist[errno],
48545223Ssklower 						strlen(sys_errlist[errno]));
48645223Ssklower 
48745223Ssklower 			}
48845223Ssklower 
48945223Ssklower 		if ((obits & (1 << pty)) && fcc > 0) {
49045294Ssklower 			cc = ptywrite(fbp, fcc);
49145223Ssklower 			if (cc > 0) {
49245223Ssklower 				fcc -= cc;
49345223Ssklower 				fbp += cc;
49445223Ssklower 			}
49545223Ssklower 		}
49645223Ssklower 	}
49745223Ssklower 	cleanup();
49845223Ssklower }
49945223Ssklower 
50045223Ssklower 
50145223Ssklower /*
50245223Ssklower  * Send interrupt to process on other side of pty.
50345223Ssklower  * If it is in raw mode, just write NULL;
50445223Ssklower  * otherwise, write intr char.
50545223Ssklower  */
50645223Ssklower 
x25_interrupt()50745223Ssklower x25_interrupt()
50845223Ssklower {
50945293Ssklower 	struct termios tt;
51045223Ssklower 	int zero = 0;
51145223Ssklower 
51245223Ssklower 	signal(SIGURG, x25_interrupt);
51345293Ssklower 	tcgetattr(pty, &tt);
51445293Ssklower 	if (tt.c_lflag & ISIG) {
51545293Ssklower 		tcsetattr(pty, TCSAFLUSH, &tt);
51645293Ssklower 		(void) write(pty, &tt.c_cc[VINTR], 1);
51745293Ssklower 	} else
51845223Ssklower 		(void) write(pty, "\0", 1);
51945223Ssklower }
52045223Ssklower 
cleanup()52145223Ssklower cleanup()
52245223Ssklower {
52345293Ssklower 	char *p;
52445223Ssklower 
52545293Ssklower 	p = line + sizeof(_PATH_DEV) - 1;
52645293Ssklower 	if (logout(p))
52745293Ssklower 		logwtmp(p, "", "");
52845293Ssklower 	(void)chmod(line, 0666);
52945293Ssklower 	(void)chown(line, 0, 0);
53045293Ssklower 	*p = 'p';
53145293Ssklower 	(void)chmod(line, 0666);
53245293Ssklower 	(void)chown(line, 0, 0);
53345293Ssklower 	shutdown(net, 2);
53445223Ssklower 	exit(1);
53545223Ssklower }
53645223Ssklower 
53745223Ssklower /*
53845223Ssklower  * Map unix tty modes and special characters
53945223Ssklower  * into x29 parameters.
54045223Ssklower  */
54145223Ssklower 
set_x29_parameters()54245223Ssklower set_x29_parameters()
54345223Ssklower {
54445223Ssklower 	register char *p;
54545294Ssklower 	int f;
54645294Ssklower 	char *lim = p + sizeof (pt);
54745223Ssklower 
54845223Ssklower 	if (netp->n_type == X25NET)
54945223Ssklower 		return (0);
55045294Ssklower 	if ((old_pt.c_lflag & ICANON) != (pt.c_lflag & ICANON)) {
55145294Ssklower 		f = pt.c_lflag & ICANON;
55245294Ssklower 		ioctl(pty, TIOCEXT, &f);
55345294Ssklower 		/* this precipitates more junk of the same
55445294Ssklower 		 * sort that caused our call here, but we can't
55545294Ssklower 		 * turn it off since something may be going on in our progeny.
55645294Ssklower 		 *
55745294Ssklower 		 * Instead, we'll check the next time around to see if nothing
55845294Ssklower 		 * has changed, and skip informing the network.
55945294Ssklower 		 */
56045294Ssklower 	}
56145294Ssklower 	if (bcmp((char *)&pt, (char *)&old_pt, sizeof (pt)) == 0)
56245294Ssklower 		return;
56345223Ssklower 	p = pibuf;
56445223Ssklower 	*p++ = Q_BIT;
56545223Ssklower 	*p++ = X29_SET_PARMS;
56645293Ssklower 	/* *p++ = X29_ESCAPE_TO_CMD_CODE; *p++ = (f & (RAW|CBREAK)) == 0;*/
56745294Ssklower 	*p++ = X29_ESCAPE_TO_CMD_CODE; *p++ = (pt.c_lflag & ICANON) != 0;
56845223Ssklower 
56945294Ssklower 	*p++ = X29_ECHO_CODE; *p++ = (pt.c_lflag & ECHO) != 0;
57045293Ssklower 	*p++ = X29_FORWARDING_SIGNAL_CODE;
57145294Ssklower 			*p++ = (pt.c_lflag & ISIG) ? 0 : 126;
57245293Ssklower 
57345223Ssklower 	/*
57445223Ssklower 	 * The value of 10 (0.5 seconds) for the idle timer when
57545223Ssklower 	 * in raw or cbreak mode is a compromise value.  For good
57645223Ssklower 	 * interactive response this value should be as low as
57745223Ssklower 	 * possible; for reasonable efficiency with file transfers
57845223Ssklower 	 * this value should be at fairly high.  This number should
57945223Ssklower 	 * be changed to suit local requirements.
58045223Ssklower 	 */
58145223Ssklower 
58245293Ssklower 	/**p++ = X29_IDLE_TIMER_CODE;	*p++ = (f & (RAW|CBREAK)) ? 10 : 0;*/
58345294Ssklower 	*p++ = X29_IDLE_TIMER_CODE; *p++ = (pt.c_lflag & ICANON)  ? 0 : 10;
58445293Ssklower 
58545293Ssklower 	/**p++ = X29_AUX_DEV_CONTROL_CODE;*p++ = (f & TANDEM) != 0;*/
58645294Ssklower 	*p++ = X29_AUX_DEV_CONTROL_CODE;*p++ = (pt.c_iflag & IXOFF) != 0;
58745294Ssklower 	*p++ = X29_XON_XOFF_CODE;	*p++ = (pt.c_iflag & IXON) != 0;
58845294Ssklower 	if (netp->n_type == CCITT1980) {
58945293Ssklower 		*p++ = X29_LF_AFTER_CR;
59045293Ssklower 		/* *p++ = (f & (RAW|CBREAK) || (f & ECHO) == 0) ? 0 : 4; */
59145294Ssklower 		*p++ = ((pt.c_lflag & (ICANON | ECHO)) != (ICANON | ECHO)) ?
59245293Ssklower 			0 : 4;
59345223Ssklower 
59445294Ssklower 		*p++ = X29_EDITING; *p++ = (pt.c_lflag & ICANON) != 0;
59545293Ssklower #define ctlchar(x) \
59645294Ssklower   (0 == (pt.c_lflag & ICANON) || pt.c_cc[x] == _POSIX_VDISABLE) ? 0 : pt.c_cc[x]
59745293Ssklower 		*p++ = X29_CHARACTER_DELETE; *p++ = ctlchar(VERASE);
59845293Ssklower 		*p++ = X29_LINE_DELETE; *p++ = ctlchar(VKILL);
59945293Ssklower 		*p++ = X29_LINE_DISPLAY; *p++ = ctlchar(VREPRINT);
60045223Ssklower 	}
60145294Ssklower #undef ctlchar
60245223Ssklower 	return (p - pibuf);
60345223Ssklower }
60445223Ssklower 
60545294Ssklower /* Have to be careful writing to pty.  The pad will forward control
60645294Ssklower  * characters without necessarily sending an interrupt so if ISIG and
60745294Ssklower  * ICANNON are set, must inspect line for quit or interrupt or suspend.
60845294Ssklower  */
ptywrite(buf,n)60945294Ssklower ptywrite(buf, n)
61045294Ssklower char *buf;
61145294Ssklower int n;
61245294Ssklower {
61345294Ssklower 	register char *cp, *lim;
61445294Ssklower 	char *last;
61545294Ssklower #define is_ctl(x) (pt.c_cc[x] == *(cc_t *)cp)
61645294Ssklower 
61745294Ssklower 	if ((pt.c_lflag & EXTPROC) && (pt.c_lflag & ISIG)) {
61845294Ssklower 		for (cp = buf, lim = buf + n; cp < lim; cp ++) {
61945294Ssklower 			if (is_ctl(VLNEXT))
62045294Ssklower 				{ cp++; continue; }
62145294Ssklower 			if (is_ctl(VSUSP) || is_ctl(VDSUSP) ||
62245294Ssklower 			    is_ctl(VINTR) || is_ctl(VQUIT))  {
62345294Ssklower 				int onoff = 0;
62445294Ssklower 				tcflag_t old_echo = pt.c_lflag & ECHO;
62545294Ssklower 
62645294Ssklower 				ioctl(pty, TIOCPKT, (char *)&onoff);
62745294Ssklower 				ioctl(pty, FIONBIO, (char *)&onoff);
62845294Ssklower 				ioctl(pty, TIOCEXT, (char *)&onoff);
62945294Ssklower 				if (old_echo) {
63045294Ssklower 					pt.c_lflag &= ~ECHO;
63145294Ssklower 					ioctl(pty, TIOCSETA, (char *)&pt);
63245294Ssklower 				}
63345294Ssklower 				n = write(pty, buf, n);
63445294Ssklower 				onoff = 1;
63545294Ssklower 				if (old_echo) {
63645294Ssklower 					pt.c_lflag |= ECHO;
63745294Ssklower 					ioctl(pty, TIOCSETA, (char *)&pt);
63845294Ssklower 				}
63945294Ssklower 				ioctl(pty, TIOCEXT, (char *)&onoff);
64045294Ssklower 				ioctl(pty, FIONBIO, (char *)&onoff);
64145294Ssklower 				ioctl(pty, TIOCPKT, (char *)&onoff);
64245294Ssklower 				return (n);
64345294Ssklower 			}
64445294Ssklower 		}
64545294Ssklower 	}
64645294Ssklower 	return write(pty, buf, n);
64745294Ssklower }
64845294Ssklower 
64945223Ssklower /*
65045223Ssklower  * Process Q BIT (control) packets from the net.
65145223Ssklower  * The only message that we are interested in are
65245223Ssklower  * those indicating output is being discarded.
65345223Ssklower  */
65445223Ssklower 
x29_qbit(n)65545223Ssklower x29_qbit(n)
65645223Ssklower {
65745223Ssklower 	register char *p;
65845223Ssklower 
65945223Ssklower 	switch (fibuf[1]) {
66045223Ssklower 	case X29_SET_PARMS:
66145223Ssklower 	case X29_SET_AND_READ_PARMS:
66245223Ssklower 	case X29_PARAMETER_INDICATION:
66345223Ssklower 	case X29_INDICATION_OF_BREAK:
66445294Ssklower 		for (p = &fibuf[2]; p < fibuf+n; p++) {
66545294Ssklower 			if (*p == X29_TRANSMISSION_SPEED_CODE) {
66645223Ssklower 				static char speeds[] = {
66745223Ssklower 					B110, B0, B300, B1200, B600,
66845223Ssklower 					B0, B0, B0, B0, B0, B0, B0,
66945223Ssklower 					B2400, B4800, B9600, EXTA };
67045223Ssklower 
67145294Ssklower 				if (*++p >= 0 && *p < sizeof(speeds)) {
67245294Ssklower 					cfsetspeed(&pt, speeds[*p]);
67345294Ssklower 					tcsetattr(pty, TCSANOW, &pt);
67445223Ssklower 				}
67545294Ssklower 			} else if (*p == X29_DISCARD_OUTPUT_CODE && *++p != 0) {
67645223Ssklower 				char message[4];
67745223Ssklower 
67845223Ssklower 				/*
67945223Ssklower 				 * Always re-enable normal output
68045223Ssklower 				 */
68145223Ssklower 				message[0] = Q_BIT;
68245223Ssklower 				message[1] = X29_SET_PARMS;
68345223Ssklower 				message[2] = X29_DISCARD_OUTPUT_CODE;
68445223Ssklower 				message[3] = 0;
68545223Ssklower 				(void) write(net, message, sizeof(message));
68645294Ssklower 				if (tracefn)
68745223Ssklower 					x29d_trace("netwrite", message, 4);
68845223Ssklower 			}
68945223Ssklower 		}
69045223Ssklower 		return;
69145223Ssklower 
69245223Ssklower 	default: {
69345223Ssklower 			register char *p2;
69445223Ssklower 			char buf[BUFSIZ*4];
69545223Ssklower 			static int fd;
69645223Ssklower 
69745223Ssklower 			/*
69845223Ssklower 			 * Bad news - we received an x29 error message or
69945223Ssklower 			 * some other unknown packet.  Dump the contents
70045223Ssklower 			 * of the packet on the console.
70145223Ssklower 			 */
70245223Ssklower 			p = buf;
70345294Ssklower 			for (p2 = "x29d: unknown q-bit packet: "; *p++ = *p2++; );
70445294Ssklower 			for (p2 = fibuf+1; p2 < fibuf+n; p2++)
70545294Ssklower 				if (*p2 >= ' ' && *p2 < 0177)
70645223Ssklower 					*p++ = *p2;
70745223Ssklower 				else {
70845223Ssklower 					*p++ = '\\';
70945223Ssklower 					*p++ = ((*p2 & 0300) >> 6) + '0';
71045223Ssklower 					*p++ = ((*p2 & 070) >> 3) + '0';
71145223Ssklower 					*p++ = (*p2 & 07) + '0';
71245223Ssklower 				}
71345223Ssklower 			*p++ = '\n';
71445294Ssklower 			if (fd <= 0)
71545223Ssklower 				fd = open(console, 1);
71645223Ssklower 			(void) write(fd, buf, p-buf);
71745223Ssklower 		}
71845223Ssklower 	}
71945223Ssklower }
72045223Ssklower 
x29d_trace(s,bp,n)72145223Ssklower x29d_trace(s, bp, n)
72245223Ssklower char *s, *bp;
72345223Ssklower {
72445223Ssklower 	static int fd;
72545223Ssklower 	char buf[BUFSIZ*4];
72645223Ssklower 	register char *p1, *p2;
72745223Ssklower 
72845294Ssklower 	for (p1 = buf; *s; *p1++ = *s++);
72945223Ssklower 	*p1++ = ':';
73045223Ssklower 	*p1++ = ' ';
73145294Ssklower 	for (p2=bp; p2 < bp+n; p2++)
73245294Ssklower 		if (*p2 >= ' ' && *p2 < 0177)
73345223Ssklower 			*p1++ = *p2;
73445223Ssklower 		else {
73545223Ssklower 			*p1++ = '\\';
73645223Ssklower 			*p1++ = ((*p2 & 0300) >> 6) + '0';
73745223Ssklower 			*p1++ = ((*p2 & 070) >> 3) + '0';
73845223Ssklower 			*p1++ = (*p2 & 07) + '0';
73945223Ssklower 		}
74045223Ssklower 	*p1++ = '\n';
74145294Ssklower 	if (fd <= 0)
74245223Ssklower 		fd = creat(tracefn, 0666);
74345223Ssklower 	(void) write(fd, buf, p1-buf);
74445223Ssklower }
745