/* dse-c.c - DSE wrapper for pepsy */

#ifndef	lint
static char *rcsid = "$Header: /var/lib/cvsd/repos/CSRG/43BSDReno/contrib/isode-beta/acsap/dse-c.c,v 1.1.1.1 2018/04/24 16:12:56 root Exp $";
#endif

/* 
 * $Header: /var/lib/cvsd/repos/CSRG/43BSDReno/contrib/isode-beta/acsap/dse-c.c,v 1.1.1.1 2018/04/24 16:12:56 root Exp $
 *
 *
 * $Log: dse-c.c,v $
 * Revision 1.1.1.1  2018/04/24 16:12:56  root
 * BSD 4.3reno
 *
 * Revision 7.2  90/07/27  08:41:47  mrose
 * update
 * 
 * Revision 7.1  90/07/09  14:31:01  mrose
 * sync
 * 
 * Revision 7.0  90/07/01  19:51:16  mrose
 * *** empty log message ***
 * 
 */

/*
 *				  NOTICE
 *
 *    Acquisition, use, and distribution of this module and related
 *    materials are subject to the restrictions of a license agreement.
 *    Consult the Preface in the User's Manual for the full terms of
 *    this agreement.
 *
 */

/* LINTLIBRARY */


#include <stdio.h>
#include "psap.h"
#include "isoaddrs.h"
#include "tailor.h"
#include "DSE-types.h"


#define advise	PY_advise


extern struct type_DSE_PSAPaddr *psap2dse ();

/*  */

int	build_DSE_PSAPaddr (pe, explicit, len, buffer, parm)
PE     *pe;
int     explicit;
int     len;
char   *buffer;
char	*parm;
{
    int	    result;
    register struct PSAPaddr *pa = (struct PSAPaddr *) parm;
    struct type_DSE_PSAPaddr *dse;

    if ((dse = psap2dse (pa)) == NULL)
	return NOTOK;

    result = encode_DSE_PSAPaddr (pe, explicit, len, buffer, (char *) dse);

    free_DSE_PSAPaddr (dse);

    return result;
}

/*  */

static struct type_DSE_PSAPaddr *psap2dse (pa)
register struct PSAPaddr *pa;
{
    register int    n;
    register struct type_DSE_PSAPaddr *dse;
    register struct SSAPaddr *sa = &pa -> pa_addr;
    register struct TSAPaddr *ta = &sa -> sa_addr;
    register struct NSAPaddr *na;
    register struct member_DSE_0  *nDSE,
				 **oDSE;

    if ((dse = (struct type_DSE_PSAPaddr *) calloc (1, sizeof *dse)) == NULL) {
	advise (NULLCP, "psap2dse: out of memory");
	return NULL;
    }

    if (pa -> pa_selectlen > 0)
	dse -> pSelector = str2qb (pa -> pa_selector, pa -> pa_selectlen, 1);
    
    if (sa -> sa_selectlen > 0)
	dse -> sSelector = str2qb (sa -> sa_selector, sa -> sa_selectlen, 1);
    
    if (ta -> ta_selectlen > 0)
	dse -> tSelector = str2qb (ta -> ta_selector, ta -> ta_selectlen, 1);

    oDSE = &dse -> nAddress;
    for (na = ta -> ta_addrs, n = ta -> ta_naddr; n > 0; na++, n--) {
	register struct NSAPaddr *ca;

	if ((nDSE = (struct member_DSE_0 *) calloc (1, sizeof *nDSE))
	        == NULL) {
	    advise (NULLCP, "psap2dse: out of memory");
losing: ;
	    free_DSE_PSAPaddr (dse);
	    return NULL;
	}
	*oDSE = nDSE;
	oDSE = &nDSE -> next;

	if ((ca = na2norm (na)) == NULLNA) {
	    advise (NULLCP, "unable to normalize address");
	    goto losing;
	}

	nDSE -> member_DSE_1 = str2qb (ca -> na_address, ca -> na_addrlen, 1);
    }
    
    return dse;
}

/*  */

int	parse_DSE_PSAPaddr (pe, explicit, len, buffer, parm)
register PE pe;
int	explicit;
int    *len;
char  **buffer;
char   *parm;
{
    int	    result;
    register struct PSAPaddr *pa = (struct PSAPaddr *) parm;
    struct type_DSE_PSAPaddr *dse;

    if (decode_DSE_PSAPaddr (pe, explicit, len, buffer, &dse) == NOTOK)
	return NOTOK;

    result = dse2psap (dse, pa);
	
    free_DSE_PSAPaddr (dse);

    return result;
}

