DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T f

⟦5e0af1bc3⟧ TextFile

    Length: 59052 (0xe6ac)
    Types: TextFile
    Names: »ftamprovider.c«

Derivation

└─⟦3d0c2be1b⟧ Bits:30001254 ISODE-5.0 Tape
    └─⟦eba4602b1⟧ »./isode-5.0.tar.Z« 
        └─⟦d3ac74d73⟧ 
            └─⟦this⟧ »isode-5.0/ftam/ftamprovider.c« 

TextFile

/* ftamprovider.c - implement the FTAM protocol */

#ifndef	lint
static char *rcsid = "$Header: /f/osi/ftam/RCS/ftamprovider.c,v 6.0 89/03/18 23:30:47 mrose Rel $";
#endif

/* 
 * $Header: /f/osi/ftam/RCS/ftamprovider.c,v 6.0 89/03/18 23:30:47 mrose Rel $
 *
 *
 * $Log:	ftamprovider.c,v $
 * Revision 6.0  89/03/18  23:30:47  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 "fpkt.h"

/* \f

   DATA */

struct pair fclass_pairs[] = {
    FCLASS_UNCONS, bit_FTAM_Service__Class_unconstrained__class,
    FCLASS_MANAGE, bit_FTAM_Service__Class_management__class,
    FCLASS_TRANSFER, bit_FTAM_Service__Class_transfer__class,
    FCLASS_TM, bit_FTAM_Service__Class_transfer__and__management__class,
    FCLASS_ACCESS, bit_FTAM_Service__Class_access__class,

    0, 0
};

struct pair funit_pairs[] = {
    FUNIT_READ, bit_FTAM_Functional__Units_read,
    FUNIT_WRITE, bit_FTAM_Functional__Units_write,
    FUNIT_ACCESS, bit_FTAM_Functional__Units_file__access,
    FUNIT_LIMITED, bit_FTAM_Functional__Units_limited__file__management,
    FUNIT_ENHANCED, bit_FTAM_Functional__Units_enhanced__file__management,
    FUNIT_GROUPING, bit_FTAM_Functional__Units_grouping,
    FUNIT_FADULOCK, bit_FTAM_Functional__Units_fadu__locking,
    FUNIT_RECOVERY, bit_FTAM_Functional__Units_recovery,
    FUNIT_RESTART, bit_FTAM_Functional__Units_restart__data__transfer,

    0, 0
};

struct pair fattr_pairs[] = {
    FATTR_STORAGE, bit_FTAM_Attribute__Groups_storage,
    FATTR_SECURITY, bit_FTAM_Attribute__Groups_security,
    FATTR_PRIVATE, bit_FTAM_Attribute__Groups_private,

    0, 0
};

struct pair fname_pairs[] = {
    FA_FILENAME, bit_FTAM_Attribute__Names_read__filename,
    FA_ACTIONS, bit_FTAM_Attribute__Names_read__permitted__actions,
    FA_CONTENTS, bit_FTAM_Attribute__Names_read__content__types,
    FA_ACCOUNT, bit_FTAM_Attribute__Names_read__storage__account,
    FA_DATE_CREATE, bit_FTAM_Attribute__Names_read__date__and__time__of__creation,
    FA_DATE_MODIFY, bit_FTAM_Attribute__Names_read__date__and__time__of__last__modification,
    FA_DATE_READ, bit_FTAM_Attribute__Names_read__date__and__time__of__last__read__access,
    FA_DATE_ATTR, bit_FTAM_Attribute__Names_read__date__and__time__of__last__attribute__modification,
    FA_ID_CREATE, bit_FTAM_Attribute__Names_read__identity__of__creator,
    FA_ID_MODIFY, bit_FTAM_Attribute__Names_read__identity__of__last__modifier,
    FA_ID_READ, bit_FTAM_Attribute__Names_read__identity__of__last__reader,
    FA_ID_ATTR, bit_FTAM_Attribute__Names_read__identity__of__last__attribute__modifier,
    FA_AVAILABILITY, bit_FTAM_Attribute__Names_read__file__availability,
    FA_FILESIZE, bit_FTAM_Attribute__Names_read__filesize,
    FA_FUTURESIZE, bit_FTAM_Attribute__Names_read__future__filesize,
    FA_CONTROL, bit_FTAM_Attribute__Names_read__access__control,
    FA_LEGAL, bit_FTAM_Attribute__Names_read__legal__qualifications,
    FA_PRIVATE, bit_FTAM_Attribute__Names_read__private__use,

    0, 0
};

struct pair fmode_pairs[] = {
    FA_PERM_READ, bit_FTAM_processing__mode_f__read,
    FA_PERM_INSERT, bit_FTAM_processing__mode_f__insert,
    FA_PERM_REPLACE, bit_FTAM_processing__mode_f__replace,
    FA_PERM_EXTEND, bit_FTAM_processing__mode_f__extend,
    FA_PERM_ERASE, bit_FTAM_processing__mode_f__erase,

    0, 0
};

struct pair frequested_pairs[] = {
    FA_PERM_READ, bit_FTAM_Access__Request_read,
    FA_PERM_INSERT, bit_FTAM_Access__Request_insert,
    FA_PERM_REPLACE, bit_FTAM_Access__Request_replace,
    FA_PERM_EXTEND, bit_FTAM_Access__Request_extend,
    FA_PERM_ERASE, bit_FTAM_Access__Request_erase,
    FA_PERM_READATTR, bit_FTAM_Access__Request_read__attribute,
    FA_PERM_CHNGATTR, bit_FTAM_Access__Request_change__attribute,
    FA_PERM_DELETE, bit_FTAM_Access__Request_delete,

    0, 0
};

struct pair fpermitted_pairs[] = {
    FA_PERM_READ, bit_FTAM_Permitted__Actions__Attribute_read,
    FA_PERM_INSERT, bit_FTAM_Permitted__Actions__Attribute_insert,
    FA_PERM_REPLACE, bit_FTAM_Permitted__Actions__Attribute_replace,
    FA_PERM_EXTEND, bit_FTAM_Permitted__Actions__Attribute_extend,
    FA_PERM_ERASE, bit_FTAM_Permitted__Actions__Attribute_erase,
    FA_PERM_READATTR, bit_FTAM_Permitted__Actions__Attribute_read__attribute,
    FA_PERM_CHNGATTR, bit_FTAM_Permitted__Actions__Attribute_change__attribute,
    FA_PERM_DELETE, bit_FTAM_Permitted__Actions__Attribute_delete__file,
    FA_PERM_TRAV, bit_FTAM_Permitted__Actions__Attribute_traversal,
    FA_PERM_RVTRAV, bit_FTAM_Permitted__Actions__Attribute_reverse__traversal,
    FA_PERM_RANDOM, bit_FTAM_Permitted__Actions__Attribute_random__order,

    0, 0
};


static int  once_only = 0;
static struct ftamblk ftamque;
static struct ftamblk *FSHead = &ftamque;

int	psDATAser (), psTOKENser (), psSYNCser (), psACTIVITYser (),
	psREPORTser (), psFINISHser (), psABORTser ();

/* \f

   F-WAIT.REQUEST (pseudo) */

int	FWaitRequest (sd, secs, fti)
int	sd;
int	secs;
struct FTAMindication *fti;
{
    SBV	    smask;
    int     result;
    register struct ftamblk *fsb;

    missingP (fti);

    smask = sigioblock ();

    ftamPsig (fsb, sd);

    result = FWaitRequestAux (fsb, secs, fti);

    (void) sigiomask (smask);

    return result;
}

/* \f

 */

int	FWaitRequestAux (fsb, secs, fti)
register struct ftamblk *fsb;
int	secs;
struct FTAMindication *fti;
{
    int     result;
    struct PSAPdata pxs;
    register struct PSAPdata   *px = &pxs;
    struct PSAPindication   pis;
    register struct PSAPindication *pi = &pis;

    for (;;) {
	switch (result = PReadRequest (fsb -> fsb_fd, px, secs, pi)) {
	    case NOTOK: 
		return doPSabort (fsb, &pi -> pi_abort, fti);

	    case OK: 
		result = doPSdata (fsb, px, fti);
		break;

	    case DONE: 
		switch (pi -> pi_type) {
		    case PI_TOKEN: 
			result = doPStokens (fsb, &pi -> pi_token, fti);
			break;

		    case PI_SYNC: 
			result = doPSsync (fsb, &pi -> pi_sync, fti);
			break;

		    case PI_ACTIVITY: 
			result = doPSactivity (fsb, &pi -> pi_activity, fti);
			break;

		    case PI_REPORT: 
			result = doPSreport (fsb, &pi -> pi_report, fti);
			break;

		    case PI_FINISH: 
			result = doPSfinish (fsb, &pi -> pi_finish, fti);
			break;

		    default: 
			result = fpktlose (fsb, fti, FS_PRO_LOWFAIL, NULLCP,
				"unknown indication (0x%x) from presentation",
				pi -> pi_type);
			freefsblk (fsb);
			break;
		}
		break;

	    default: 
		result = fpktlose (fsb, fti, FS_PRO_LOWFAIL, NULLCP,
			"unexpected return from PReadRequest=%d", result);
		freefsblk (fsb);
		break;
	}

	switch (result) {
	    case NOTOK: 
		return NOTOK;

	    case OK: 
		break;

	    case DONE: 
		return OK;
	}
    }
}

/* \f

 */

static int  doPSdata (fsb, px, fti)
register struct ftamblk   *fsb;
register struct PSAPdata *px;
struct FTAMindication *fti;
{
    int     next;
    register int    i;
    register PE	pe,
               *pep;
    register struct FTAMgroup  *ftg = &fti -> fti_group;
    struct type_FTAM_PDU *pdu;

    fti -> fti_type = FTI_FINISH;/* temporary for group */
    bzero ((char *) ftg, sizeof *ftg);
    pdu = NULL;

