|
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; }