|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T p
Length: 38958 (0x982e)
Types: TextFile
Names: »psaprovider.c«
└─⟦2d1937cfd⟧ Bits:30007241 EUUGD22: P.P 5.0
└─⟦35176feda⟧ »EurOpenD22/isode/isode-6.tar.Z«
└─⟦de7628f85⟧
└─⟦this⟧ »isode-6.0/psap2/psaprovider.c«
/* psaprovider.c - implement the presentation protocol */
#ifndef lint
static char *rcsid = "$Header: /f/osi/psap2/RCS/psaprovider.c,v 7.1 89/11/24 16:22:20 mrose Exp $";
#endif
/*
* $Header: /f/osi/psap2/RCS/psaprovider.c,v 7.1 89/11/24 16:22:20 mrose Exp $
*
*
* $Log: psaprovider.c,v $
* Revision 7.1 89/11/24 16:22:20 mrose
* sync
*
* Revision 7.0 89/11/23 22:14:33 mrose
* Release 6.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"
/* \f
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
};
/* \f
*/
#define doABORT ss2psabort
int DATAser (), TOKENser (), SYNCser (), ACTIVITYser (), REPORTser (),
FINISHser (), ABORTser ();
/* \f
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);
}
/* \f
*/
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;
}
/* \f
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;
}
/* \f
*/
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;
}
/* \f
*/
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;
}
/* \f
*/
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);
}
/* \f
*/
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);
}
/* \f
*/
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);
}
/* \f
*/
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);
}
/* \f
*/
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;
}
/* \f
*/
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;
}
/* \f
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
/* \f
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);
}
}
/* \f
*/
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);
}
/* \f
*/
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);
}
/* \f
*/
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);
}
/* \f
*/
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);
}
/* \f
*/
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);
}
/* \f
*/
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);
}
/* \f
*/
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);
}
/* \f
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_realbase)
free (pb -> pb_realbase);
else
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);
}
/* \f
*/
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;
}
/* \f
*/
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;
for (q = d, j = i + 1; j < ndata; q++, j++)
if ((*q) -> pe_context != pe -> pe_context)
break;
q--, j--;
if (i == j) {
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;
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);
}
}
}
}
return pdu;
out: ;
if (pdu)
free_PS_User__data (pdu);
return NULL;
}
/* \f
*/
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;
}
/* \f
*/
#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;
}
/* \f
*/
#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, NULLCP, "%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;
}
/* \f
*/
#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, NULLCP, "%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;
}
/* \f
*/
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;
}
/* \f
*/
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;
}
/* \f
*/
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;
}