    next = 0;
    for (pep = px -> px_info, i = px -> px_ninfo - 1; i >= 0; pep++, i--) {
	if ((pe = *pep) == NULLPE)
	    continue;

	if (pe -> pe_context != fsb -> fsb_id)
	    goto got_fadu;

	switch (PE_ID (pe -> pe_class, pe -> pe_id)) {
	    case PE_ID (PE_CLASS_APPL, FADU_NODESCR):
	    case PE_ID (PE_CLASS_APPL, FADU_ENTERTREE):
	    case PE_ID (PE_CLASS_APPL, FADU_EXITREE):
		pe -> pe_context = PE_DFLT_CTX;

got_fadu: ;
		if (next < 0) {
unexpected_fadu: ;
		    (void) fpktlose (fsb, fti, FS_PRO_ERR, NULLCP,
				"unexpected FADU; state=0x%x",
				fsb -> fsb_state);
		    goto out;
		}
		next = 1;
		break;

	    default:
		if (next > 0)
		    goto unexpected_fadu;
		next = -1;
		break;
	}
    }

    if (next > 0) {
	switch (fsb -> fsb_state) {
	    case FSB_DATAREAD: 
		if (!(fsb -> fsb_flags & FSB_INIT))
		    goto unexpected_fadu;
		break;

	    case FSB_DATAWRITE: 
		if (fsb -> fsb_flags & FSB_INIT)
		    goto unexpected_fadu;
		break;

	    case FSB_DATACANCEL: 
		fsbtrace (fsb, (fsb -> fsb_fd,
			    "discarding FADU during CANCEL procedure",
			    NULLCP, NULLPE, -1));
		PXFREE (px);
		return OK;

	    default: 
		goto unexpected_fadu;
	}

	fti -> fti_type = FTI_DATA;
	{
	    register struct PSAPdata   *fx = &fti -> fti_data;

	    *fx = *px;		/* struct copy */
	}

	return DONE;
    }