/*  */

static int  dse2psap (dse, pa)
register struct type_DSE_PSAPaddr *dse;
register struct PSAPaddr *pa;
{
    register struct SSAPaddr *sa = &pa -> pa_addr;
    register struct TSAPaddr *ta = &sa -> sa_addr;
    register struct member_DSE_0 *nDSE;

    bzero ((char *) pa, sizeof *pa);

    pa -> pa_selectlen = gstring (pa -> pa_selector,
				  sizeof pa -> pa_selector,
				  dse -> pSelector, "psap selector");

    sa -> sa_selectlen = gstring (sa -> sa_selector, sizeof sa -> sa_selector,
				  dse -> sSelector, "ssap selector");

    ta -> ta_selectlen = gstring (ta -> ta_selector, sizeof ta -> ta_selector,
				  dse -> tSelector, "tsap selector");

    for (nDSE  = dse -> nAddress; nDSE; nDSE = nDSE -> next) {
	char   *p;

	if (ta -> ta_naddr >= NTADDR) {
	    advise (NULLCP, "too many network addresses");
	    return NOTOK;
	}

	p = qb2str (nDSE->member_DSE_1);
	if (str2nsap (p, nDSE -> member_DSE_1 -> qb_len,
		  &ta -> ta_addrs[ta -> ta_naddr++]) == NOTOK)
	    return NOTOK;
	free (p);
    }

    return OK;
}

/*  */

static int  gstring (buf, buflen, qb, w)
char   *buf;
int	buflen;
struct qbuf *qb;
char	*w;
{
    char   *p;

    if (qb == NULL || qb -> qb_len <= 0)
	return 0;
    
    if (qb -> qb_len > buflen) {
	advise (NULLCP, "%s too long", w);
	return 0;
    }

    p = qb2str (qb);
    bcopy (p, buf, qb -> qb_len);
    free (p);

    return qb -> qb_len;
}

/*  */

static int  str2nsap (p, len, na)
char	*p;
int	len;
struct NSAPaddr *na;
{
    na -> na_stack = NA_NSAP;

