4.4BSD/usr/src/contrib/usr.x25/nimd/x29.c

Compare this file to the similar file:
Show the results in this format:

/*
 * X.29 specific code for
 * Network Interface Machine server
 *
 * Frank Pronk
 * Copyright (c) 1984
 */

#include <sys/types.h>
#include "../h/x29.h"

#include "nim.h"

short 	pnums[NX29_PARMS] = {
	1,2,3,4,5,6,7,8,9,10,11,12,	/* 1978+1980 params */
	13, 14, 15, 16, 17, 18		/* 1980 only */
};

char chartab[] = {	/* EVEN parity and forwarding code table */
	0000,0200,0200,0000,0200,0000,0000,0200,
	0200,0000,0000,0200,0000,0200,0200,0000,
	0200,0000,0000,0200,0000,0200,0200,0000,
	0000,0200,0200,0000,0200,0000,0000,0200,
	0200,0000,0000,0200,0000,0200,0200,0000,
	0000,0200,0200,0000,0200,0000,0000,0200,
	0000,0200,0200,0000,0200,0000,0000,0200,
	0200,0000,0000,0200,0000,0200,0200,0000,
	0200,0000,0000,0200,0000,0200,0200,0000,
	0000,0200,0200,0000,0200,0000,0000,0200,
	0000,0200,0200,0000,0200,0000,0000,0200,
	0200,0000,0000,0200,0000,0200,0200,0000,
	0000,0200,0200,0000,0200,0000,0000,0200,
	0200,0000,0000,0200,0000,0200,0200,0000,
	0200,0000,0000,0200,0000,0200,0200,0000,
	0000,0200,0200,0000,0200,0000,0000,0200,
};

char	profiles[NPROFILES+1][NX29_PARMS] = {
/*    1  2    3   4  5  6   7  8  9 10 11 12/13 14 15   16   17   18 */
    { 1, 1, 126,  0, 0, 1, 21, 0, 2, 0, 0, 1, 4, 0, 1,   8,  21,  18 },
    { 1, 0, 126,  0, 1, 1,  2, 0, 0, 0, 0, 1, 0, 0, 0,   0,   0,   0 },
    { 1, 0,   2,  0, 0, 1, 21, 0, 2, 0, 0, 1, 4, 0, 1,   8,  21,  18 },
    { 0, 0,   0, 20, 0, 0,  2, 0, 0, 0, 0, 0, 0, 0, 0,   0,   0,   0 },
    { 1, 0,   2,  0, 0, 1, 21, 0, 2, 0, 0, 0, 0, 0, 0,   0,   0,   0 },
    { 1, 0,   2,  0, 0, 1,  2, 0, 2, 0, 1, 0, 0, 0, 0,   0,   0,   0 },
    { 0, 0,   0,  4, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, 0,   0,   0,   0 }
};

/*
 * Initialize user's profile
 */

InitProfile(profile)
{
	register int i;

	for(i = 0; i < 128; i++)
		CurrentX29Parms[i] = INVALID;
	for(i = 0; i < NetInfo.n_nparms; i++)
		CurrentX29Parms[pnums[i]] = profiles[profile][i];
	SetSpecialChars();
	CurrentProfile = profile;
}