    next = FTG_BEGIN;
    for (pep = px -> px_info, i = px -> px_ninfo - 1; i >= 0; pep++, i--) {
	if ((pe = *pep) == NULLPE)
	    continue;
	if (decode_FTAM_PDU (pe, 1, NULLIP, NULLVP, &pdu) == NOTOK) {
	    (void) fpktlose (fsb, fti, FS_PRO_ERRMSG, NULLCP,
			     "unable to parse PDU: %s", PY_pepy);
	    goto out;
	}
	fsbtrace (fsb, (fsb -> fsb_fd, "P-DATA.INDICATION", "FPDU", pe, 1));

	switch (pdu -> offset) {
	    case type_FTAM_PDU_f__begin__group__request:
		if (fsb -> fsb_flags & FSB_INIT)
		    goto unexpected_fpdu;
		ftg -> ftg_threshold =
		    	    pdu -> un.f__begin__group__request -> parm;
		goto do_begin;

	    case type_FTAM_PDU_f__begin__group__response:
		if (!(fsb -> fsb_flags & FSB_INIT))
		    goto unexpected_fpdu;
	do_begin: ;
		if (!(next & FTG_BEGIN))
		    goto unexpected_fpdu;
		if (!(fsb -> fsb_units & FUNIT_GROUPING)) {
	    no_grouping: ;
		    (void) fpktlose (fsb, fti, FS_PRO_ERRFUNIT, NULLCP,
			    "grouping not permitted");
		    goto out;
		}
		ftg -> ftg_flags |= FTG_BEGIN;
		next = FTG_SELECT | FTG_CREATE | FTG_CLOSE;
		break;

	    case type_FTAM_PDU_f__select__request:
		if ((fsb -> fsb_flags & FSB_INIT) || !(next & FTG_SELECT))
		    goto unexpected_fpdu;
		ftg -> ftg_flags |= FTG_SELECT;
		{
		    register struct FTAMselect *ftse = &ftg -> ftg_select;
		    register struct type_FTAM_F__SELECT__request *req =
						pdu -> un.f__select__request;

		    if (fpm2attr (fsb, req -> attributes, &ftse -> ftse_attrs,
				  fti) == NOTOK)
			goto out;
		    ftse -> ftse_attrs.fa_present &= FA_SEL_ATTRS;
		    if (fpm2bits (fsb, frequested_pairs,
				  req -> requested__access,
				  &ftse -> ftse_access, fti) == NOTOK)
			goto out;
		    if ((fsb -> fsb_attrs & FATTR_SECURITY)
			    && req -> access__passwords
			    && fpm2pass (fsb, req -> access__passwords,
					 &ftse -> ftse_pwds, fti) == NOTOK)
			goto out;
		    FCINIT (&ftse -> ftse_conctl);
		    if ((fsb -> fsb_attrs & FATTR_STORAGE)
			    && req -> concurrency__control
			    && fpm2conctl (fsb, req -> concurrency__control,
					   &ftse -> ftse_conctl, fti) == NOTOK)
			goto out;
		    if (req -> shared__ASE__information
			    && fpm2shared (fsb,
					   req -> shared__ASE__information,
					   &ftse -> ftse_sharedASE, fti) == NOTOK)
			goto out;
		    if (req -> account
			    && (ftse -> ftse_account = qb2str (req -> account))
					== NULL) {
no_mem: ;
			(void) ftamlose (fti, FS_GEN (fsb), 1, NULLCP,
					 "out of memory");
			goto out;
		    }
		}
		next = FTG_RDATTR | FTG_CHATTR | FTG_OPEN | FTG_DESELECT
		    	| FTG_DELETE;
		break;

	    case type_FTAM_PDU_f__select__response:
		if (!(fsb -> fsb_flags & FSB_INIT) || !(next & FTG_SELECT))
		    goto unexpected_fpdu;
		ftg -> ftg_flags |= FTG_SELECT;
		{
		    register struct FTAMselect *ftse = &ftg -> ftg_select;
		    register struct type_FTAM_F__SELECT__response *rsp =
						pdu -> un.f__select__response;

		    ftse -> ftse_state = rsp -> state__result
					    ? rsp -> state__result -> parm
					    : int_FTAM_State__Result_success;
		    ftse -> ftse_action = rsp -> action__result
					    ? rsp -> action__result -> parm
					    : int_FTAM_Action__Result_success;
		    if (fpm2attr (fsb, rsp  -> attributes, &ftse -> ftse_attrs,
				  fti) == NOTOK)
			goto out;
		    ftse -> ftse_attrs.fa_present &= FA_SEL_ATTRS;
		    if (rsp -> shared__ASE__information
			    && fpm2shared (fsb,
					   rsp -> shared__ASE__information,
					   &ftse -> ftse_sharedASE, fti) == NOTOK)
			goto out;
		    if (rsp -> diagnostic
			    && fpm2diag (fsb, rsp -> diagnostic,
					 ftse -> ftse_diags,
					 &ftse -> ftse_ndiag, fti) == NOTOK)
			goto out;
		}
		next = FTG_RDATTR | FTG_CHATTR | FTG_OPEN | FTG_DESELECT
		    	| FTG_DELETE | FTG_END;
		break;

	    case type_FTAM_PDU_f__create__request:
		if ((fsb -> fsb_flags & FSB_INIT) || !(next & FTG_CREATE))
		    goto unexpected_fpdu;
		if (!(fsb -> fsb_units & FUNIT_LIMITED)) {
	no_limited: ;
		    (void) fpktlose (fsb, fti, FS_PRO_ERRPROC, NULLCP,
			    "limited file management not permitted");
		    goto out;
		}
		ftg -> ftg_flags |= FTG_CREATE;
		{
		    register struct FTAMcreate *ftce = &ftg -> ftg_create;
		    register struct type_FTAM_F__CREATE__request *req =
						pdu -> un.f__create__request;

		    ftce -> ftce_override = req -> override;
		    if (fpm2attr (fsb, req -> initial__attributes,
				  &ftce -> ftce_attrs, fti) == NOTOK)
			goto out;
		    if ((ftce -> ftce_attrs.fa_present &
			         (FA_FILENAME | FA_ACTIONS | FA_CONTENTS))
			    != (FA_FILENAME | FA_ACTIONS | FA_CONTENTS)) {
			(void) ftamlose (fti, FS_GEN (fsb), 1, NULLCP,
			   "missing mandatory parameters in F-CREATE-request");
			goto out;
		    }
		    ftce -> ftce_attrs.fa_present &= FA_CRE_ATTRS;
		    if (!(fsb -> fsb_attrs & FATTR_STORAGE))
			ftce -> ftce_attrs.fa_present &= ~FA_STORAGE;
		    if (!(fsb -> fsb_attrs & FATTR_SECURITY))
			ftce -> ftce_attrs.fa_present &= ~FA_SECURITY;
		    if (req->create__password) {/* both choices are qbufs... */
			register struct qbuf *qb =
			    		req -> create__password -> un.graphic;

			if ((ftce -> ftce_create = qb2str (qb)) == NULL)
			    goto no_mem;
			ftce -> ftce_crelen = qb -> qb_len;
		    }
		    if (fpm2bits (fsb, frequested_pairs,
				  req -> requested__access,
				  &ftce -> ftce_access, fti) == NOTOK)
			goto out;
		    if ((fsb -> fsb_attrs & FATTR_SECURITY)
			    && req -> access__passwords
			    && fpm2pass (fsb, req -> access__passwords,
					 &ftce -> ftce_pwds, fti) == NOTOK)
			goto out;
		    FCINIT (&ftce -> ftce_conctl);
		    if ((fsb -> fsb_attrs & FATTR_STORAGE)
			    && req -> concurrency__control
			    && fpm2conctl (fsb, req -> concurrency__control,
					   &ftce -> ftce_conctl, fti) == NOTOK)
			goto out;
		    if (req -> shared__ASE__information
			    && fpm2shared (fsb,
					   req -> shared__ASE__information,
					   &ftce -> ftce_sharedASE, fti) == NOTOK)
			goto out;
		    if (req -> account
			    && (ftce -> ftce_account = qb2str (req -> account))
					== NULL)
			goto no_mem;
		}
		next = FTG_RDATTR | FTG_CHATTR | FTG_OPEN | FTG_DESELECT
		    	| FTG_DELETE;
		break;

	    case type_FTAM_PDU_f__create__response:
		if (!(fsb -> fsb_flags & FSB_INIT) || !(next & FTG_CREATE))
		    goto unexpected_fpdu;
		if (!(fsb -> fsb_units & FUNIT_LIMITED))
		    goto no_limited;
		ftg -> ftg_flags |= FTG_CREATE;
		{
		    register struct FTAMcreate *ftce = &ftg -> ftg_create;
		    register struct type_FTAM_F__CREATE__response *rsp =
						pdu -> un.f__create__response;

		    ftce -> ftce_state = rsp -> state__result
					    ? rsp -> state__result -> parm
					    : int_FTAM_State__Result_success;
		    ftce -> ftce_action = rsp -> action__result
					    ? rsp -> action__result -> parm
					    : int_FTAM_Action__Result_success;
		    if (fpm2attr (fsb, rsp -> initial__attributes,
				  &ftce -> ftce_attrs, fti) == NOTOK)
			goto out;
		    ftce -> ftce_attrs.fa_present &= FA_CRE_ATTRS;
		    if (!(fsb -> fsb_attrs & FATTR_STORAGE))
			ftce -> ftce_attrs.fa_present &= ~FA_STORAGE;
		    if (!(fsb -> fsb_attrs & FATTR_SECURITY))
			ftce -> ftce_attrs.fa_present &= ~FA_SECURITY;
		    if (rsp -> shared__ASE__information
			    && fpm2shared (fsb,
					   rsp -> shared__ASE__information,
					   &ftce -> ftce_sharedASE, fti) == NOTOK)
			goto out;
		    if (rsp -> diagnostic
			    && fpm2diag (fsb, rsp -> diagnostic,
					 ftce -> ftce_diags,
					 &ftce -> ftce_ndiag, fti) == NOTOK)
			goto out;
		}
		next = FTG_RDATTR | FTG_CHATTR | FTG_OPEN | FTG_DESELECT
		    	| FTG_DELETE | FTG_END;
		break;

	    case type_FTAM_PDU_f__read__attrib__request:
		if ((fsb -> fsb_flags & FSB_INIT) || !(next & FTG_RDATTR))
		    goto unexpected_fpdu;
		if (!(fsb -> fsb_units & FUNIT_LIMITED))
		    goto no_limited;
		ftg -> ftg_flags |= FTG_RDATTR;
		{
		    register struct FTAMreadattr  *ftra = &ftg -> ftg_readattr;
		    register struct type_FTAM_F__READ__ATTRIB__request *req =
					    pdu -> un.f__read__attrib__request;

		    if (fpm2bits (fsb, fname_pairs, req,
				     &ftra -> ftra_attrnames, fti) == NOTOK)
			goto out;
		    if (!(fsb -> fsb_attrs & FATTR_STORAGE))
			ftra -> ftra_attrnames &= ~FA_STORAGE;
		    if (!(fsb -> fsb_attrs & FATTR_SECURITY))
			ftra -> ftra_attrnames &= ~FA_SECURITY;
		}
		next = FTG_CHATTR | FTG_OPEN | FTG_DESELECT | FTG_DELETE;
		break;

	    case type_FTAM_PDU_f__read__attrib__response:
		if (!(fsb -> fsb_flags & FSB_INIT) || !(next & FTG_RDATTR))
		    goto unexpected_fpdu;
		if (!(fsb -> fsb_units & FUNIT_LIMITED))
		    goto no_limited;
		ftg -> ftg_flags |= FTG_RDATTR;
		{
		    register struct FTAMreadattr  *ftra = &ftg -> ftg_readattr;
		    register struct type_FTAM_F__READ__ATTRIB__response *rsp =
					   pdu -> un.f__read__attrib__response;

		    ftra -> ftra_action = rsp -> action__result
					    ? rsp -> action__result -> parm
					    : int_FTAM_Action__Result_success;
		    if (rsp -> attributes
			    && fpm2attr (fsb, rsp -> attributes,
					 &ftra -> ftra_attrs, fti) == NOTOK)
			goto out;
		    if (!(fsb -> fsb_attrs & FATTR_STORAGE))
			ftra -> ftra_attrs.fa_present &= ~FA_STORAGE;
		    if (!(fsb -> fsb_attrs & FATTR_SECURITY))
			ftra -> ftra_attrs.fa_present &= ~FA_SECURITY;
		    if (rsp -> diagnostic
			    && fpm2diag (fsb, rsp -> diagnostic,
					 ftra -> ftra_diags,
					 &ftra -> ftra_ndiag, fti) == NOTOK)
			goto out;
		}
		next = FTG_CHATTR | FTG_OPEN | FTG_DESELECT | FTG_DELETE;
		break;

	    case type_FTAM_PDU_f__change__attrib__request:
		if ((fsb -> fsb_flags & FSB_INIT) || !(next & FTG_CHATTR))
		    goto unexpected_fpdu;
		if (!(fsb -> fsb_units & FUNIT_ENHANCED)) {
	    no_enhanced: ;
		    (void) fpktlose (fsb, fti, FS_PRO_ERRPROC, NULLCP,
			    "enhanced file management not permitted");
		    goto out;
		}
		ftg -> ftg_flags |= FTG_CHATTR;
		{
		    register struct FTAMchngattr  *ftca = &ftg -> ftg_chngattr;
		    register struct type_FTAM_F__CHANGE__ATTRIB__request *req =
					  pdu -> un.f__change__attrib__request;

		    if (fpm2attr (fsb, req, &ftca -> ftca_attrs, fti) == NOTOK)
			goto out;
		    if (ftca -> ftca_attrs.fa_present
				& ftca -> ftca_attrs.fa_novalue) {
			(void) fpktlose (fsb, fti, FS_PRO_ERRPROC, NULLCP,
				"attributes can not be changed to no value available");
			goto out;
		    }
		    if (!(fsb -> fsb_attrs & FATTR_STORAGE))
			ftca -> ftca_attrs.fa_present &= ~FA_STORAGE;
		    if (!(fsb -> fsb_attrs & FATTR_SECURITY))
			ftca -> ftca_attrs.fa_present &= ~FA_SECURITY;
		}
		next = FTG_OPEN | FTG_DESELECT | FTG_DELETE;
		break;

	    case type_FTAM_PDU_f__change__attrib__response:
		if (!(fsb -> fsb_flags & FSB_INIT) || !(next & FTG_CHATTR))
		    goto unexpected_fpdu;
		if (!(fsb -> fsb_units & FUNIT_ENHANCED))
		    goto no_enhanced;
		ftg -> ftg_flags |= FTG_CHATTR;
		{
		    register struct FTAMchngattr  *ftca = &ftg -> ftg_chngattr;
		    register struct type_FTAM_F__CHANGE__ATTRIB__response *rsp =
					 pdu -> un.f__change__attrib__response;

		    ftca -> ftca_action = rsp -> action__result
					    ? rsp -> action__result -> parm
					    : int_FTAM_Action__Result_success;
		    if (rsp -> attributes
			    && fpm2attr (fsb, rsp -> attributes,
					 &ftca -> ftca_attrs, fti) == NOTOK)
			goto out;
		    if (!(fsb -> fsb_attrs & FATTR_STORAGE))
			ftca -> ftca_attrs.fa_present &= ~FA_STORAGE;
		    if (!(fsb -> fsb_attrs & FATTR_SECURITY))
			ftca -> ftca_attrs.fa_present &= ~FA_SECURITY;
		    if (rsp -> diagnostic
			    && fpm2diag (fsb, rsp -> diagnostic,
					 ftca -> ftca_diags,
					 &ftca -> ftca_ndiag, fti) == NOTOK)
			goto out;
		    if (!(fsb -> fsb_attrs & FATTR_STORAGE))
			ftca -> ftca_attrs.fa_present &= ~FA_STORAGE;
		    if (!(fsb -> fsb_attrs & FATTR_SECURITY))
			ftca -> ftca_attrs.fa_present &= ~FA_SECURITY;
		}
		next = FTG_OPEN | FTG_DESELECT | FTG_DELETE;
		break;

	    case type_FTAM_PDU_f__open__request:
		if ((fsb -> fsb_flags & FSB_INIT) || !(next & FTG_OPEN))
		    goto unexpected_fpdu;
		ftg -> ftg_flags |= FTG_OPEN;
		{
		    register struct FTAMopen *ftop = &ftg -> ftg_open;
		    register struct type_FTAM_F__OPEN__request *req =
					  pdu -> un.f__open__request;

		    if (req -> processing__mode) {
			if (fpm2bits (fsb, fmode_pairs,
				      req -> processing__mode,
				      &ftop -> ftop_mode, fti) == NOTOK)
			    goto out;
		    }
		    else
			ftop -> ftop_mode = FA_PERM_READ;
		    if (req -> contents__type -> offset
			    == choice_FTAM_0_proposed) {
			register struct type_FTAM_Contents__Type__Attribute
			    *proposed = req -> contents__type -> un.proposed;

			ftop -> ftop_contents =
			    	proposed -> document__type__name;
			proposed -> document__type__name = NULLOID;
			if (proposed -> parameter
			        && (ftop -> ftop_parameter =
				    	pe_cpy (proposed -> parameter))
			    			== NULLPE)
			    goto no_mem;
		    }
		    FCINIT (&ftop -> ftop_conctl);
		    if ((fsb -> fsb_attrs & FATTR_STORAGE)
			    && req -> concurrency__control
			    && fpm2conctl (fsb, req -> concurrency__control,
					   &ftop -> ftop_conctl, fti) == NOTOK)
			goto out;
		    if (req -> shared__ASE__information
			    && fpm2shared (fsb,
					   req -> shared__ASE__information,
					   &ftop -> ftop_sharedASE, fti) == NOTOK)
			goto out;
		    if (fsb -> fsb_units & FUNIT_FADULOCK)
			ftop -> ftop_locking = req -> enable__fadu__locking;
		}
		next = FTG_END;
		break;

	    case type_FTAM_PDU_f__open__response:
		if (!(fsb -> fsb_flags & FSB_INIT) || !(next & FTG_OPEN))
		    goto unexpected_fpdu;
		ftg -> ftg_flags |= FTG_OPEN;
		{
		    register struct FTAMopen *ftop = &ftg -> ftg_open;
		    register struct type_FTAM_F__OPEN__response *rsp =
					  pdu -> un.f__open__response;
		    register struct type_FTAM_Contents__Type__Attribute
					*proposed = rsp -> contents__type;

		    ftop -> ftop_state = rsp -> state__result
					    ? rsp -> state__result -> parm
					    : int_FTAM_State__Result_success;
		    ftop -> ftop_action = rsp -> action__result
					    ? rsp -> action__result -> parm
					    : int_FTAM_Action__Result_success;
		    ftop -> ftop_contents = proposed -> document__type__name;
		    proposed -> document__type__name = NULLOID;
		    if (proposed -> parameter
			    && (ftop -> ftop_parameter =
				    pe_cpy (proposed -> parameter)) == NULLPE)
			goto no_mem;
		    FCINIT (&ftop -> ftop_conctl);
		    if ((fsb -> fsb_attrs & FATTR_STORAGE)
			    && rsp -> concurrency__control
			    && fpm2conctl (fsb, rsp -> concurrency__control,
					   &ftop -> ftop_conctl, fti) == NOTOK)
			goto out;
		    if (rsp -> shared__ASE__information
			    && fpm2shared (fsb,
					   rsp -> shared__ASE__information,
					   &ftop -> ftop_sharedASE, fti) == NOTOK)
			goto out;
		    if (rsp -> diagnostic
			    && fpm2diag (fsb, rsp -> diagnostic,
					 ftop -> ftop_diags,
					 &ftop -> ftop_ndiag, fti) == NOTOK)
			goto out;
		}
		next = FTG_END;
		break;

	    case type_FTAM_PDU_f__close__request:
		if (fsb -> fsb_flags & FSB_INIT)
		    goto unexpected_fpdu;
		goto do_close;
	    case type_FTAM_PDU_f__close__response:
		if (!(fsb -> fsb_flags & FSB_INIT))
		    goto unexpected_fpdu;
	do_close: ;
		if (!(next & FTG_CLOSE))
		    goto unexpected_fpdu;
		ftg -> ftg_flags |= FTG_CLOSE;
		{			/* F-CLOSE-response is identical... */
		    register struct FTAMclose *ftcl = &ftg -> ftg_close;
		    register struct type_FTAM_F__CLOSE__request *req =
					  pdu -> un.f__close__request;

		    ftcl -> ftcl_action = req -> action__result
					    ? req -> action__result -> parm
					    : int_FTAM_Action__Result_success;
		    if (req -> shared__ASE__information
			    && fpm2shared (fsb,
					   req -> shared__ASE__information,
					   &ftcl -> ftcl_sharedASE, fti) == NOTOK)
			goto out;
		    if (req -> diagnostic
			    && fpm2diag (fsb, req -> diagnostic,
					 ftcl -> ftcl_diags,
					 &ftcl -> ftcl_ndiag, fti) == NOTOK)
			goto out;
		}
		next = FTG_DESELECT | FTG_DELETE;
		break;

	    case type_FTAM_PDU_f__deselect__request:
		if ((fsb -> fsb_flags & FSB_INIT) || !(next & FTG_DESELECT))
		    goto unexpected_fpdu;
		ftg -> ftg_flags |= FTG_DESELECT;
		{
		    register struct FTAMdeselect  *ftde = &ftg -> ftg_deselect;
		    register struct type_FTAM_F__DESELECT__request *req =
					  pdu -> un.f__deselect__request;

		    if (req
			    && fpm2shared (fsb, req,
					   &ftde -> ftde_sharedASE, fti) == NOTOK)
			goto out;
		}
		next = FTG_END;
		break;

	    case type_FTAM_PDU_f__deselect__response:
		if (!(fsb -> fsb_flags & FSB_INIT) || !(next & FTG_DESELECT))
		    goto unexpected_fpdu;
		ftg -> ftg_flags |= FTG_DESELECT;
		{
		    register struct FTAMdeselect  *ftde = &ftg -> ftg_deselect;
		    register struct type_FTAM_F__DESELECT__response *rsp =
					  pdu -> un.f__deselect__response;

		    ftde -> ftde_action = rsp -> action__result
					    ? rsp -> action__result -> parm
					    : int_FTAM_Action__Result_success;
		    if (rsp -> shared__ASE__information
			    && fpm2shared (fsb,
					   rsp -> shared__ASE__information,
					   &ftde -> ftde_sharedASE, fti) == NOTOK)
			goto out;
		    if (rsp -> charging
			    && fpm2chrg (fsb, rsp -> charging,
					  &ftde -> ftde_charges, fti) == NOTOK)
			goto out;
		    if (rsp -> diagnostic
			    && fpm2diag (fsb, rsp -> diagnostic,
					 ftde -> ftde_diags,
					 &ftde -> ftde_ndiag, fti) == NOTOK)
			goto out;
		}
		next = FTG_END;
		break;

	    case type_FTAM_PDU_f__delete__request:
		if (fsb -> fsb_flags & FSB_INIT)
		    goto unexpected_fpdu;
		if (!(fsb -> fsb_units & FUNIT_LIMITED))
		    goto no_limited;
		ftg -> ftg_flags |= FTG_DELETE;
		{
		    register struct FTAMdelete  *ftxe = &ftg -> ftg_delete;
		    register struct type_FTAM_F__DELETE__request *req =
					  pdu -> un.f__delete__request;

		    if (req
			    && fpm2shared (fsb, req,
					   &ftxe -> ftxe_sharedASE, fti) == NOTOK)
			goto out;
		}
		next = FTG_END;
		break;

	    case type_FTAM_PDU_f__delete__response:
		if (!(fsb -> fsb_flags & FSB_INIT) || !(next & FTG_DELETE))
		    goto unexpected_fpdu;
		if (!(fsb -> fsb_units & FUNIT_LIMITED))
		    goto no_limited;
		ftg -> ftg_flags |= FTG_DELETE;
		{
		    register struct FTAMdelete  *ftxe = &ftg -> ftg_delete;
		    register struct type_FTAM_F__DELETE__response *rsp =
					  pdu -> un.f__delete__response;

		    ftxe -> ftxe_action = rsp -> action__result
					    ? rsp -> action__result -> parm
					    : int_FTAM_Action__Result_success;
		    if (rsp -> shared__ASE__information
			    && fpm2shared (fsb,
					   rsp -> shared__ASE__information,
					   &ftxe -> ftxe_sharedASE, fti) == NOTOK)
			goto out;
		    if (rsp -> charging
			    && fpm2chrg (fsb, rsp -> charging,
					  &ftxe -> ftxe_charges, fti) == NOTOK)
			goto out;
		    if (rsp -> diagnostic
			    && fpm2diag (fsb, rsp -> diagnostic,
					 ftxe -> ftxe_diags,
					 &ftxe -> ftxe_ndiag, fti) == NOTOK)
			goto out;
		}
		next = FTG_END;
		break;

	    case type_FTAM_PDU_f__end__group__request:
		if (fsb -> fsb_flags & FSB_INIT)
		    goto unexpected_fpdu;
		goto do_end;
	    case type_FTAM_PDU_f__end__group__response:
		if (!(fsb -> fsb_flags & FSB_INIT))
		    goto unexpected_fpdu;
	do_end: ;
		if (!(next & FTG_END))
		    goto unexpected_fpdu;
		if (!(fsb -> fsb_units & FUNIT_GROUPING))
		    goto no_grouping;
		ftg -> ftg_flags |= FTG_END;
		next = 0;
		break;

	    case type_FTAM_PDU_f__locate__request:
		if ((fsb -> fsb_flags & FSB_INIT)
			|| fsb -> fsb_state != FSB_DATAIDLE
		        || next != FTG_BEGIN)
		    goto unexpected_fpdu;
		if (!(fsb -> fsb_units & FUNIT_ACCESS)) {
	no_access: ;
		    (void) fpktlose (fsb, fti, FS_PRO_ERRPROC, NULLCP,
			    "file access not permitted");
		    goto out;
		}
		fti -> fti_type = FTI_ACCESS;
		{
		    register struct FTAMaccess *ftac = &fti -> fti_access;
		    register struct type_FTAM_F__LOCATE__request *req =
					  pdu -> un.f__locate__request;

		    ftac -> ftac_operation = FA_OPS_LOCATE;
		    if (fpm2faduid (fsb,
				    req -> file__access__data__unit__identity,
				    &ftac -> ftac_identity, fti) == NOTOK)
			goto out;
		    if (req -> fadu__lock)
			ftac -> ftac_locking = req -> fadu__lock -> parm;
		}
		next = 0;
		break;

	    case type_FTAM_PDU_f__locate__response:
		if (!(fsb -> fsb_flags & FSB_INIT)
			|| fsb -> fsb_state != FSB_LOCATE
		        || next != FTG_BEGIN)
		    goto unexpected_fpdu;
		if (!(fsb -> fsb_units & FUNIT_ACCESS))
		    goto no_access;
		fti -> fti_type = FTI_ACCESS;
		{
		    register struct FTAMaccess *ftac = &fti -> fti_access;
		    register struct type_FTAM_F__LOCATE__response *rsp =
					  pdu -> un.f__locate__response;

		    ftac -> ftac_operation = FA_OPS_LOCATE;
		    ftac -> ftac_action = rsp -> action__result
					    ? rsp -> action__result -> parm
					    : int_FTAM_Action__Result_success;
		    if (rsp -> file__access__data__unit__identity
			    && fpm2faduid (fsb,
					   rsp -> file__access__data__unit__identity,
					   &ftac -> ftac_identity, fti)
				    == NOTOK)
			goto out;
		    if (rsp -> diagnostic
			    && fpm2diag (fsb, rsp -> diagnostic,
					 ftac -> ftac_diags,
					 &ftac -> ftac_ndiag, fti) == NOTOK)
			goto out;
		}
		next = 0;
		break;

	    case type_FTAM_PDU_f__erase__request:
		if ((fsb -> fsb_flags & FSB_INIT)
			|| fsb -> fsb_state != FSB_DATAIDLE
		        || next != FTG_BEGIN)
		    goto unexpected_fpdu;
		if (!(fsb -> fsb_units & FUNIT_ACCESS))
		    goto no_access;
		fti -> fti_type = FTI_ACCESS;
		{
		    register struct FTAMaccess *ftac = &fti -> fti_access;
		    register struct type_FTAM_F__ERASE__request *req =
					  pdu -> un.f__erase__request;

		    ftac -> ftac_operation = FA_OPS_ERASE;
		    if (fpm2faduid (fsb, req, &ftac -> ftac_identity, fti)
			    == NOTOK)
			goto out;
		}
		next = 0;
		break;

	    case type_FTAM_PDU_f__erase__response:
		if (!(fsb -> fsb_flags & FSB_INIT)
			|| fsb -> fsb_state != FSB_ERASE
		        || next != FTG_BEGIN)
		    goto unexpected_fpdu;
		if (!(fsb -> fsb_units & FUNIT_ACCESS))
		    goto no_access;
		fti -> fti_type = FTI_ACCESS;
		{
		    register struct FTAMaccess *ftac = &fti -> fti_access;
		    register struct type_FTAM_F__ERASE__response *rsp =
					  pdu -> un.f__erase__response;

		    ftac -> ftac_operation = FA_OPS_ERASE;
		    ftac -> ftac_action = rsp -> action__result
					    ? rsp -> action__result -> parm
					    : int_FTAM_Action__Result_success;
		    if (rsp -> diagnostic
			    && fpm2diag (fsb, rsp -> diagnostic,
					 ftac -> ftac_diags,
					 &ftac -> ftac_ndiag, fti) == NOTOK)
			goto out;
		}
		next = 0;
		break;

	    case type_FTAM_PDU_f__read__request:
		if ((fsb -> fsb_flags & FSB_INIT)
			|| next != FTG_BEGIN
			|| fsb -> fsb_state != FSB_DATAIDLE)
		    goto unexpected_fpdu;
		if (!(fsb -> fsb_units & FUNIT_READ)) {
		    (void) fpktlose (fsb, fti, FS_PRO_ERRPROC, NULLCP,
			    "reading not permitted");
		    goto out;
		}
		fti -> fti_type = FTI_READWRITE;
		{
		    register struct FTAMreadwrite *ftrw = &fti -> fti_readwrite;
		    register struct type_FTAM_F__READ__request *req =
						pdu -> un.f__read__request;

		    ftrw -> ftrw_operation = FA_OPS_READ;
		    if (fpm2faduid (fsb,
				    req -> file__access__data__unit__identity,
				    &ftrw -> ftrw_identity, fti) == NOTOK)
			goto out;
		    if ((ftrw -> ftrw_context =
				    req -> access__context -> access__context)
			    == FA_ACC_FL) {
			if (req -> access__context -> optionals
			        & opt_FTAM_Access__Context_level__number)
			    ftrw -> ftrw_level =
				    req -> access__context -> level__number;
			else {
			    (void) fpktlose (fsb, fti, FS_PRO_ERRMSG, NULLCP,
				 "level-number missing for access-context FL");
			    goto out;
			}
		    }
		    else
			ftrw -> ftrw_level = -1;

		    if ((fsb -> fsb_units & FUNIT_FADULOCK)
			    && req -> fadu__lock)
			ftrw -> ftrw_locking = req -> fadu__lock -> parm;
		}
		next = 0;
		break;

	    case type_FTAM_PDU_f__write__request:
		if ((fsb -> fsb_flags & FSB_INIT)
			|| next != FTG_BEGIN
			|| fsb -> fsb_state != FSB_DATAIDLE)
		    goto unexpected_fpdu;
		if (!(fsb -> fsb_units & FUNIT_WRITE)) {
		    (void) fpktlose (fsb, fti, FS_PRO_ERRPROC, NULLCP,
			    "writing not permitted");
		    goto out;
		}
		fti -> fti_type = FTI_READWRITE;
		{
		    register struct FTAMreadwrite *ftrw = &fti -> fti_readwrite;
		    register struct type_FTAM_F__WRITE__request *req =
		    				pdu -> un.f__write__request;

		    ftrw -> ftrw_operation =
				    req -> file__access__data__unit__operation;
		    if (fpm2faduid (fsb,
				    req -> file__access__data__unit__identity,
				    &ftrw -> ftrw_identity, fti) == NOTOK)
			goto out;
		    if ((fsb -> fsb_units & FUNIT_FADULOCK)
			    && req -> fadu__lock)
			ftrw -> ftrw_locking = req -> fadu__lock -> parm;
		}
		next = 0;
		break;

	    case type_FTAM_PDU_f__data__end__request:
		switch (fsb -> fsb_state) {
		    case FSB_DATAREAD:
			if (!(fsb -> fsb_flags & FSB_INIT))
			    goto unexpected_data_end;
			break;

		    case FSB_DATAWRITE:
			if (fsb -> fsb_flags & FSB_INIT)
			    goto unexpected_data_end;
			break;

		    case FSB_DATACANCEL:
			fsbtrace (fsb,
			    (fsb -> fsb_fd,
			   "discarding F-DATA-END during CANCEL procedure",
				NULLCP, NULLPE, -1));
			free_FTAM_PDU (pdu);
			PXFREE (px);
			return OK;
			
		    default:
unexpected_data_end: ;
			(void) fpktlose (fsb, fti, FS_PRO_ERR, NULLCP,
				    "unexpected data end; state=0x%x",
				    fsb -> fsb_state);
			goto out;
		}
		if (next != FTG_BEGIN)
		    goto unexpected_data_end;

		fti -> fti_type = FTI_DATAEND;
		{
		    register struct FTAMdataend *ftda = &fti -> fti_dataend;
		    register struct type_FTAM_F__DATA__END__request *req =
					pdu -> un.f__data__end__request;

		    ftda -> ftda_action = req -> action__result
					    ?req -> action__result -> parm
					    : int_FTAM_Action__Result_success;
		    if (req -> diagnostic
			    && fpm2diag (fsb, req -> diagnostic,
					 ftda -> ftda_diags,
					 &ftda -> ftda_ndiag, fti) == NOTOK)
			goto out;
		}
		next = 0;
		break;

	    case type_FTAM_PDU_f__cancel__request:
		switch (fsb -> fsb_state) {
		    case FSB_DATAREAD:
		    case FSB_DATAWRITE:
		    case FSB_DATAFIN1:
		    case FSB_DATAFIN2:
			break;

		    case FSB_DATACANCEL:
			fsb -> fsb_flags |= FSB_COLLIDE;
			break;

		    default:
			goto unexpected_fpdu;
		}
		goto do_cancel;
	    case type_FTAM_PDU_f__cancel__response:
		if (fsb -> fsb_state != FSB_DATACANCEL)
		    goto unexpected_fpdu;
	do_cancel: ;
		if (next != FTG_BEGIN)
		    goto unexpected_fpdu;
		fti -> fti_type = FTI_CANCEL;
		{			/* F-CANCEL-response is identical... */
		    register struct FTAMcancel *ftcn = &fti -> fti_cancel;
		    register struct type_FTAM_F__CANCEL__request *req =
						pdu -> un.f__cancel__request;

		    ftcn -> ftcn_action = req -> action__result
					    ? req -> action__result -> parm
					    : int_FTAM_Action__Result_success;
		    if (req -> shared__ASE__information
			    && fpm2shared (fsb,
					   req -> shared__ASE__information,
					   &ftcn -> ftcn_sharedASE, fti) == NOTOK)
			goto out;
		    if (req -> diagnostic
			    && fpm2diag (fsb, req -> diagnostic,
					 ftcn -> ftcn_diags,
					 &ftcn -> ftcn_ndiag, fti) == NOTOK)
			goto out;
		}
		next = 0;
		break;

	    case type_FTAM_PDU_f__transfer__end__request:
		if ((fsb -> fsb_flags & FSB_INIT)
			|| next != FTG_BEGIN)
		    goto unexpected_fpdu;
		switch (fsb -> fsb_state) {
		    case FSB_DATAFIN1:
			break;

		    case FSB_DATACANCEL:
			fsbtrace (fsb,
			   (fsb -> fsb_fd,
			   "discarding F-TRANSFER-END during CANCEL procedure",
				NULLCP, NULLPE, -1));
			free_FTAM_PDU (pdu);
			PXFREE (px);
			return OK;
			
		    default:
			goto unexpected_fpdu;
		}
		fti -> fti_type = FTI_TRANSEND;
		{
		    register struct FTAMtransend *ftre = &fti -> fti_transend;
		    register struct type_FTAM_F__TRANSFER__END__request *req =
					   pdu -> un.f__transfer__end__request;

		    if (req
			    && fpm2shared (fsb, req,
					   &ftre -> ftre_sharedASE, fti) == NOTOK)
			goto out;
		}
		next = 0;
		break;

	    case type_FTAM_PDU_f__transfer__end__response:
		if (!(fsb -> fsb_flags & FSB_INIT)
			|| next != FTG_BEGIN
			|| fsb -> fsb_state != FSB_DATAFIN2)
		    goto unexpected_fpdu;
		fti -> fti_type = FTI_TRANSEND;
		{
		    register struct FTAMtransend *ftre = &fti -> fti_transend;
		    register struct type_FTAM_F__TRANSFER__END__response *rsp =
					  pdu -> un.f__transfer__end__response;

		    ftre -> ftre_action = rsp -> action__result
					    ? rsp -> action__result -> parm
					    : int_FTAM_Action__Result_success;
		    if (rsp -> shared__ASE__information
			    && fpm2shared (fsb,
					   rsp -> shared__ASE__information,
					   &ftre -> ftre_sharedASE, fti) == NOTOK)
			goto out;
		    if (rsp -> diagnostic
			    && fpm2diag (fsb, rsp -> diagnostic,
					 ftre -> ftre_diags,
					 &ftre -> ftre_ndiag, fti) == NOTOK)
			goto out;
		}
		next = 0;
		break;

	    default: 
	unexpected_fpdu: ;
		(void) fpktlose (fsb, fti, FS_PRO_ERR, NULLCP,
			"FPDU mismatch; expecting one of 0x%x, found tag %s/%d/0x%x; state=0x%x",
			next, pe_classlist[pe -> pe_class], pe -> pe_form,
			pe -> pe_id, fsb -> fsb_state);
		goto out;
	}

	free_FTAM_PDU (pdu);
	pdu = NULL;
    }

