4.4BSD/usr/src/contrib/usr.x25/nimd/x29.c
/*
* 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++;
}
}