SetSpecialChars()
{
	register int c, code;

	for(c = 0; c < 128; c++)
		chartab[c] &= 0200;

	code = CurrentX29Parms[X29_FORWARDING_SIGNAL_CODE];
	if (code & 01) {	/* A-Z, a-z, 0-9 */
		for (c = 'A'; c <= 'Z'; c++)
			chartab[c] |= C_FORWARD;
		for (c = 'a'; c <= 'z'; c++)
			chartab[c] |= C_FORWARD;
		for (c = '0'; c <= '9'; c++)
			chartab[c] |= C_FORWARD;
	}
	if (code & 02)		/* CR */
		chartab['\r'] |= C_FORWARD;
	if (code & 04) {	/* ESC, BEL, ENQ, ACK */
		chartab[033] |= C_FORWARD;
		chartab[07] |= C_FORWARD;
		chartab[05] |= C_FORWARD;
		chartab[06] |= C_FORWARD;
	}
	if (code & 8) {		/* DEL, CAN, DC2 */
		chartab[0177] |= C_FORWARD;
		chartab[030] |= C_FORWARD;
		chartab[022] |= C_FORWARD;
	}
	if (code & 16) {	/* ETX, EOT */
		chartab[03] |= C_FORWARD;
		chartab[04] |= C_FORWARD;
	}
	if (code & 32) {	/* HT, LF, VT, FF */
		chartab[011] |= C_FORWARD;
		chartab[012] |= C_FORWARD;
		chartab[013] |= C_FORWARD;
		chartab[014] |= C_FORWARD;
	}
	if (code & 64) {	/* control codes not in the above list */
		chartab[01] |= C_FORWARD;
		chartab[02] |= C_FORWARD;
		chartab[010] |= C_FORWARD;
		chartab[016] |= C_FORWARD;
		chartab[017] |= C_FORWARD;
		chartab[020] |= C_FORWARD;
		chartab[021] |= C_FORWARD;
		chartab[023] |= C_FORWARD;
		chartab[024] |= C_FORWARD;
		chartab[025] |= C_FORWARD;
		chartab[026] |= C_FORWARD;
		chartab[027] |= C_FORWARD;
		chartab[031] |= C_FORWARD;
		chartab[032] |= C_FORWARD;
		chartab[034] |= C_FORWARD;
		chartab[035] |= C_FORWARD;
		chartab[036] |= C_FORWARD;
		chartab[037] |= C_FORWARD;
	}

	if ((c = CurrentX29Parms[X29_ESCAPE_TO_CMD_CODE]) > 0)
		chartab[c==1 ? ('P' & 037) : c] |= C_ESCAPE;

	if (CurrentX29Parms[X29_EDITING]) {
		if ((c = CurrentX29Parms[X29_CHARACTER_DELETE]) > 0)
			chartab[c] |= C_ERASE;
		if ((c = CurrentX29Parms[X29_LINE_DELETE]) > 0)
			chartab[c] |= C_KILL;
		if ((c = CurrentX29Parms[X29_LINE_DISPLAY]) > 0)
			chartab[c] |= C_DISPLAY;
	}
}

X29ControlMessage (bp, len)
register struct x29packet *bp;
{

	ForwardPacket ();
	switch (bp->p_x29code) {
	case X29_SET_PARMS:
		if (SetNIM (bp, len))
			ReadNIM (bp, len);
		break;

	case X29_READ_PARMS:
		ReadNIM (bp, len);
		break;

	case X29_SET_AND_READ_PARMS:
		(void) SetNIM (bp, len);
		ReadNIM (bp, len);
		break;

	case X29_INVITATION_TO_CLEAR:
		ExitDataState ("remote directive");
		break;

	case X29_INDICATION_OF_BREAK:
		break;

	case X29_ERROR:
		log ("x.29 error indication from remote host");
		LogPacket ((char *)bp, len);
		break;
		
	default:
		X29Error ("Unknown X.29 request", bp, len, 1);
	}
}

/*
 * Bad news - we received an invalid or an
 * unknown packet.  Send an error indication
 * to the remote host and dump the contents
 * of the packet in the log file.
 */

X29Error (why, bp, len, code)
struct x29packet *bp;
char *why;
{
	register struct x29packet *pp;
	char errmsg[4];

	log ("x.29 error: %s: packet contents:", why);
	LogPacket ((char *)bp, len);
	pp = (struct x29packet *)errmsg;
	pp->p_x29flag = Q_BIT;
	pp->p_x29code = X29_ERROR;
	pp->p_x29errno = code;
	pp->p_x29mtype = bp->p_x29code;
	ToNet (pp, sizeof (errmsg));
}