    if (next) {
	(void) fpktlose (fsb, fti, FS_PRO_ERRPROC, NULLCP,
		"missing FPDU(s) in group; expecting one of 0x%x next",
		next);
	goto out;
    }

    switch (fti -> fti_type) {
	case FTI_ACCESS:
	    fsb -> fsb_state = (fsb -> fsb_flags & FSB_INIT) ? FSB_DATAIDLE
				    : fti -> fti_access.ftac_operation
					== FA_OPS_LOCATE ? FSB_LOCATE
							 : FSB_ERASE;
	    goto done;

	case FTI_READWRITE:
	    fsb -> fsb_state = fti -> fti_readwrite.ftrw_operation
				    == FA_OPS_READ ? FSB_DATAREAD
						   : FSB_DATAWRITE;
	    goto done;

	case FTI_DATAEND:
	    fsb -> fsb_state = FSB_DATAFIN1;
	    goto done;

	case FTI_TRANSEND:
	    fsb -> fsb_state = (fsb -> fsb_flags & FSB_INIT) ? FSB_DATAIDLE
					: FSB_DATAFIN2;
	    goto done;

	case FTI_CANCEL:
	    if (fsb -> fsb_flags & FSB_COLLIDE) {
		struct FTAMindication ftis;

		fsbtrace (fsb, (fsb -> fsb_fd, "resolving CANCEL collision",
			    NULLCP, NULLPE, -1));
		(void) FCancelResponseAux (fsb, fsb -> fsb_cancelaction,
					   fsb -> fsb_cancelshared,
					   fsb -> fsb_canceldiags,
					   fsb -> fsb_cancelndiag,
					   &ftis);

		fsb -> fsb_flags &= ~FSB_COLLIDE;
		fsb -> fsb_cancelaction = FACTION_PERM;
		if (fsb -> fsb_cancelshared) {
		    pe_free (fsb -> fsb_cancelshared);
		    fsb -> fsb_cancelshared = NULLPE;
		}
		fsb -> fsb_canceldiags = NULL;
		fsb -> fsb_cancelndiag = 0;
	    }

	    if (fsb -> fsb_flags & FSB_CANCEL) {
		fsb -> fsb_flags &= ~FSB_CANCEL;
		fsb -> fsb_state = FSB_DATAIDLE;
	    }
	    else
		fsb -> fsb_state = FSB_DATACANCEL;
	    goto done;

	default:		/* a grouped request */
	    break;
    }

