[comp.protocols.iso.dev-environ] ISODE and VAX FTAM

jh@tut.fi (Hein{nen Juha) (06/19/89)

In article <8906171104.AA24104@ucbvax.Berkeley.EDU> barnes@scr.slb.COM writes:

   The main questions I have at this stage are (i) have they been made
   to interwork? and if so, (ii) are there any particular table
   entries to watch out for? 

We also tried this and found VAX FTAM failing. Instead of fixing VAX
FTAM, they sent us a new psap2/psaprovider.c file (included below)
that circumvents the problem at the ISODE end.  (I don't know what
side effects the code has to other FTAM connections.)  After applying
the "fix", we got the FTAMs interworking atleast when the connection
is initiated from the ISODE end.

-- Juha Heinanen
----------------------------------------------------------------------
#define DEBUG
/* psaprovider.c - implement the presentation protocol (dec version) */
 
#ifndef	lint
static char *rcsid = "$Header: /f/osi/psap2/RCS/psaprovider.c,v 6.0 89/03/18 23:40:08 mrose Rel $";
#endif
 
/* 
 * $Header: /f/osi/psap2/RCS/psaprovider.c,v 6.0 89/03/18 23:40:08 mrose Rel $
 *
 *
 * $Log:	psaprovider.c,v $
 * Revision 6.0  89/03/18  23:40:08  mrose
 * Release 5.0
 * 
 */
 
/*
 *				  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 <signal.h>
#include "PS-types.h"
#include "ppkt.h"
#include "tailor.h"
 
/*    DATA */
 
static int  once_only = 0;
static struct psapblk psapque;
static struct psapblk *PHead = &psapque;
 
 
struct pair preq_pairs[] = {
    PR_MANAGEMENT, bit_PS_Presentation__requirements_context__management,
    PR_RESTORATION, bit_PS_Presentation__requirements_restoration,
    0, 0
};
 
 
struct pair sreq_pairs[] = {
    SR_HALFDUPLEX, bit_PS_User__session__requirements_half__duplex,
    SR_DUPLEX, bit_PS_User__session__requirements_duplex,
    SR_EXPEDITED, bit_PS_User__session__requirements_expedited__data,
    SR_MINORSYNC, bit_PS_User__session__requirements_minor__synchronize,
    SR_MAJORSYNC, bit_PS_User__session__requirements_major__synchronize,
    SR_RESYNC, bit_PS_User__session__requirements_resynchronize,
    SR_ACTIVITY, bit_PS_User__session__requirements_activity__management,
    SR_NEGOTIATED, bit_PS_User__session__requirements_negotiated__release,
    SR_CAPABILITY, bit_PS_User__session__requirements_capability__data,
    SR_EXCEPTIONS, bit_PS_User__session__requirements_exceptions,
    SR_TYPEDATA, bit_PS_User__session__requirements_typed__data,
    0, 0
};
 
/*  */
 
#define	doABORT		ss2psabort
 
 
int	DATAser (), TOKENser (), SYNCser (), ACTIVITYser (), REPORTser (),
	FINISHser (), ABORTser ();
 
 
/*    P-[*-]DATA.REQUEST */
 
int	PDataRequest (sd, data, ndata, pi)
int	sd;
PE     *data;
int	ndata;
struct PSAPindication *pi;
{
    return PDataRequestAux (sd, data, ndata, pi, "user", SDataRequest,
			    "SDataRequest", "P-DATA user-data", PPDU_TD);
}
 
/*  */
 
int	PDataRequestAux (sd, data, ndata, pi, dtype, sfunc, stype, text, ppdu)
int	sd;
PE     *data;
int	ndata;
struct PSAPindication *pi;
char   *dtype,
       *stype,
       *text;
IFP	sfunc;
int	ppdu;
{
    SBV	    smask;
    int     i,
	    len,
	    result;
    char   *base,
	   *realbase;
    register struct psapblk *pb;
    struct SSAPindication   sis;
    register struct SSAPabort  *sa = &sis.si_abort;
    register PE	   *d,
		    p;
 
    missingP (data);
    toomuchP (data, ndata, NPDATA, dtype);
    if (ndata <= 0)
	return psaplose (pi, PC_PARAMETER, NULLCP,
		    "illegal number of PDVs (%d)", ndata);
    missingP (pi);
    missingP (sfunc);
    missingP (stype);
    missingP (text);
 
    smask = sigioblock ();
 
    psapPsig (pb, sd);
 
    if (ppdu == PPDU_TE) {
	for (d = data, i = 0; i < ndata; i++)
	    if ((p = *d++) && p -> pe_context != PE_DFLT_CTX) {
		(void) sigiomask (smask);
		return psaplose (pi, PC_OPERATION, NULLCP,
			"defined context not permited with expedited service");
	    }
    }
	
    if (ppdu == PPDU_TTD && !(pb -> pb_urequirements & SR_TYPEDATA)) {
	(void) sigiomask (smask);
	return psaplose (pi, PC_OPERATION, NULLCP,
			 "typed data service unavailable");
    }
 
    if ((result = info2ssdu (pb, pi, data, ndata, &realbase, &base, &len, text,
			    ppdu)) != OK)
	goto out2;
 
    if ((result = (*sfunc) (sd, base, len, &sis)) == NOTOK)
	if (SC_FATAL (sa -> sa_reason))
	    (void) ss2pslose (pb, pi, stype, sa);
	else {
	    (void) ss2pslose (NULLPB, pi, stype, sa);
	    goto out1;
	}
 
out2: ;
    if (result == NOTOK)
	freepblk (pb);
    else
	if (result == DONE)
	    result = NOTOK;
out1: ;
    if (realbase)
	free (realbase);
    else
	if (base)
	    free (base);
 
    (void) sigiomask (smask);
 
    return result;
}
 
/*    P-READ.REQUEST (pseudo) */
 
int	PReadRequest (sd, px, secs, pi)
int	sd;
struct PSAPdata *px;
int	secs;
struct PSAPindication *pi;
{
    SBV	    smask;
    int     result;
    register struct psapblk *pb;
 
    missingP (px);
    missingP (pi);
 
    smask = sigioblock ();
 
    psapPsig (pb, sd);
 
    result = PReadRequestAux (pb, px, secs, pi);
 
    (void) sigiomask (smask);
 
    return result;
}
 
/*  */
 
static int  PReadRequestAux (pb, px, secs, pi)
register struct psapblk *pb;
struct PSAPdata *px;
int	secs;
register struct PSAPindication *pi;
{
    int	    result;
    struct SSAPdata sxs;
    register struct SSAPdata   *sx = &sxs;
    struct SSAPindication   sis;
    register struct SSAPindication *si = &sis;
 
    bzero ((char *) px, sizeof *px);
    bzero ((char *) pi, sizeof *pi);
 
    for (;;) {
	switch (result = SReadRequest (pb -> pb_fd, sx, secs, si)) {
	    case NOTOK:
		return doABORT (pb, &si -> si_abort, pi);
 
	    case OK:
		return doDATA (pb, sx, px, pi);
 
	    case DONE:
		switch (si -> si_type) {
		    case SI_TOKEN:
			return doTOKEN (pb, &si -> si_token, pi);
 
		    case SI_SYNC:
			return doSYNC (pb, &si -> si_sync, pi);
			
		    case SI_ACTIVITY:
			return doACTIVITY (pb, &si -> si_activity, pi);
 
		    case SI_REPORT:
			return doREPORT (pb, &si -> si_report, pi);
 
		    case SI_FINISH:
			return doFINISH (pb, &si -> si_finish, pi);
 
		    default:
			(void) ppktlose (pb, pi, PC_PROTOCOL, PPDU_NONE,
				NULLCP,
				"unknown indication (0x%x) from session",
				si -> si_type);
			break;
		}
		break;
		
	    default:
		(void) ppktlose (pb, pi, PC_PROTOCOL, PPDU_NONE, NULLCP,
			"unexpected return from SReadRequest=%d", result);
		break;
	}
	break;
    }
 
    freepblk (pb);
    return NOTOK;
}
 
/*  */
 
static int  doDATA (pb, sx, px, pi)
register struct psapblk *pb;
register struct SSAPdata *sx;
register struct PSAPdata  *px;
struct PSAPindication *pi;
{
    int     ppdu,
            result;
    char   *text;
 
    switch (px -> px_type = sx -> sx_type) {
	case SX_NORMAL: 
	    ppdu = PPDU_TD;
	    text = "P-DATA user-data";
	    break;
 
	case SX_EXPEDITED: 
	    ppdu = PPDU_TE;
	    text = "P-EXPEDITED-DATA user-data";
	    break;
 
	case SX_CAPDIND: 
	    ppdu = PPDU_TC;
	    goto capd;
	case SX_CAPDCNF: 
	    ppdu = PPDU_TCC;
capd: ;
	    text = "P-CAPABILITY-DATA user-data";
	    break;
 
	case SX_TYPED: 
	    ppdu = PPDU_TTD;
	    text = "P-TYPED-DATA user-data";
	    break;
 
	default: 
	    result = ppktlose (pb, pi, PC_PROTOCOL, PPDU_NONE, NULLCP,
		    "unknown data indication type=0x%x, %d bytes",
		    sx -> sx_type, sx -> sx_cc);
	    freepblk (pb);
	    goto out;
    }
 
    result = qbuf2info (pb, pi, &sx -> sx_qbuf, sx -> sx_cc,
	    px -> px_info, &px -> px_ninfo, text, ppdu);
 
out: ;
    if (result == NOTOK)
	SXFREE (sx);
 
    return result;
}
 
/*  */
 
static int  doTOKEN (pb, st, pi)
register struct psapblk *pb;
register struct SSAPtoken *st;
struct PSAPindication *pi;
{
    int	    result;
    register struct PSAPtoken  *pt = &pi -> pi_token;
 
    pi -> pi_type = PI_TOKEN;
 
    pt -> pt_type = st -> st_type;
    pt -> pt_tokens = st -> st_tokens;
    pt -> pt_owned = pb -> pb_owned = st -> st_owned;
 
    result = ssdu2info (pb, pi, st -> st_data, st -> st_cc, pt -> pt_info,
		&pt -> pt_ninfo, "P-PLEASE-TOKEN user-data", PPDU_NONE);
 
    STFREE (st);
 
    return (result != NOTOK ? DONE : NOTOK);
}
 
/*  */
 
static int  doSYNC (pb, sn, pi)
register struct psapblk *pb;
register struct SSAPsync *sn;
struct PSAPindication *pi;
{
    int	    result;
    register struct PSAPsync   *pn = &pi -> pi_sync;
 
    pi -> pi_type = PI_SYNC;
 
    pn -> pn_type = sn -> sn_type;
    pn -> pn_options = sn -> sn_options;
    pn -> pn_ssn = sn -> sn_ssn;
    pn -> pn_settings = sn -> sn_settings;
 
    result = ssdu2info (pb, pi, sn -> sn_data, sn -> sn_cc, pn -> pn_info,
			&pn -> pn_ninfo, sn -> sn_type <= SN_MAJORCNF
			    ? "P-MAJOR-SYNC user-data"
			    : sn -> sn_type <= SN_MINORCNF
			        ? "P-MINOR-SYNC user-data"
			        : "P-RESYNCHRONIZE user-data",
			sn -> sn_type == SN_RESETIND
			    ? PPDU_RS
			    : sn -> sn_type == SN_RESETCNF
			        ? PPDU_RSA
			        : PPDU_NONE);
 
    SNFREE (sn);
 
    return (result != NOTOK ? DONE : NOTOK);
}
 
/*  */
 
static int  doACTIVITY (pb, sv, pi)
register struct psapblk *pb;
register struct SSAPactivity *sv;
struct PSAPindication *pi;
{
    int	    result;
    register struct PSAPactivity   *pv = &pi -> pi_activity;
 
    pi -> pi_type = PI_ACTIVITY;
 
    pv -> pv_type = sv -> sv_type;
    pv -> pv_id = sv -> sv_id;			/* struct copy */
    pv -> pv_oid = sv -> sv_oid;		/* struct copy */
    pv -> pv_connect = sv -> sv_connect;	/* struct copy */
    pv -> pv_ssn = sv -> sv_ssn;
    pv -> pv_reason = sv -> sv_reason;
 
    result = ssdu2info (pb, pi, sv -> sv_data, sv -> sv_cc, pv -> pv_info,
		&pv -> pv_ninfo, sv -> sv_type <= SV_START
			? "P-ACTIVITY-START user-data"
			: sv -> sv_type <= SV_RESUME
			? "P-ACTIVITY-RESUME user-data"
			: "P-ACTIVITY-END user-data", PPDU_NONE);
 
    SVFREE (sv);
 
    return (result != NOTOK ? DONE : NOTOK);
}
 
/*  */
 
static int  doREPORT (pb, sp, pi)
register struct psapblk *pb;
register struct SSAPreport *sp;
struct PSAPindication *pi;
{
    int	    result;
    register struct PSAPreport *pp = &pi -> pi_report;
 
    pi -> pi_type = PI_REPORT;
 
    pp -> pp_peer = sp -> sp_peer;
    pp -> pp_reason = sp -> sp_reason;
 
    result = ssdu2info (pb, pi, sp -> sp_data, sp -> sp_cc, pp -> pp_info,
		&pp -> pp_ninfo, "P-U-EXCEPTION-REPORT user-data", PPDU_NONE);
 
    SPFREE (sp);
 
    return (result != NOTOK ? DONE : NOTOK);
}
 
/*  */
 
static int  doFINISH (pb, sf, pi)
register struct psapblk *pb;
register struct SSAPfinish *sf;
struct PSAPindication *pi;
{
    int	    result;
    register struct PSAPfinish *pf = &pi -> pi_finish;
 
    pi -> pi_type = PI_FINISH;
 
    result = ssdu2info (pb, pi, sf -> sf_data, sf -> sf_cc, pf -> pf_info,
		&pf -> pf_ninfo, "P-RELEASE user-data", PPDU_NONE);
 
    SFFREE (sf);
 
    if (result == NOTOK)
	return NOTOK;
 
    pb -> pb_flags |= PB_FINN;
 
    return DONE;
}
 
/*  */
 
int	ss2psabort (pb, sa, pi)
register struct psapblk *pb;
register struct SSAPabort *sa;
struct PSAPindication *pi;
{
    int	    result,
	    ppdu;
    register PE	    pe;
    register struct PSAPabort *pa = &pi -> pi_abort;
    struct type_PS_Abort__type *pdu;
    register struct element_PS_3 *aru;
    register struct type_PS_ARP__PPDU *arp;
    register struct type_PS_User__data *info;
 
    pdu = NULL, pe = NULLPE;
    if (!sa -> sa_peer) {
	if (sa -> sa_reason == SC_TIMER)
	    return psaplose (pi, PC_TIMER, NULLCP, NULLCP);
 
	(void) ss2pslose (pb, pi, NULLCP, sa);
	goto out;
    }
 
    if (sa -> sa_cc == 0) {
	(void) psaplose (pi, PC_ABORTED, NULLCP, NULLCP);
	goto out;
    }
 
    bzero ((char *) pi, sizeof *pi);
    pi -> pi_type = PI_ABORT;
 
    if ((pe = ssdu2pe (sa -> sa_info, sa -> sa_cc, NULLCP, &result))
	    == NULLPE) {
	(void) psaplose (pi, result == PS_ERR_NMEM ? PC_CONGEST : PC_PROTOCOL,
			 NULLCP, "%s", ps_error (result));
	goto out;
    }
 
    if (decode_PS_Abort__type (pe, 1, NULLIP, NULLVP, &pdu) == NOTOK) {
	(void) psaplose (pi, PC_UNRECOGNIZED, NULLCP, "%s", PY_pepy);
	goto out;
    }
 
    PLOG (psap2_log, print_PS_Abort__type, pe, "Abort-type", 1);
 
    switch (pdu -> offset) {
	default:
	    pa -> pa_peer = 1;
	    pa -> pa_reason = PC_ABORTED;
	    info = NULL, ppdu = PPDU_NONE;
	    break;
 
	case type_PS_Abort__type_normal__mode:
	    aru = pdu -> un.normal__mode;
	    pa -> pa_peer = 1;
	    pa -> pa_reason = PC_ABORTED;
	    info = aru -> user__data, ppdu = PPDU_ARU;
	    break;
 
	case type_PS_Abort__type_provider__abort:
	    if ((arp = pdu -> un.provider__abort) -> provider__reason) {
		if ((result = arp -> provider__reason -> parm) == 0)
		    result = PC_NOTSPECIFIED;
		else
		    result += PC_ABORT_BASE;
	    }
	    else
		result = PC_NOTSPECIFIED;
 
	    (void) psaplose (pi, result, NULLCP, NULLCP);
	    info = NULL, ppdu = PPDU_ARP;
	    break;
    }
 
    (void) ppdu2info (pb, pi, info, pa -> pa_info, &pa -> pa_ninfo, ppdu);
 
out: ;
    SAFREE (sa);
    if (pe)
	pe_free (pe);
    if (pdu)
	free_PS_Abort__type (pdu);
    pb -> pb_fd = NOTOK;
    freepblk (pb);
 
    return NOTOK;
}
 
/*    define vectors for INDICATION events */
 
#define	e(i)	(data ? (i) : NULLIFP)
 
 
int	PSetIndications (sd, data, tokens, sync, activity, report, finish,
	abort, pi)
int	sd;
IFP	data,
	tokens,
	sync,
	activity,
	report,
	finish,
	abort;
struct PSAPindication *pi;
{
    SBV     smask;
    register struct psapblk *pb;
    struct SSAPindication   sis;
    register struct SSAPabort  *sa = &sis.si_abort;
 
    if (data || tokens || sync || activity || report || finish || abort) {
	missingP (data);
	missingP (tokens);
	missingP (sync);
	missingP (activity);
	missingP (report);
	missingP (finish);
	missingP (abort);
    }
 
    smask = sigioblock ();
 
    psapPsig (pb, sd);
 
    if (SSetIndications (pb -> pb_fd, e (DATAser), e (TOKENser),
		e (SYNCser), e (ACTIVITYser), e (REPORTser), e (FINISHser),
		e (ABORTser), &sis) == NOTOK)
	switch (sa -> sa_reason) {
	    case SC_WAITING: 
		(void) sigiomask (smask);
		return psaplose (pi, PC_WAITING, NULLCP, NULLCP);
 
	    default: 
		(void) ss2pslose (pb, pi, "SSetIndications", sa);
		freepblk (pb);
		(void) sigiomask (smask);
		return NOTOK;
	}
 
    if (pb -> pb_DataIndication = data)
	pb -> pb_flags |= PB_ASYN;
    else
	pb -> pb_flags &= ~PB_ASYN;
    pb -> pb_TokenIndication = tokens;
    pb -> pb_SyncIndication = sync;
    pb -> pb_ActivityIndication = activity;
    pb -> pb_ReportIndication = report;
    pb -> pb_ReleaseIndication = finish;
    pb -> pb_AbortIndication = abort;
 
    (void) sigiomask (smask);
 
    return OK;
}
 
#undef	e
 
/*    SSAP interface */
 
int	ss2pslose (pb, pi, event, sa)
register struct psapblk *pb;
register struct PSAPindication *pi;
char   *event;
register struct SSAPabort *sa;
{
    int     reason;
    char   *cp,
            buffer[BUFSIZ];
 
    if (event && SC_FATAL (sa -> sa_reason))
	SLOG (psap2_log, LLOG_EXCEPTIONS, NULLCP,
	      (sa -> sa_cc > 0 ? "%s: %s [%*.*s]": "%s: %s", event,
	       SErrString (sa -> sa_reason), sa -> sa_cc, sa -> sa_cc,
	       sa -> sa_data));
 
    cp = "";
    switch (sa -> sa_reason) {
	case SC_SSAPID: 
	case SC_SSUSER: 
	case SC_ADDRESS: 
	    reason = PC_ADDRESS;
	    break;
 
	case SC_REFUSED:
	    reason = PC_REFUSED;
	    break;
 
	case SC_CONGEST: 
	    reason = PC_CONGEST;
	    break;
 
	case SC_TRANSPORT:
	case SC_ABORT:
	    reason = PC_SESSION;
	    break;
 
	default: 
	    reason = PC_SESSION;
	    if (pb == NULLPB)
		switch (sa -> sa_reason) {
		    case SC_PARAMETER:
			reason = PC_PARAMETER;
			break;
 
		    case SC_OPERATION:
			reason = PC_OPERATION;
			break;
 
		    case SC_TIMER:
			reason = PC_TIMER;
			break;
 
		    case SC_WAITING:
			reason = PC_WAITING;
			break;
		}
	    (void) sprintf (cp = buffer, " (%s at session)",
			SErrString (sa -> sa_reason));
	    break;
    }
 
    if (pb) {
	if (sa -> sa_cc > 0)
	    return ppktlose (pb, pi, reason, PPDU_NONE, NULLCP, "%*.*s%s",
		    sa -> sa_cc, sa -> sa_cc, sa -> sa_data, cp);
	else
	    return ppktlose (pb, pi, reason, PPDU_NONE, NULLCP, "%s",
		    *cp ? cp + 1 : cp);
    }
    else {
	if (sa -> sa_cc > 0)
	    return psaplose (pi, reason, NULLCP, "%*.*s%s",
		    sa -> sa_cc, sa -> sa_cc, sa -> sa_data, cp);
	else
	    return psaplose (pi, reason, NULLCP, "%s",
		    *cp ? cp + 1 : cp);
    }
}
 
/*  */
 
static int  DATAser (sd, sx)
int     sd;
register struct SSAPdata   *sx;
{
    IFP	    abort;
    register struct psapblk *pb;
    struct PSAPindication   pis;
    register struct PSAPindication *pi = &pis;
    register struct PSAPdata   *px = &pi -> pi_data;
 
    if ((pb = findpblk (sd)) == NULL)
	return;
 
    bzero ((char *) px, sizeof *px);
    bzero ((char *) pi, sizeof *pi);
    abort = pb -> pb_AbortIndication;
 
    if (doDATA (pb, sx, px, pi) == NOTOK)
	(*abort) (sd, &pi -> pi_abort);
    else
	(*pb -> pb_DataIndication) (sd, px);
}
 
/*  */
 
static int  TOKENser (sd, st)
int     sd;
register struct SSAPtoken *st;
{
    IFP	    abort;
    register struct psapblk *pb;
    struct PSAPindication   pis;
    register struct PSAPindication *pi = &pis;
 
    if ((pb = findpblk (sd)) == NULL)
	return;
 
    bzero ((char *) pi, sizeof *pi);
    abort = pb -> pb_AbortIndication;
 
    if  (doTOKEN (pb, st, pi) == NOTOK)
	(*abort) (sd, &pi -> pi_abort);
    else
	(*pb -> pb_TokenIndication) (sd, &pi -> pi_token);
}
 
/*  */
 
static int  SYNCser (sd, sn)
int     sd;
register struct SSAPsync   *sn;
{
    IFP	    abort;
    register struct psapblk *pb;
    struct PSAPindication   pis;
    register struct PSAPindication *pi = &pis;
 
    if ((pb = findpblk (sd)) == NULL)
	return;
 
    bzero ((char *) pi, sizeof *pi);
    abort = pb -> pb_AbortIndication;
 
    if  (doSYNC (pb, sn, pi) == NOTOK)
	(*abort) (sd, &pi -> pi_abort);
    else
	(*pb -> pb_SyncIndication) (sd, &pi -> pi_sync);
}
 
/*  */
 
static int  ACTIVITYser (sd, sv)
int     sd;
register struct SSAPactivity   *sv;
{
    IFP	    abort;
    register struct psapblk *pb;
    struct PSAPindication   pis;
    register struct PSAPindication *pi = &pis;
 
    if ((pb = findpblk (sd)) == NULL)
	return;
 
    bzero ((char *) pi, sizeof *pi);
    abort = pb -> pb_AbortIndication;
 
    if  (doACTIVITY (pb, sv, pi) == NOTOK)
	(*abort) (sd, &pi -> pi_abort);
    else
	(*pb -> pb_ActivityIndication) (sd, &pi -> pi_activity);
}
 
/*  */
 
static int  REPORTser (sd, sp)
int     sd;
register struct SSAPreport   *sp;
{
    IFP	    abort;
    register struct psapblk *pb;
    struct PSAPindication   pis;
    register struct PSAPindication *pi = &pis;
 
    if ((pb = findpblk (sd)) == NULL)
	return;
 
    bzero ((char *) pi, sizeof *pi);
    abort = pb -> pb_AbortIndication;
 
    if  (doREPORT (pb, sp, pi) == NOTOK)
	(*abort) (sd, &pi -> pi_abort);
    else
	(*pb -> pb_ReportIndication) (sd, &pi -> pi_report);
}
 
/*  */
 
static int  FINISHser (sd, sf)
int     sd;
register struct SSAPfinish   *sf;
{
    IFP	    abort;
    register struct psapblk *pb;
    struct PSAPindication   pis;
    register struct PSAPindication *pi = &pis;
 
    if ((pb = findpblk (sd)) == NULL)
	return;
 
    bzero ((char *) pi, sizeof *pi);
    abort = pb -> pb_AbortIndication;
 
    if  (doFINISH (pb, sf, pi) == NOTOK)
	(*abort) (sd, &pi -> pi_abort);
    else
	(*pb -> pb_ReleaseIndication) (sd, &pi -> pi_finish);
}
 
/*  */
 
static int  ABORTser (sd, sa)
int     sd;
register struct SSAPabort   *sa;
{
    IFP	    abort;
    register struct psapblk *pb;
    struct PSAPindication   pis;
    register struct PSAPindication *pi = &pis;
 
    if ((pb = findpblk (sd)) == NULL)
	return;
 
    bzero ((char *) pi, sizeof *pi);
    abort = pb -> pb_AbortIndication;
 
    (void) doABORT (pb, sa, pi);
    (*abort) (sd, &pi -> pi_abort);
}
 
/*    INTERNAL */
 
struct psapblk  *newpblk () {
    register struct psapblk *pb;
 
    pb = (struct psapblk   *) calloc (1, sizeof *pb);
    if (pb == NULL)
	return NULL;
 
    pb -> pb_fd = NOTOK;
 
    if (once_only == 0) {
	PHead -> pb_forw = PHead -> pb_back = PHead;
	once_only++;
    }
 
    insque (pb, PHead -> pb_back);
 
    return pb;
}
 
 
int	freepblk (pb)
register struct psapblk *pb;
{
    register int    i;
    register struct PSAPcontext *qp;
 
    if (pb == NULL)
	return;
 
    if (pb -> pb_fd != NOTOK) {
	struct SSAPindication   sis;
	
	(void) SUAbortRequest (pb -> pb_fd, NULLCP, 0, &sis);
    }
 
    if (pb -> pb_retry)
	free (pb -> pb_retry);
 
    for (qp = pb -> pb_contexts, i = pb -> pb_ncontext - 1;
	    i >= 0;
	    qp++, i--) {
	if (qp -> pc_asn)
	    oid_free (qp -> pc_asn);
	if (qp -> pc_atn)
	    oid_free (qp -> pc_atn);
    }
    if (pb -> pb_asn)
	oid_free (pb -> pb_asn);
    if (pb -> pb_atn)
	oid_free (pb -> pb_atn);
 
    if (pb -> pb_ber)
	oid_free (pb -> pb_ber);
 
    remque (pb);
 
    free ((char *) pb);
}
 
/*  */
 
struct psapblk   *findpblk (sd)
register int sd;
{
    register struct psapblk *pb;
 
    if (once_only == 0)
	return NULL;
 
    for (pb = PHead -> pb_forw; pb != PHead; pb = pb -> pb_forw)
	if (pb -> pb_fd == sd)
	    return pb;
 
    return NULL;
}
 
/*  */
 
struct type_PS_User__data *info2ppdu (pb, pi, data, ndata, ppdu)
register struct psapblk *pb;
struct PSAPindication *pi;
PE     *data;
int	ndata,
	ppdu;
{
    register int    i,
		    j;
    register PE	   *d,
		    pe;
    register struct qbuf *qb;
    register struct PSAPcontext *qp;
    OID	    atn;
    struct type_PS_User__data *pdu;
    register struct type_PS_Simply__encoded__data *simple;
    register struct type_PS_Fully__encoded__data **complex,
						  *full;
 
    if ((pdu = (struct type_PS_User__data *) calloc (1, sizeof *pdu))
	    == NULL) {
no_mem: ;
	(void) psaplose (pi, PC_CONGEST, NULLCP, "out of memory");
	goto out;
    }
 
    pdu -> offset = type_PS_User__data_simple;
    for (d = data, i = 0; i < ndata; i++) {
	if ((pe = *d++) == NULLPE) {
	    (void) psaplose (pi, PC_PARAMETER, NULLCP,
		    "missing %d%s PDV in PSDU", i + 1,
		    i == 0 ? "st" : i == 1 ? "nd" : i == 2 ? "rd" : "th");
	    goto out;
	}
	if (pb -> pb_ncontext > 0
		&& pe -> pe_context == PE_DFLT_CTX) {
	    if (ppdu != PPDU_TE) {
		(void) psaplose (pi, PC_PARAMETER, NULLCP,
				 "default context not permitted");
		goto out;
	    }
	}
	else
	    if (ppdu == PPDU_CP
		     || (pb -> pb_ncontext > 1
				&& pe -> pe_context != PE_DFLT_CTX))
		pdu -> offset = type_PS_User__data_complex;
    }
 
    if (pdu -> offset == type_PS_User__data_simple) {
	if ((qb = (struct qbuf *) malloc (sizeof *qb)) == NULL)
	    goto no_mem;
	simple = pdu -> un.simple = qb;
	qb -> qb_forw = qb -> qb_back = qb;
	qb -> qb_data = NULL, qb -> qb_len = 0;
 
	j = 0;
	for (d = data, i = 0; i < ndata; i++)
	    j += ps_get_abs (*d++);
	qb -> qb_len = j;
	if ((qb = (struct qbuf *) malloc (sizeof *qb + ((unsigned)j))) == NULL)
	    goto no_mem;
	qb -> qb_data = qb -> qb_base, qb -> qb_len = j;
	insque (qb, simple -> qb_back);
    }
    else
	complex = &pdu -> un.complex;
 
    for (d = data, i = 0; i < ndata; i++) {
	pe = *d++;
	switch (pe -> pe_context) {
	    case PE_DFLT_CTX:
		atn = pb -> pb_atn;
		break;
 
	    default:
		for (j = 0, qp = pb -> pb_contexts;
			j < pb -> pb_ncontext;
			j++, qp++)
		    if (qp -> pc_id == pe -> pe_context)
			break;
		if (j >= pb -> pb_ncontext) {
		    (void) psaplose (pi, PC_PARAMETER, NULLCP,
				"context %d is undefined", pe -> pe_context);
		    goto out;
		}
		if (qp -> pc_result != PC_ACCEPT) {
		    (void) psaplose (pi, PC_PARAMETER, NULLCP,
				"context %d is unsupported", pe -> pe_context);
		    goto out;
		}
		atn = qp -> pc_atn;
		break;
	}
 
	if (!atn_is_ber (pb, atn)) {
	    (void) psaplose (pi, PC_PARAMETER, NULLCP,
			     "ATN not BER for context %d", pe -> pe_context);
	    goto out;
	}
 
	if (pdu -> offset == type_PS_User__data_simple) {
	    if (info2qb (pe, qb, pi) == NULL)
		goto out;
	}
	else {
	    register PE    *q;
 
	    if ((full = (struct type_PS_Fully__encoded__data *)
		 	    calloc (1, sizeof *full)) == NULL)
		goto no_mem;
	    *complex = full;
	    complex = &full -> next;
	    if ((full -> PDV__list = (struct type_PS_PDV__list *)
				    calloc (1, sizeof *full -> PDV__list))
		    == NULL)
		goto no_mem;
	    full -> PDV__list -> identifier = pe -> pe_context;
	    if ((full -> PDV__list -> presentation__data__values =
		     (struct choice_PS_0 *)
		     	calloc (1, sizeof (struct choice_PS_0))) == NULL)
		goto no_mem;
 
/*ckw VOTS/VMS FTAM does not like single context definition encoding
	    for (q = d, j = i + 1; j < ndata; q++, j++)
		if ((*q) -> pe_context != pe -> pe_context)
		    break;
	    q--, j--;
 
	    if (i == j) {
ckw*/	    if (ndata == 1) {
		full -> PDV__list -> presentation__data__values ->
		    offset = choice_PS_0_single__ASN1__type;
		(full -> PDV__list -> presentation__data__values ->
		    un.single__ASN1__type = pe) -> pe_refcnt++;
	    }
	    else {
		register struct qbuf *qb2;
 
		full -> PDV__list -> presentation__data__values ->
		    offset = choice_PS_0_octet__aligned;
		if ((qb2 = (struct qbuf *) malloc (sizeof *qb2)) == NULL)
		    goto no_mem;
		full -> PDV__list -> presentation__data__values ->
		    un.octet__aligned = qb2;
		qb2 -> qb_forw = qb2 -> qb_back = qb2;
		qb2 -> qb_data = NULL, qb2 -> qb_len = 0;
/*ckw  following 7 lines are replaced by the 4 lines following 
		for (d--, j++; i < j; i++) {
		    if ((qb = info2qb (*d++, (struct qbuf *) NULL, pi))
			    == NULL)
			goto out;
		    qb2 -> qb_len += qb -> qb_len;
		    insque (qb, qb2 -> qb_back);
		}
following 4 lines replace above 7 ckw*/
                if ((qb = info2qb (pe, (struct qbuf *) NULL, pi)) == NULL)
                    goto out;
                qb2 -> qb_len = qb -> qb_len;
                insque (qb, qb2);
	    }
	}
    }
 
    return pdu;
    
out: ;
    if (pdu)
	free_PS_User__data (pdu);
 
    return NULL;
}
 
/*  */
 
int	ppdu2info (pb, pi, info, data, ndata, ppdu)
register struct psapblk *pb;
struct PSAPindication *pi;
struct type_PS_User__data *info;
PE     *data;
int    *ndata,
	ppdu;
{
    register int    i,
		    j;
    int	    ctx,
	    result;
    PE	    pe;
    register struct type_PS_Fully__encoded__data *full;
 
    *ndata = 0;
    if (info == NULL)
	return OK;
 
    i = 0;
    switch (info -> offset) {
	case type_PS_User__data_simple:
	    if (pb -> pb_ncontext < 1 || ppdu == PPDU_TE)
		ctx = PE_DFLT_CTX;
	    else
		if (pb -> pb_ncontext > 1)
		    return ppktlose (pb, pi, PC_INVALID, ppdu, NULLCP,
				     "unexpected Simply-encoded-data");
		else
		    ctx = pb -> pb_contexts[0].pc_id;
	    while ((result = qb2info (info -> un.simple, &pe)) == PS_ERR_NONE){
		if (i++ >= NPDATA) {
		    pe_free (pe);
		    return ppktlose (pb, pi, PC_CONGEST, ppdu, NULLCP,
				     "too much user information");
		}
		(*data++ = pe) -> pe_context = ctx;
	    }
	    if (result != PS_ERR_EOF)
		return ppktlose (pb, pi, result != PS_ERR_NMEM ? PC_INVALID
				 : PC_CONGEST, ppdu, NULLCP, "%s",
				 ps_error (result));
	    break;
 
	case type_PS_User__data_complex:
	    for (full = info -> un.complex; full; full = full -> next) {
		struct qbuf *qb;
		register struct PSAPcontext *qp;
		register struct type_PS_PDV__list *pdv = full -> PDV__list;
 
		ctx = pdv -> identifier;
		for (j = 0, qp = pb -> pb_contexts;
		         j < pb -> pb_ncontext;
		         j++, qp++)
		    if (qp -> pc_id == ctx)
			break;
		if (j >= pb -> pb_ncontext)
		    return ppktlose (pb, pi, PC_INVALID, ppdu, NULLCP,
				     "unexpected use of context %d", ctx);
		switch (pdv -> presentation__data__values -> offset) {
		    case choice_PS_0_single__ASN1__type:
		        if (i++ >= NPDATA)
			    return ppktlose (pb, pi, PC_CONGEST, ppdu, NULLCP,
					     "too much user information");
			pe = pdv -> presentation__data__values ->
			    	un.single__ASN1__type;
			pdv -> presentation__data__values ->
			   un.single__ASN1__type = NULLPE;
			(*data++ = pe) -> pe_context = ctx;
			break;
 
		    case choice_PS_0_octet__aligned:
			qb = pdv -> presentation__data__values ->
			    un.octet__aligned;
			while ((result = qb2info (qb, &pe)) == PS_ERR_NONE) {
			    pe -> pe_context = ctx;
			    if (i++ >= NPDATA) {
				pe_free (pe);
				return ppktlose (pb, pi, PC_CONGEST, ppdu,
						 NULLCP,
						 "too much user information");
			    }
			    (*data++ = pe) -> pe_context = ctx;
			}
			if (result != PS_ERR_EOF)
			    return ppktlose (pb, pi, result != PS_ERR_NMEM
					     ? PC_INVALID : PC_CONGEST, ppdu,
					     NULLCP, "%s", ps_error (result));
			break;
 
		    default:
			return ppktlose (pb, pi, PC_INVALID, ppdu, NULLCP,
					 "not expecting non-BER encoding");
		}
	    }
	    break;
    }
    *ndata = i;
 
    return OK;
}
 
/*  */
 
#ifndef	DEBUG
/* ARGSUSED */
#endif
 
int	info2ssdu (pb, pi, data, ndata, realbase, base, len, text, ppdu)
register struct psapblk *pb;
struct PSAPindication *pi;
PE     *data;
int	ndata;
char  **realbase,
      **base;
int    *len;
char   *text;
int	ppdu;
{
    int	    result;
    PE	    pe;
    struct type_PS_User__data *info;
 
    *realbase = *base = NULLCP, *len = 0;
    if (data == NULLPEP || ndata <= 0)
	return OK;
 
    if ((info = info2ppdu (pb, pi, data, ndata, ppdu)) == NULL)
	return (PC_FATAL (pi -> pi_abort.pa_reason) ? NOTOK : DONE);
 
    if (ppdu == PPDU_TTD) {
	pe = NULLPE;
	if ((result = encode_PS_User__data (&pe, 1, 0, NULLCP, info))
	        == NOTOK) {
losing: ;
	    free_PS_User__data (info);
	    return psaplose (pi, PC_CONGEST, NULLCP, "error encoding PDU: %s",
			     PY_pepy);
	}
 
	PLOG (psap2_log, print_PS_User__data, pe, text, 0);
 
	goto serialize;
    }
    else
	if (ppdu == PPDU_RS || ppdu == PPDU_RSA) {
				    /* this works 'cause RS-PPDU == RSA-PPDU */
	    struct type_PS_RS__PPDU rss;
	    register struct type_PS_RS__PPDU *rs = &rss;
 
	    if ((rs -> context__list = silly_list (pb, pi)) == NULL)
		return (PC_FATAL (pi -> pi_abort.pa_reason) ? NOTOK : DONE);
	    rs -> user__data = info;
 
	    pe = NULLPE;
	    if ((result = encode_PS_RS__PPDU (&pe, 1, 0, NULLCP, rs))
		    == NOTOK) {
		free_PS_Identifier__list (rs -> context__list);
		goto losing;
	    }
 
	    PLOG (psap2_log, print_PS_RS__PPDU, pe, text, 0);
 
	    free_PS_Identifier__list (rs -> context__list);
 
	    goto serialize;
	}
 
    if (info -> offset == type_PS_User__data_simple) {
	register struct qbuf *qb;
 
	qb = info -> un.simple;
	*len = qb -> qb_len;
 
	qb = qb -> qb_forw;
	remque (qb);
 
	*realbase = (char *) qb, *base = qb -> qb_base;
 
#ifdef	DEBUG
	if (psap2_log -> ll_events & LLOG_PDUS)
	    while (ndata-- > 0)
		vpdu (psap2_log, vunknown, *data++, text, 0);	
#endif
    }
    else {
	pe = NULLPE;
	if (encode_PS_Fully__encoded__data (&pe, 0, 0, NULLCP,
					   info -> un.complex) == NOTOK)
	    goto losing;
	pe -> pe_class = PE_CLASS_APPL, pe -> pe_id = 1;
 
	PLOG (psap2_log, print_PS_User__data, pe, text, 0);
 
serialize: ;
	result = pe2ssdu (pe, base, len);
 
	pe_free (pe);
 
	if (result == NOTOK) {
	    free_PS_User__data (info);
	    return psaplose (pi, PC_CONGEST, NULLCP, NULLCP);
	}
    }
    free_PS_User__data (info);
 
    return OK;
}
 
/*  */
 
#ifndef	DEBUG
/* ARGSUSED */
#endif
    
int	ssdu2info (pb, pi, base, len, data, ndata, text, ppdu)
register struct psapblk *pb;
struct PSAPindication *pi;
char   *base;
int     len;
PE     *data;
int    *ndata;
char   *text;
int	ppdu;
{
    int    result;
    register PE	    pe;
    register struct type_PS_User__data *info;
 
    *ndata = 0;
    if (base == NULLCP || len <= 0)
	return OK;
 
    if (ppdu == PPDU_RS || ppdu == PPDU_RSA) {
	struct type_PS_RS__PPDU *rs;/* this works 'cause RS-PPDU == RSA-PPDU */
 
	if ((pe = ssdu2pe (base, len, NULLCP, &result)) == NULLPE)
	    return ppktlose (pb, pi, result == PS_ERR_NMEM ? PC_CONGEST
			     : PC_PROTOCOL, ppdu, NULLCP, "%s",
			     ps_error (result));
 
	rs = NULL, info = NULL;
	result = decode_PS_RS__PPDU (pe, 1, NULLIP, NULLVP, &rs);
 
#ifdef	DEBUG
	if (result == OK && (psap2_log -> ll_events & LLOG_PDUS))
	    vpdu (psap2_log, print_PS_RS__PPDU, pe, text, 1);
#endif
 
	info = rs -> user__data, rs -> user__data = NULL;
	free_PS_RS__PPDU (rs);
 
	goto punch_it;
    }
 
    if ((info = (struct type_PS_User__data *) calloc (1, sizeof *info))
	    == NULL) {
no_mem: ;
	(void) psaplose (pi, PC_CONGEST, NULLCP, "out of memory");
out: ;
        if (info)
	    free_PS_User__data (info);
        return NOTOK;
    }
 
    if (pb -> pb_ncontext < 1 || ppdu == PPDU_TE) {
	register struct qbuf *qb;
 
	info -> offset = type_PS_User__data_simple;
 
	if ((qb = (struct qbuf *) malloc (sizeof *qb)) == NULL)
	    goto no_mem;
	info -> un.simple = qb;
	qb -> qb_forw = qb -> qb_back = qb;
	qb -> qb_data = NULL, qb -> qb_len = len;
	if ((qb = (struct qbuf *) malloc (sizeof *qb)) == NULL)
	    goto no_mem;
	insque (qb, info -> un.simple);
	qb -> qb_data = base, qb -> qb_len = len;
    }
    else {
	info -> offset = type_PS_User__data_complex;
 
	if ((pe = ssdu2pe (base, len, NULLCP, &result)) == NULLPE) {
	    (void) ppktlose (pb, pi, result == PS_ERR_NMEM ? PC_CONGEST
			     : PC_PROTOCOL, ppdu, NULLCP, "%s",
			     ps_error (result));
	    goto out;
	}
 
	if (pe -> pe_class != PE_CLASS_APPL
	    	|| pe -> pe_form != PE_FORM_CONS
	        || pe -> pe_id != 1) {
	    PY_advise (NULLCP,
		       "Fully-encoded-data bad class/form/id: %s/%d/0x%x",
		       pe_classlist[pe -> pe_class], pe -> pe_form,
		       pe -> pe_id);
	    result = NOTOK;
	}
	else
	    result = decode_PS_Fully__encoded__data (pe, 0, NULLIP, NULLVP,
						     &info -> un.complex);
 
#ifdef	DEBUG
	if (result == OK && (psap2_log -> ll_events & LLOG_PDUS))
	    vpdu (psap2_log, print_PS_User__data, pe, text, 1);
#endif
 
punch_it: ;
	pe_free (pe);
	
	if (result == NOTOK) {
	    (void) ppktlose (pb, pi, PC_UNRECOGNIZED, ppdu, "%s", PY_pepy);
	    goto out;
	}
    }
 
    if ((result = ppdu2info (pb, pi, info, data, ndata, ppdu)) == NOTOK)
	result = PC_FATAL (pi -> pi_abort.pa_reason) ? NOTOK : DONE;
 
#ifdef	DEBUG
    if (result == OK
	    && ppdu != PPDU_RS 
	    && ppdu != PPDU_RSA
	    && info -> offset == type_PS_User__data_simple
	    && (psap2_log -> ll_events & LLOG_PDUS)) {
	register int	i;
 
	for (i = *ndata; i > 0; i--)
	    vpdu (psap2_log, vunknown, *data++, text, 1);
    }
#endif
 
    free_PS_User__data (info);
 
    return result;
}
 
/*  */
 
#ifndef	DEBUG
/* ARGSUSED */
#endif
    
int	qbuf2info (pb, pi, qb, len, data, ndata, text, ppdu)
register struct psapblk *pb;
struct PSAPindication *pi;
struct qbuf *qb;
int     len;
PE     *data;
int    *ndata;
char   *text;
int	ppdu;
{
    int	    result;
    register PE	    pe;
    register struct qbuf *qp;
    struct type_PS_User__data *info;
 
    *ndata = 0;
    if (qb == NULL || len <= 0)
	return OK;
 
    if (ppdu == PPDU_TTD) {
	if ((pe = qbuf2pe (qb, len, &result)) == NULLPE)
	    return ppktlose (pb, pi, result == PS_ERR_NMEM ? PC_CONGEST
			     : PC_PROTOCOL, ppdu, NULLCP, "%s",
			     ps_error (result));
 
	info = NULL;
	result = decode_PS_User__data (pe, 1, NULLIP, NULLVP, &info);
 
#ifdef	DEBUG
	if (result == OK && (psap2_log -> ll_events & LLOG_PDUS))
	    vpdu (psap2_log, print_PS_User__data, pe, text, 1);
#endif
 
	goto punch_it;
    }
 
    if ((info = (struct type_PS_User__data *) calloc (1, sizeof *info))
	    == NULL) {
no_mem: ;
	(void) psaplose (pi, PC_CONGEST, NULLCP, "out of memory");
	goto out;
    }
 
    if (pb -> pb_ncontext <= 1 || ppdu == PPDU_TE) {
	register struct qbuf *qbp,
			     *qpp;
 
	info -> offset = type_PS_User__data_simple;
	if ((qp = (struct qbuf *) malloc (sizeof *qp)) == NULL)
	    goto no_mem;
	info -> un.simple = qpp = qp;
	qp -> qb_forw = qp -> qb_back = qp;
	qp -> qb_data = NULL, qp -> qb_len = len;
	for (qp = qb -> qb_forw; qp != qb; qp = qbp) {
	    qbp = qp -> qb_forw;
 
	    remque (qp);
	    insque (qp, qpp -> qb_back);
	}
    }
    else {
	info -> offset = type_PS_User__data_complex;
 
	if ((pe = qbuf2pe (qb, len, &result)) == NULLPE) {
	    (void) ppktlose (pb, pi, result == PS_ERR_NMEM ? PC_CONGEST
			     : PC_PROTOCOL, ppdu, NULLCP, "%s",
			     ps_error (result));
	    goto out;
	}
	if (pe -> pe_class != PE_CLASS_APPL
	    	|| pe -> pe_form != PE_FORM_CONS
	        || pe -> pe_id != 1) {
	    PY_advise (NULLCP,
		       "Fully-encoded-data bad class/form/id: %s/%d/0x%x",
		       pe_classlist[pe -> pe_class], pe -> pe_form,
		       pe -> pe_id);
	    result = NOTOK;
	}
	else
	    result = decode_PS_Fully__encoded__data (pe, 0, NULLIP, NULLVP,
						     &info -> un.complex);
 
#ifdef	DEBUG
	if (result == OK && (psap2_log -> ll_events & LLOG_PDUS))
	    vpdu (psap2_log, print_PS_User__data, pe, text, 1);
#endif
 
punch_it: ;
	pe_free (pe);
	
	if (result == NOTOK) {
	    (void) ppktlose (pb, pi, PC_UNRECOGNIZED, ppdu, "%s", PY_pepy);
	    goto out;
	}
    }
 
    if ((result = ppdu2info (pb, pi, info, data, ndata, ppdu)) == NOTOK)
	result = PC_FATAL (pi -> pi_abort.pa_reason) ? NOTOK : DONE;
 
#ifdef	DEBUG
    if (result == OK
	    && ppdu != PPDU_TTD
	    && info -> offset == type_PS_User__data_simple
	    && (psap2_log -> ll_events & LLOG_PDUS)) {
	register int	i;
 
	for (i = *ndata; i > 0; i--)
	    vpdu (psap2_log, vunknown, *data++, text, 1);
    }
#endif
 
    free_PS_User__data (info);
 
    return result;
 
out: ;
    if (info)
	free_PS_User__data (info);
 
    return NOTOK;
}
 
/*  */
 
struct qbuf *info2qb (pe, qp, pi)
register PE pe;
register struct qbuf *qp;
struct PSAPindication *pi;
{
    int	    len;
    register struct qbuf *qb;
    register PS	    ps;
 
    if ((qb = qp) == NULL) {
	if ((qb = (struct qbuf *) malloc ((unsigned) sizeof *qb
					  + (len = ps_get_abs (pe))))
		== NULL) {
no_mem: ;
	    (void) psaplose (pi, PC_CONGEST, NULLCP, NULLCP);
	    goto out;
	}	
 
	qb -> qb_data = qb -> qb_base, qb -> qb_len = len;
    }
 
    if ((ps = ps_alloc (str_open)) == NULLPS)
	goto no_mem;
    if (str_setup (ps, qb -> qb_data, qb -> qb_len, 1) == NOTOK
	    || pe2ps_aux (ps, pe, 0) == NOTOK) {
	(void) psaplose (pi, PC_CONGEST, NULLCP, "error encoding user-info");
	ps_free (ps);
	goto out;
    }
 
    len = ps -> ps_ptr - ps -> ps_base;
    if (qp)
	qp -> qb_data += len, qp -> qb_len -= len;
    else
	qb -> qb_len = len;
 
#ifdef	DEBUG
    if (psap_log -> ll_events & LLOG_PDUS)
	pe2text (psap_log, pe, 0, len);
#endif
 
    ps_free (ps);
 
    return qb;
 
out: ;
    if (qb && qb != qp)
	free ((char *) qb);
 
    return NULL;
}
    
/*  */
 
int	qb2info (qb, pe)
register struct qbuf *qb;
PE     *pe;
{
    int	    result;
#ifdef	DEBUG
    int	    len;
#endif
    PE	    p;
    register PS	    ps;
 
    *pe = NULLPE;
 
    if ((ps = ps_alloc (qbuf_open)) == NULLPS)
	return PS_ERR_NMEM;
#ifdef	DEBUG
    len = ps -> ps_byteno;
#endif
    if (qbuf_setup (ps, qb) == NOTOK || (p = ps2pe (ps)) == NULLPE) {
	if ((result = ps -> ps_errno) == PS_ERR_NONE)
	    result = PS_ERR_EOF;
    }
    else {
	result = PS_ERR_NONE;
	*pe = p;
    }
 
    ps -> ps_addr = NULL;	/* so ps_free doesn't free remainder of qbuf */
#ifdef	DEBUG
    len = ps -> ps_byteno - len;
#endif
    ps_free (ps);
 
#ifdef	DEBUG
    if (p && (psap_log -> ll_events & LLOG_PDUS))
	pe2text (psap_log, p, 1, len);
#endif
 
    return result;
}
 
/*  */
 
struct type_PS_Identifier__list *silly_list (pb, pi)
register struct psapblk *pb;
struct PSAPindication *pi;
{
    register int    j;
    register struct PSAPcontext *qp;
    struct type_PS_Identifier__list *list;
    register struct type_PS_Identifier__list *lp,
					    **mp;
 
    list = NULL;
    mp = &list;
 
    for (j = 0, qp = pb -> pb_contexts;
	     j < pb -> pb_ncontext;
	     j++, qp++) {
	if ((lp = (struct type_PS_Identifier__list *)
			calloc (1, sizeof *lp)) == NULL) {
no_mem: ;
	    (void) psaplose (pi, PC_CONGEST, NULLCP, "out of memory");
	    free_PS_Identifier__list (list);
	    return NULL;
	}
	*mp = lp;
	mp = &lp -> next;
	if ((lp -> element_PS_10 = (struct element_PS_11 *)
     			    calloc (1, sizeof (struct element_PS_11))) == NULL
	        || (lp -> element_PS_10 -> transfer__syntax =
		    	oid_cpy (qp -> pc_atn)) == NULLOID)
	    goto no_mem;
	lp -> element_PS_10 -> identifier = qp -> pc_id;
    }
 
    return list;    
}
 
========================================================================
Received: by decwrl.dec.com (5.54.5/4.7.34)
	id AA06576; Thu, 1 Jun 89 02:00:07 PDT
Received: by decwrl.dec.com (5.54.5/4.7.34)
	for eemeli::vesalainen; id AA06576; Thu, 1 Jun 89 02:00:07 PDT


--
--	Juha Heinanen, Tampere Univ. of Technology, Finland
	jh@tut.fi (Internet), tut!jh (UUCP), jh@tut (Bitnet)