    if ((len == 8) && ((p[0] == 0x36) || (p[0] == 0x37))) {
	int	xlen;			/* SEK - X121 form */
	register char   *cp,
			*cp2,
		        *dp;
	char	nsap[14];

	dp = nsap;
	for (cp2 = (cp = p + 1) + 7; cp < cp2; cp++) {
	    register int     j;

	    if ((j = ((*cp & 0xf0) >> 4)) > 9)
		goto concrete;
	    *dp++ = j + '0';

	    if ((j = (*cp & 0x0f)) > 9) {
		if (j != 0x0f)
		    goto concrete;
	    }
	    else
		*dp++ = j + '0';
	}

	for (cp = nsap, xlen = 14; *cp == '0'; cp++, xlen--)
	    continue;
	na -> na_dtelen = xlen;
	for (cp2 = na -> na_dte; xlen-- > 0; )
		*cp2++ = *cp++;
	*cp2 = NULL;
#ifdef	BRIDGE_X25
	na -> na_stack = bridgediscrim (na) ? NA_BRG : NA_X25;
#else
	na -> na_stack = NA_X25;
#endif
	na -> na_community = SUBNET_INT_X25;
    }
    else {
	register struct ts_interim *ts,
				   *tp;

	tp = NULL;
	for (ts = ts_interim; ts -> ts_name; ts++)
	    if (len > ts -> ts_length
		    && (tp == NULL || ts -> ts_length > tp -> ts_length)
		    && bcmp (p, ts -> ts_prefix, ts -> ts_length) == 0)
		tp = ts;
	if (tp) {
	    int	    i,
		    ilen,
		    rlen;
	    register char   *cp,
			    *dp,
			    *ep;
	    char    nsap[NASIZE * 2 + 1];

	    dp = nsap;
	    for (cp = p + tp -> ts_length, ep = p + len;
		     cp < ep;
		     cp++) {
		register int     j;

		if ((j = ((*cp & 0xf0) >> 4)) > 9) {
concrete: ;
		    LLOG (addr_log, LLOG_EXCEPTIONS,
			  ("invalid concrete encoding"));
		    goto realNS;
		}
		*dp++ = j + '0';

		if ((j = (*cp & 0x0f)) > 9) {
		    if (j != 0x0f)
			goto concrete;
		}
		else
		    *dp++ = j + '0';
	    }
	    *dp = NULL;

	    cp = nsap;
	    na -> na_community = tp -> ts_subnet;
	    switch (na -> na_stack = tp -> ts_syntax) {
		case NA_NSAP:
		    goto unrealNS;

		case NA_X25:
		    if (strlen (cp) < 1) {
			LLOG (addr_log, LLOG_EXCEPTIONS,
			      ("missing DTE+CUDF indicator: %s", nsap));
			goto realNS;
		    }
		    (void) sscanf (cp, "%1d", &i);
		    cp += 1;
		    switch (i) {
		        case 0:	/* DTE only */
			    break;

			case 1:	/* DTE+PID */
			case 2:	/* DTE+CUDF */
			    if (strlen (cp) < 1) {
				LLOG (addr_log, LLOG_EXCEPTIONS,
				      ("missing DTE+CUDF indicator: %s",
				       nsap));
				goto realNS;
			    }
			    (void) sscanf (cp, "%1d", &ilen);
			    cp += 1;
			    rlen = ilen * 3;
			    if (strlen (cp) < rlen) {
				LLOG (addr_log, LLOG_EXCEPTIONS,
				      ("bad DTE+CUDF length: %s", nsap));
				goto realNS;
			    }
			    if (i == 1) {
				if (ilen > NPSIZE) {
				    LLOG (addr_log, LLOG_EXCEPTIONS,
					  ("PID too long: %s", nsap));
				    goto realNS;
				}
				dp = na -> na_pid;
				na -> na_pidlen = ilen;
			    }
			    else {
				if (ilen > CUDFSIZE) {
				    LLOG (addr_log, LLOG_EXCEPTIONS,
					  ("CUDF too long: %s", nsap));
				    goto realNS;
				}
				dp = na -> na_cudf;
				na -> na_cudflen = ilen;
			    }
			    for (; rlen > 0; rlen -= 3) {
				(void) sscanf (cp, "%3d", &i);
				cp += 3;

				if (i > 255) {
				    LLOG (addr_log, LLOG_EXCEPTIONS,
					  ("invalid PID/CUDF: %s", nsap));
				    goto realNS;
				}
				*dp++ = i & 0xff;
			    }
			    break;

			default:
			    LLOG (addr_log, LLOG_EXCEPTIONS,
				  ("invalid DTE+CUDF indicator: %s", nsap));
			    goto realNS;
			}
		    (void) strcpy (na -> na_dte, cp);
		    na -> na_dtelen = strlen (na -> na_dte);

#ifdef	BRIDGE_X25
		    if (bridgediscrim (na))
			na -> na_stack = NA_BRG;
#endif
		    break;

		case NA_TCP:
		    if (strlen (cp) < 12) {
			LLOG (addr_log, LLOG_EXCEPTIONS,
			      ("missing IP address: %s", nsap));
			goto realNS;
		    }
		    {
			int	    q[4];

			(void) sscanf (cp, "%3d%3d%3d%3d", q, q + 1, q + 2,
				       q + 3);
			(void) sprintf (na -> na_domain,
					"%d.%d.%d.%d", q[0], q[1], q[2], q[3]);
		    }
		    cp += 12;

		    if (*cp) {
			if (strlen (cp) < 5) {
			    LLOG (addr_log, LLOG_EXCEPTIONS,
				  ("missing port: %s", nsap));
			    goto realNS;
			}
			(void) sscanf (cp, "%5d", &i);
			cp += 5;
			na -> na_port = htons ((u_short) i);

			if (*cp) {
			    if (strlen (cp) < 5) {
				LLOG (addr_log, LLOG_EXCEPTIONS,
				      ("missing tset: %s", nsap));
				goto realNS;
			    }
			    (void) sscanf (cp, "%5d", &i);
			    cp += 5;
			    na -> na_tset = (u_short) i;

			    if (*cp)
				LLOG (addr_log, LLOG_EXCEPTIONS,
				      ("extra TCP information: %s", nsap));
			}
		    }
		    break;

		default:
		    LLOG (addr_log, LLOG_NOTICE,
			  ("unknown syntax %d for DSP: %s", ts -> ts_syntax,
			   nsap));
		    goto realNS;
		}
	}
	else {
realNS: ;
	    na -> na_stack = NA_NSAP;
	    na -> na_community = SUBNET_REALNS;
unrealNS: ;
	    if (len > sizeof na -> na_address) {
		advise (NULLCP, "NSAP address too long");
		return NOTOK;
	    }
	    bcopy (p, na -> na_address, na -> na_addrlen = len);
	}
    }

    return OK;
}