    if (!(fsb -> fsb_flags & FSB_INIT)
	    && ftg -> ftg_threshold != px -> px_ninfo - 2) {
	(void) fpktlose (fsb, fti, FS_PRO_ERRPROC, NULLCP,
		"threshold mismatch; expecting %d, found %d",
		px -> px_ninfo - 2, ftg -> ftg_threshold);
	goto out;
    }

    if (ftg -> ftg_flags & (FTG_SELECT | FTG_CREATE)) {
	if ((fsb -> fsb_flags & FSB_INIT)
		? (fsb -> fsb_state == FSB_MANAGEMENT)
		: (ftg -> ftg_flags & (FTG_DESELECT | FTG_DELETE))) {
	    if (!(fsb -> fsb_flags & FSB_INIT))
		switch (fsb -> fsb_class) {
		    case FCLASS_MANAGE:
		    case FCLASS_TM:
		    case FCLASS_ACCESS:
		        break;

		    default:
		        goto unexpected_group;
		}

	    fti -> fti_type = FTI_MANAGEMENT;

	    if (fsb -> fsb_flags & FSB_INIT) {
		if (ftg -> ftg_flags & ~fsb -> fsb_group) {
		    (void) fpktlose (fsb, fti, FS_PRO_ERRPROC, NULLCP,
			    "management reply mismatch; expecting 0x%x, found 0x%x",
			    fsb -> fsb_group, ftg -> ftg_flags);
		    goto out;
		}
		fsb -> fsb_state = FSB_INITIALIZED;
	    }
	    else {
		if (fsb -> fsb_state != FSB_INITIALIZED)
		    goto unexpected_group;
		if ((ftg -> ftg_flags & FTG_SELECT)
			? ftg -> ftg_select.ftse_account
			: ftg -> ftg_create.ftce_account)
		    fsb -> fsb_flags |= FSB_DECHARGE;
		else
		    fsb -> fsb_flags &= ~FSB_DECHARGE;
		fsb -> fsb_state = FSB_MANAGEMENT;
		fsb -> fsb_group = ftg -> ftg_flags;
	    }

	    goto done;
	}

	if ((fsb -> fsb_flags & FSB_INIT)
	        ? (fsb -> fsb_state == FSB_BULKBEGIN)
		: (ftg -> ftg_flags & FTG_OPEN)) {
	    if (!(fsb -> fsb_flags & FSB_INIT))
		switch (fsb -> fsb_class) {
		    case FCLASS_TRANSFER: 
		    case FCLASS_TM: 
		    case FCLASS_ACCESS: 
		        break;

		    default: 
		        goto unexpected_group;
		}

	    fti -> fti_type = FTI_BULKBEGIN;

	    if (fsb -> fsb_flags & FSB_INIT) {
		int	state;

		if (ftg -> ftg_flags & ~fsb -> fsb_group) {
		    (void) fpktlose (fsb, fti, FS_PRO_ERRPROC, NULLCP,
			    "bulk transfer reply mismatch; expecting 0x%x found 0x%x",
			    fsb -> fsb_group, ftg -> ftg_flags);
		    goto out;
		}
		if (ftg -> ftg_flags & FTG_SELECT)
		    state = ftg -> ftg_select.ftse_state;
		else
		    state = ftg -> ftg_create.ftce_state;
		if (state != FSTATE_SUCCESS
			|| ftg -> ftg_open.ftop_state != FSTATE_SUCCESS)
		    fsb -> fsb_state = FSB_INITIALIZED;
		else
		    fsb -> fsb_state = FSB_DATAIDLE;
	    }
	    else {
		if (fsb -> fsb_state != FSB_INITIALIZED)
		    goto unexpected_group;
		if ((ftg -> ftg_flags & FTG_SELECT)
			? ftg -> ftg_select.ftse_account
			: ftg -> ftg_create.ftce_account)
		    fsb -> fsb_flags |= FSB_DECHARGE;
		else
		    fsb -> fsb_flags &= ~FSB_DECHARGE;
		fsb -> fsb_state = FSB_BULKBEGIN;
		fsb -> fsb_group = ftg -> ftg_flags;
	    }

	    goto done;
	}

	goto unexpected_group;
    }