SetX29Parm (pnum, value)
u_char pnum, value;
{
	register int special = 0;

	if (pnum >= 128 || CurrentX29Parms[pnum] < 0)
		return (1);
	switch (pnum) {
	case X29_ESCAPE_TO_CMD_CODE:
		if (value > 1 && value != 033 && (value < 32 || value > 126))
			return (1);
		special++;
		break;

	case X29_ECHO_CODE:
	case X29_DISCARD_OUTPUT_CODE:
	case X29_XON_XOFF_CODE:
		if (value > 1)
			return (1);
		break;

	case X29_AUX_DEV_CONTROL_CODE:
		if (value > 1)
			return (1);
		OutputBlocked = 0;
		break;

	case X29_RECEIVE_NET_MSGS_CODE:
		if (value > 1 && value != 5)
			return (1);
		break;

	case X29_FORWARDING_SIGNAL_CODE:
		if (value > 127)
			return (1);
		special++;
		break;

	case X29_IDLE_TIMER_CODE:
		break;

	case X29_BREAK_PROCEDURE_CODE:
		if (value != 0 && value != 1 && value != 2 && value != 4 &&
		    value != 5 && value != 8 && value != 16 && value != 21)
			return (1);
		break;

	case X29_PADDING_CODE:
		if (value > 7)
			return (1);
		break;

	case X29_LINE_FOLDING_CODE:
		break;

	case X29_TRANSMISSION_SPEED_CODE:
	/*
	 * Trying to change the line speed is illegal.
	 * This seems to be a defect in many PADs.
	 * Rather than log an error and send a complaint back
	 * to the remote PAD, we will quietly ignore the problem.
	 */
/*		return (1);	/* read-only variable */
		return (0);

	/* Parameters specific to 1980 CCITT recommendation */

	case X29_LF_AFTER_CR:
		if (value > 1 && (value < 4 || value > 7))
			return (1);
		break;

	case X29_PADDING_AFTER_LF:
		if (value > 7)
			return (1);
		break;

	case X29_EDITING:
		if (value > 1)
			return (1);
		special++;
		break;

	case X29_CHARACTER_DELETE:
	case X29_LINE_DELETE:
	case X29_LINE_DISPLAY:
		if (value > 127)
			return (1);
		special++;
		break;

	default:
		return (1);
	}
	CurrentX29Parms[pnum] = value;
	if (special)
		SetSpecialChars ();
	return (0);
}

SetNIM (bp, len)
register struct x29packet *bp;
{
	register int nparms;

	nparms = (struct x29param *)((char *)bp + len) - bp->p_x29param;
	if ((char *)&bp->p_x29param[nparms] != (char *)bp + len) {
		X29Error ("incomplete set parameter request", bp, len, 3);
		return (0);
	}

	/*
	 * if no parameters then reset to subscription profile
	 */

	if (nparms == 0) {
		register int i;

		nparms = NetInfo.n_nparms;
		for (i = 0; i < nparms; i++)
			(void) SetX29Parm (pnums[i], profiles[CurrentProfile][i]);
			return (0);
	} else {
		register struct x29param *xp;
		register int errors = 0;

		for (xp = bp->p_x29param; xp < &bp->p_x29param[nparms]; xp++) {

			/*
			 * Stop processing parameters if we find a national
			 * parameter marker.  We don't support any network
			 * specific private parameters.  Rather than logging
			 * an error and bouncing back a complaint to the
			 * remote PAD, we will just give up.
			 */

			if (xp->x29_pnum == X29_NATIONAL_PARAMETER_MARKER)
				break;

			/*
			 * if attempt to set illegal parameter or legal
			 * parameter to illegal value then mark parameter
			 * as invalid.
			 */

			if (SetX29Parm(xp->x29_pnum, xp->x29_value)) {
				if (errors == 0) {
					log ("x.29 error: invalid parameters in set parameter request:");
					LogPacket ((char *)bp, len);
				}
				xp->x29_pnum |= 0200;
				errors++;
			}
		}
		return (errors);
	}
}