    if (ftg -> ftg_flags & FTG_CLOSE) {
	switch (fsb -> fsb_class) {
	    case FCLASS_TRANSFER: 
	    case FCLASS_TM: 
	    case FCLASS_ACCESS: 
		break;

	    default: 
		goto unexpected_group;
	}

	fti -> fti_type = FTI_BULKEND;

	if (fsb -> fsb_flags & FSB_INIT) {
	    if (fsb -> fsb_state != FSB_BULKEND)
		goto unexpected_group;
	    if (ftg -> ftg_flags & ~fsb -> fsb_group) {
		(void) fpktlose (fsb, fti, FS_PRO_ERRPROC, NULLCP,
			"bulk transfer reply mismatch; expecting 0x%x found 0x%x",
			fsb -> fsb_group, ftg -> ftg_flags);
		goto out;
	    }
	    fsb -> fsb_state = FSB_INITIALIZED;
	}
	else {
	    if (fsb -> fsb_state != FSB_DATAIDLE)
		goto unexpected_group;
	    fsb -> fsb_state = FSB_BULKEND;
	    fsb -> fsb_group = ftg -> ftg_flags;
	}

	goto done;
    }

unexpected_group: ;
    (void) fpktlose (fsb, fti, FS_PRO_ERR, NULLCP,
		"unexpected group type 0x%x; state=0x%x", ftg -> ftg_flags,
		fsb -> fsb_state);
    goto out;

done: ;
    PXFREE (px);
    return DONE;

out: ;
    if (pdu)
	free_FTAM_PDU (pdu);
    switch (fti -> fti_type) {
	case FTI_ACCESS:
	    FTACFREE (&fti -> fti_access);
	    break;

	case FTI_READWRITE:
	    FTRWFREE (&fti -> fti_readwrite);
	    break;

	case FTI_TRANSEND:
	    FTREFREE (&fti -> fti_transend);
	    break;

	case FTI_CANCEL:
	    FTCNFREE (&fti -> fti_cancel);
	    break;

	case FTI_FINISH:
	case FTI_MANAGEMENT:
	case FTI_BULKBEGIN:
	case FTI_BULKEND:
	    FTGFREE (ftg);
	    break;

	default:
	    break;
    }
    PXFREE (px);

    freefsblk (fsb);
    return NOTOK;
}

/* \f

 */

static int  doPStokens (fsb, pt, fti)
register struct ftamblk   *fsb;
register struct PSAPtoken *pt;
struct FTAMindication *fti;
{
    (void) fpktlose (fsb, fti, FS_PRO_ERR, NULLCP,
	    "unexpected token indication (0x%x)", pt -> pt_type);
    PTFREE (pt);

    freefsblk (fsb);
    return NOTOK;
}

/* \f

 */

static int  doPSsync (fsb, pn, fti)
register struct ftamblk   *fsb;
register struct PSAPsync *pn;
struct FTAMindication *fti;
{
    register int i;
    struct PSAPdata pxs;
    register struct PSAPdata *px = &pxs;

    switch (pn -> pn_type) {
	case SN_RESETCNF:
		break;
	case SN_RESETIND:
	    if (pn -> pn_options == SYNC_ABANDON)
		break;		/* else fall */

	default:
	    (void) fpktlose (fsb, fti, FS_PRO_ERR, NULLCP,
			"unexpected sync indication (0x%x)", pn -> pn_type);
	    PNFREE (pn);

	    freefsblk (fsb);
	    return NOTOK;
    }

    fsb -> fsb_settings = pn -> pn_settings;
#define dotoken(requires,shift,bit,type) \
{ \
    if (fsb -> fsb_srequirements & requires) \
	switch (fsb -> fsb_settings & (ST_MASK << shift)) { \
	    default: \
		fsb -> fsb_settings &= ~(ST_MASK << shift); \
		fsb -> fsb_settings |= ST_INIT_VALUE << shift; \
 \
	    case ST_INIT_VALUE << shift: \
		fsb -> fsb_owned |= bit; \
		fsb -> fsb_avail |= bit; \
		break; \
 \
	    case ST_RESP_VALUE << shift: \
		fsb -> fsb_avail |= bit; \
		break; \
	} \
}
    dotokens ();
#undef	dotoken

    if (pn -> pn_type == SN_RESETCNF && pn -> pn_ninfo == 0) {
	register struct FTAMcancel *ftcn = &fti -> fti_cancel;

	bzero ((char *) ftcn, sizeof *ftcn);
	ftcn -> ftcn_action = FACTION_SUCCESS;/* what else can be done? */

	fsb -> fsb_flags &= ~FSB_CANCEL;
	fsb -> fsb_state = FSB_DATAIDLE;

	PNFREE (pn);
	return DONE;
    }

    bzero ((char *) px, sizeof *px);
    for (i = pn -> pn_ninfo - 1; i >= 0; i--) {
	px -> px_info[i] = pn -> pn_info[i];
	pn -> pn_info[i] = NULLPE;
    }
    px -> px_ninfo = pn -> pn_ninfo;
    PNFREE (pn);

    return doPSdata (fsb, px, fti);
}

/* \f

 */

static int  doPSactivity (fsb, pv, fti)
register struct ftamblk   *fsb;
register struct PSAPactivity *pv;
struct FTAMindication *fti;
{
    (void) fpktlose (fsb, fti, FS_PRO_ERR, NULLCP,
	    "unexpected activity indication (0x%x)", pv -> pv_type);
    PVFREE (pv);

    freefsblk (fsb);
    return NOTOK;
}

/* \f

 */

static int  doPSreport (fsb, pp, fti)
register struct ftamblk   *fsb;
register struct PSAPreport *pp;
struct FTAMindication *fti;
{
    (void) fpktlose (fsb, fti, FS_PRO_ERR, NULLCP,
	    "unexpected exception report indication (0x%x)", pp -> pp_peer);
    PPFREE (pp);

    freefsblk (fsb);
    return NOTOK;
}

/* \f

 */

static int  doPSfinish (fsb, pf, fti)
register struct ftamblk   *fsb;
register struct PSAPfinish *pf;
struct FTAMindication *fti;
{
    PE	    pe;
    struct AcSAPindication  acis;
    register struct AcSAPabort *aca = &acis.aci_abort;
    register struct AcSAPfinish *acf = &acis.aci_finish;
    struct type_FTAM_PDU *pdu;
    register struct type_FTAM_F__TERMINATE__request *req;

    pdu = NULL;
    if ((fsb -> fsb_flags & FSB_INIT) || fsb -> fsb_state != FSB_INITIALIZED) {
	(void) fpktlose (fsb, fti, FS_ACS_MGMT, NULLCP,
		"association management botched");
	PFFREE (pf);
	goto out1;
    }

    if (AcFINISHser (fsb -> fsb_fd, pf, &acis) == NOTOK) {
	(void) acs2ftamlose (fsb, fti, "AcFINISHser", aca);
	goto out1;
    }

    if (acf -> acf_ninfo < 1 || (pe = acf -> acf_info[0]) == NULLPE) {
	(void) fpktlose (fsb, fti, FS_PRO_ERR, NULLCP, NULLCP);
	goto out2;
    }

    if (decode_FTAM_PDU (pe, 1, NULLIP, NULLVP, &pdu) == NOTOK) {
	(void) fpktlose (fsb, fti, FS_PRO_ERRMSG, NULLCP,
			 "unable to parse PDU: %s", PY_pepy);
	goto out2;
    }
    if (pdu -> offset != type_FTAM_PDU_f__terminate__request) {
	(void) fpktlose (fsb, fti, FS_PRO_ERRPROC, NULLCP,
			 "expecting F-TERMINATE-request, got %d",
			 pdu -> offset);
	goto out2;
    }
    req = pdu -> un.f__terminate__request;

    fsbtrace (fsb, (fsb -> fsb_fd, "A-RELEASE.INDICATION",
		"F-TERMINATE-request", pe, 1));

    ACFFREE (acf);

    fti -> fti_type = FTI_FINISH;
    {
	register struct FTAMfinish *ftf = &fti -> fti_finish;

	bzero ((char *) ftf, sizeof *ftf);
	if (req && fpm2shared (fsb, req, &ftf -> ftf_sharedASE, fti) == NOTOK)
	    goto out2;
    }
    fsb -> fsb_flags |= FSB_FINN;

    free_FTAM_PDU (pdu);
    return DONE;

out2: 	;
    ACFFREE (acf);
out1: 	;
    if (pdu)
	free_FTAM_PDU (pdu);
    freefsblk (fsb);
    return NOTOK;
}

/* \f

 */

static int  doPSabort (fsb, pa, fti)
register struct ftamblk *fsb;
register struct PSAPabort *pa;
struct FTAMindication *fti;
{
    struct AcSAPindication  acis;
    register struct AcSAPabort *aca = &acis.aci_abort;

    if (!pa -> pa_peer && pa -> pa_reason == PC_TIMER)
	return ftamlose (fti, FS_PRO_TIMEOUT, 0, NULLCP, NULLCP);

    if (AcABORTser (fsb -> fsb_fd, pa, &acis) == NOTOK) {
	(void) acs2ftamlose (fsb, fti, "AcABORTser", aca);
	fsb -> fsb_fd = NOTOK;
	freefsblk (fsb);

	return NOTOK;
    }

    return acs2ftamabort (fsb, aca, fti);
}

/* \f

 */

static int  psDATAser (sd, px)
int	sd;
register struct PSAPdata *px;
{
    IFP	    handler;
    register struct ftamblk   *fsb;
    struct FTAMindication  ftis;
    register struct FTAMindication *fti = &ftis;

    if ((fsb = findfsblk (sd)) == NULL)
	return;
    handler = fsb -> fsb_indication;

    if (doPSdata (fsb, px, fti) != OK)
	(*handler) (sd, fti);
}

/* \f

 */

static int  psTOKENser (sd, pt)
int	sd;
register struct PSAPtoken *pt;
{
    IFP	    handler;
    register struct ftamblk   *fsb;
    struct FTAMindication  ftis;
    register struct FTAMindication *fti = &ftis;

    if ((fsb = findfsblk (sd)) == NULL)
	return;
    handler = fsb -> fsb_indication;

    if (doPStokens (fsb, pt, fti) != OK)
	(*handler) (sd, fti);
}

/* \f

 */

static int  psSYNCser (sd, pn)
int	sd;
register struct PSAPsync *pn;
{
    IFP	    handler;
    register struct ftamblk   *fsb;
    struct FTAMindication  ftis;
    register struct FTAMindication *fti = &ftis;

    if ((fsb = findfsblk (sd)) == NULL)
	return;
    handler = fsb -> fsb_indication;

    if (doPSsync (fsb, pn, fti) != OK)
	(*handler) (sd, fti);
}

/* \f

 */

static int  psACTIVITYser (sd, pv)
int	sd;
register struct PSAPactivity *pv;
{
    IFP	    handler;
    register struct ftamblk   *fsb;
    struct FTAMindication  ftis;
    register struct FTAMindication *fti = &ftis;

    if ((fsb = findfsblk (sd)) == NULL)
	return;
    handler = fsb -> fsb_indication;

    if (doPSactivity (fsb, pv, fti) != OK)
	(*handler) (sd, fti);
}

/* \f

 */

static int  psREPORTser (sd, pp)
int	sd;
register struct PSAPreport *pp;
{
    IFP	    handler;
    register struct ftamblk   *fsb;
    struct FTAMindication  ftis;
    register struct FTAMindication *fti = &ftis;

    if ((fsb = findfsblk (sd)) == NULL)
	return;
    handler = fsb -> fsb_indication;

    if (doPSreport (fsb, pp, fti) != OK)
	(*handler) (sd, fti);
}

/* \f

 */

static int  psFINISHser (sd, pf)
int	sd;
struct PSAPfinish *pf;
{
    IFP	    handler;
    register struct ftamblk   *fsb;
    struct FTAMindication  ftis;
    register struct FTAMindication *fti = &ftis;

    if ((fsb = findfsblk (sd)) == NULL)
	return;
    handler = fsb -> fsb_indication;

    if (doPSfinish (fsb, pf, fti) != OK)
	(*handler) (sd, fti);
}

/* \f

 */

static int  psABORTser (sd, pa)
int	sd;
register struct PSAPabort *pa;
{
    IFP	    handler;
    register struct ftamblk   *fsb;
    struct FTAMindication  ftis;
    register struct FTAMindication *fti = &ftis;

    if ((fsb = findfsblk (sd)) == NULL)
	return;
    handler = fsb -> fsb_indication;

    if (doPSabort (fsb, pa, fti) != OK)
	(*handler) (sd, fti);
}

/* \f

   define vector for INDICATION events */

#define	e(i)	(indication ? (i) : NULLIFP)


int	FSetIndications (sd, indication, fti)
int	sd;
IFP	indication;
struct FTAMindication *fti;
{
    SBV     smask;
    register struct ftamblk *fsb;
    struct PSAPindication   pis;
    register struct PSAPabort  *pa = &pis.pi_abort;