ReadNIM (bp, len)
register struct x29packet *bp;
{
	register int nparms;

	nparms = (struct x29param *)((char *)bp + len) - bp->p_x29param;
	if ((char *)&bp->p_x29param[nparms] != (char *)bp + len) {
		X29Error ("incomplete read parameter request", bp, len, 3);
		return;
	}

	/*
	 * if no parameters specified then send
	 * all parameters.
	 */

	if (nparms == 0) {
		register int i;
		register struct x29packet *pp;
		char reply[128];

		pp = (struct x29packet *)reply;
		pp->p_x29flag = Q_BIT;
		pp->p_x29code = X29_PARAMETER_INDICATION;

		nparms = NetInfo.n_nparms;
		for (i = 0; i < nparms; i++) {
			pp->p_x29param[i].x29_pnum = pnums[i];
			pp->p_x29param[i].x29_value = CurrentX29Parms[pnums[i]];
		}
		ToNet (pp, (char *)&pp->p_x29param[nparms] - (char *)pp);
	} else {
		register int pnum, errors = 0;
		register struct x29param *xp;

		/*
		 * Scribble over the original Read Parameter request
		 * replacing the message code and filling in the values
		 * for the requested parameters.
		 */

		bp->p_x29code = X29_PARAMETER_INDICATION;
		for (xp = bp->p_x29param; xp < &bp->p_x29param[nparms]; xp++) {
			pnum = xp->x29_pnum;

			/*
			 * Parameters private to specific networks generate
			 * lots of errors because we don't support any of them.
			 * We'll set the errors flag to avoid filling our
			 * log file with messages related to this limitation.
			 */

			if (pnum == X29_NATIONAL_PARAMETER_MARKER)
				errors++;
			/*
			 * If the requested parameter is invalid and has
			 * not already been marked as invalid (by SetNIM()
			 * in a set and read parameter request) then mark
			 * the parameter as invalid and set its value to 0.
			 */

			if ((pnum & 0200) == 0 && CurrentX29Parms[pnum] < 0) {
				if (errors == 0) {
					log ("x.29 error: invalid parameters in read parameter request:");
					LogPacket ((char *)bp, len);
				}
				pnum |= 0200;
				errors++;
			}
			if (pnum & 0200)
				xp->x29_value = 0;
			else
				xp->x29_value = CurrentX29Parms[pnum];
		}
		ToNet (bp, len);
	}
}

Break (code)
{
	register struct x29packet *bp;
	char brkmsg[4];

	bp = (struct x29packet *)brkmsg;
	switch (code) {
	case 1:		/* interrupt */
		SendX25Interrupt ();
		ForwardPacket ();
		return;

	case 2:		/* reset */
		ResetBufs ();
		return;

	case 4:		/* send indication of break */
		ForwardPacket();
		bp->p_x29flag = Q_BIT;
		bp->p_x29code = X29_INDICATION_OF_BREAK;
		ToNet (bp, 2);
		return;

	case 5:		/* send interrupt and indication of break */
		SendX25Interrupt ();
		ForwardPacket();
		bp->p_x29flag = Q_BIT;
		bp->p_x29code = X29_INDICATION_OF_BREAK;
		ToNet (bp, 2);
		return;

	case 8:		/* enter command state */
		EnterCommandState ();
		return;

	case 16:	/* discard output */
		ForwardPacket();
		bp->p_x29flag = Q_BIT;
		bp->p_x29code = X29_PARAMETER_INDICATION;
		bp->p_x29param[0].x29_pnum = X29_DISCARD_OUTPUT_CODE;
		bp->p_x29param[0].x29_value = 1;
		ToNet (bp, 4);
		CurrentX29Parms[X29_DISCARD_OUTPUT_CODE] = 1;
		return;

	case 21:	/* INT + BR indication + discard output */
		SendX25Interrupt ();
		ForwardPacket ();
		bp->p_x29flag = Q_BIT;
		bp->p_x29code = X29_INDICATION_OF_BREAK;
		bp->p_x29param[0].x29_pnum = X29_DISCARD_OUTPUT_CODE;
		bp->p_x29param[0].x29_value = 1;
		ToNet (bp, 4);
		CurrentX29Parms[X29_DISCARD_OUTPUT_CODE] = 1;
		return;
	}
}

/*
 * Change data pointed to by 'start' to be
 * even parity.  Note that with the 1980 standard
 * there is no way to force an 8 bit data path,
 * but by convention, we do not set parity iff
 * data forwarding occurs only on timer expiry.
 */

AddParity(start, len)
register char *start;
{
	register char *end;

	if(CurrentX29Parms[X29_FORWARDING_SIGNAL_CODE] == 0)
		return;
	end = start + len;
	while(start < end) {
		*start &= 0177;
		*start |= chartab[*start] & 0200;
		start++;
	}
}