    missingP (fti);

    smask = sigioblock ();

    ftamPsig (fsb, sd);

    if (PSetIndications (fsb -> fsb_fd, e (psDATAser), e (psTOKENser),
		e (psSYNCser), e (psACTIVITYser), e (psREPORTser),
		e (psFINISHser), e (psABORTser), &pis) == NOTOK)
	switch (pa -> pa_reason) {
	    case PC_WAITING: 
		(void) sigiomask (smask);
		return ftamlose (fti, FS_GEN_WAITING, 0, NULLCP, NULLCP);

	    default: 
		(void) ps2ftamlose (fsb, fti, "PSetIndications", pa);
		freefsblk (fsb);
		(void) sigiomask (smask);
		return NOTOK;
	}

    if (fsb -> fsb_indication = indication)
	fsb -> fsb_flags |= FSB_ASYN;
    else
	fsb -> fsb_flags &= ~FSB_ASYN;

    (void) sigiomask (smask);

    return OK;
}

#undef	e

/* \f

   AcSAP interface */

int	acs2ftamlose (fsb, fti, event, aca)
register struct ftamblk *fsb;
struct FTAMindication *fti;
char   *event;
register struct AcSAPabort *aca;
{
    int     observer,
            reason;
    char   *cp,
            buffer[BUFSIZ];

    if (fsb && fsb -> fsb_trace && event) {
	cp = buffer;
	(void) sprintf (cp, "%s: %s", event, AcErrString (aca -> aca_reason));
	if (aca -> aca_cc > 0) {
	    cp += strlen (cp);
	    (void) sprintf (cp, " [%*.*s]", aca -> aca_cc, aca -> aca_cc,
		    aca -> aca_data);
	}

	fsbtrace (fsb, (fsb -> fsb_fd, buffer, NULLCP, NULLPE, -1));
    }

    cp = "";
    switch (aca -> aca_reason) {
	case ACS_ADDRESS: 
	    reason = FS_PRO_LOWADDR;
	    (void) sprintf (cp = buffer, " (%s)", AcErrString (ACS_ADDRESS));
	    break;

	case ACS_REFUSED: 
	    reason = FS_PRO_LOWFAIL;
	    (void) sprintf (cp = buffer, " (%s)", AcErrString (ACS_REFUSED));
	    break;

	default: 
	    (void) sprintf (cp = buffer, " (%s at association control)",
		    AcErrString (aca -> aca_reason));
	case ACS_CONGEST: 
	case ACS_PARAMETER: 
	case ACS_OPERATION: 
	case ACS_PRESENTATION: 
	    reason = FS_PRO_LOWFAIL;
	    break;
    }

    if (fsb) {
	if (fsb -> fsb_flags & FSB_INIT)
	    observer = EREF_IFPM;
	else
	    observer = EREF_RFPM;
    }
    else
	observer = EREF_NONE;

    if (aca -> aca_cc > 0)
	return ftamoops (fti, reason, ACS_FATAL (aca -> aca_reason), observer,
		EREF_NONE, NULLCP, "%*.*s%s", aca -> aca_cc, aca -> aca_cc,
		aca -> aca_data, cp);
    else
	return ftamoops (fti, reason, ACS_FATAL (aca -> aca_reason), observer,
		EREF_NONE, NULLCP, "%s", *cp ? cp + 1 : cp);
}

/* \f

 */

int	acs2ftamabort (fsb, aca, fti)
register struct ftamblk *fsb;
register struct AcSAPabort *aca;
struct FTAMindication *fti;
{
    int     peer;
    PE	    pe;
    register struct FTAMabort  *fta = &fti -> fti_abort;
    struct type_FTAM_PDU *pdu;
    register struct type_FTAM_F__U__ABORT__request *req;

    pdu = NULL;
    if (aca -> aca_source != ACA_USER) {
	(void) acs2ftamlose (fsb, fti, NULLCP, aca);
	goto out;
    }

    if (aca -> aca_ninfo < 1 || (pe = aca -> aca_info[0]) == NULLPE) {
	(void) ftamlose (fti, FS_PRO_ERR, 1, NULLCP, NULLCP);
	goto out;
    }

    if (decode_FTAM_PDU (pe, 1, NULLIP, NULLVP, &pdu) == NOTOK) {
	(void) ftamlose (fti, FS_PRO_ERRMSG, 1, NULLCP,
			 "unable to parse PDU: %s", PY_pepy);
	goto out;
    }
    switch (pdu -> offset) {
	case type_FTAM_PDU_f__u__abort__request:
	    peer = 1;
	    req = pdu -> un.f__u__abort__request;
	    break;

	case type_FTAM_PDU_f__p__abort__request:
	    peer = 0;	/* F-P-ABORT-request is identical... */
	    req = pdu -> un.f__u__abort__request;
	    break;

	default:
	    (void) ftamlose (fti, FS_PRO_ERRPROC, 1, NULLCP,
			     "expecting F-{U,P}-ABORT-request, got %d",
			     pdu -> offset);
	    goto out;
    }
    fsbtrace (fsb, (fsb -> fsb_fd, "A-ABORT.INDICATION",
		    pdu -> offset != type_FTAM_PDU_f__u__abort__request
		    	? "F-P-ABORT-request" : "F-U-ABORT-request",
		    pe, 1));

    fti -> fti_type = FTI_ABORT;

    fta -> fta_peer = peer;
    fta -> fta_action = req -> action__result ? req -> action__result -> parm
					      :int_FTAM_Action__Result_success;
    if (req -> diagnostic)
	(void) fpm2diag (fsb, req -> diagnostic, fta -> fta_diags,
			 &fta -> fta_ndiag, fti);

out: ;
    ACAFREE (aca);
    if (pdu)
	free_FTAM_PDU (pdu);

    fsb -> fsb_fd = NOTOK;
    freefsblk (fsb);

    return NOTOK;
}

/* \f

   PSAP interface */

int	ps2ftamlose (fsb, fti, event, pa)
register struct ftamblk *fsb;
struct FTAMindication *fti;
char   *event;
register struct PSAPabort *pa;
{
    int     observer,
            reason;
    char   *cp,
            buffer[BUFSIZ];

    if (fsb && fsb -> fsb_trace && event) {
	cp = buffer;
	(void) sprintf (cp, "%s: %s", event, PErrString (pa -> pa_reason));
	if (pa -> pa_cc > 0) {
	    cp += strlen (cp);
	    (void) sprintf (cp, " [%*.*s]", pa -> pa_cc, pa -> pa_cc,
		    pa -> pa_data);
	}

	fsbtrace (fsb, (fsb -> fsb_fd, buffer, NULLCP, NULLPE, -1));
    }

    cp = "";
    switch (pa -> pa_reason) {
	case PC_PARAMETER: 
	case PC_OPERATION: 
	default:
	    (void) sprintf (cp = buffer, " (%s at presentation)",
		    PErrString (pa -> pa_reason));
	case PC_CONGEST: 
	case PC_SESSION: 
	    reason = FS_PRO_LOWFAIL;
	    break;
    }

    if (fsb) {
	if (fsb -> fsb_flags & FSB_INIT)
	    observer = EREF_IFPM;
	else
	    observer = EREF_RFPM;
    }
    else
	observer = EREF_NONE;

    if (pa -> pa_cc > 0)
	return ftamoops (fti, reason, PC_FATAL (pa -> pa_reason), observer,
		EREF_NONE, NULLCP, "%*.*s%s", pa -> pa_cc, pa -> pa_cc,
		pa -> pa_data, cp);
    else
	return ftamoops (fti, reason, PC_FATAL (pa -> pa_reason), observer,
		EREF_NONE, NULLCP, "%s", *cp ? cp + 1 : cp);
}

/* \f

   INTERNAL */

struct ftamblk *newfsblk () {
    register struct ftamblk *fsb;

    fsb = (struct ftamblk  *) calloc (1, sizeof *fsb);
    if (fsb == NULL)
	return NULL;

    fsb -> fsb_fd = NOTOK;

    if (once_only == 0) {
	FSHead -> fsb_forw = FSHead -> fsb_back = FSHead;
	once_only++;
    }

    insque (fsb, FSHead -> fsb_back);

    return fsb;
}

/* \f

 */

freefsblk (fsb)
register struct ftamblk *fsb;
{
    register int    i;
    register struct PSAPcontext *pp;
    register struct FTAMcontent *fcont;

    if (fsb == NULL)
	return;

    if (fsb -> fsb_fd != NOTOK) {
	struct AcSAPindication  acis;

	fsbtrace (fsb, (fsb -> fsb_fd, "A-ABORT.REQUEST(discard)",
		NULLCP, NULLPE, 0));

	(void) AcUAbortRequest (fsb -> fsb_fd, NULLPEP, 0, &acis);
    }

    if (fsb -> fsb_context)
	oid_free (fsb -> fsb_context), fsb -> fsb_context = NULLOID;

    for (pp = fsb -> fsb_contexts.pc_ctx, i = fsb -> fsb_contexts.pc_nctx - 1;
	    i >= 0; 
	    pp++, i--) {
	if (pp -> pc_asn)
	    oid_free (pp -> pc_asn);
    }
    fsb -> fsb_contexts.pc_nctx = 0;

    for (fcont = fsb -> fsb_contents.fc_contents,
	 	i = fsb -> fsb_contents.fc_ncontent - 1;
	     i >= 0;
	     fcont++, i--) {
	if (fcont -> fc_dtn)
	    oid_free (fcont -> fc_dtn);
    }
    fsb -> fsb_contents.fc_ncontent = 0;

    if (fsb -> fsb_cancelshared)
	pe_free (fsb -> fsb_cancelshared);

    remque (fsb);

    free ((char *) fsb);
}

/* \f

 */

struct ftamblk   *findfsblk (sd)
register int sd;
{
    register struct ftamblk *fsb;

    if (once_only == 0)
	return NULL;

    for (fsb = FSHead -> fsb_forw; fsb != FSHead; fsb = fsb -> fsb_forw)
	if (fsb -> fsb_fd == sd)
	    return fsb;

    return NULL;
}