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 t

⟦e859c3e54⟧ TextFile

    Length: 43775 (0xaaff)
    Types: TextFile
    Names: »tsdu2spkt.c«

Derivation

└─⟦2d1937cfd⟧ Bits:30007241 EUUGD22: P.P 5.0
    └─⟦35176feda⟧ »EurOpenD22/isode/isode-6.tar.Z« 
        └─⟦de7628f85⟧ 
            └─⟦this⟧ »isode-6.0/ssap/tsdu2spkt.c« 

TextFile

/* tsdu2spkt.c - read/write a SPDU to a TSDU */

#ifndef	lint
static char *rcsid = "$Header: /f/osi/ssap/RCS/tsdu2spkt.c,v 7.0 89/11/23 22:25:55 mrose Rel $";
#endif

/* 
 * $Header: /f/osi/ssap/RCS/tsdu2spkt.c,v 7.0 89/11/23 22:25:55 mrose Rel $
 *
 *
 * $Log:	tsdu2spkt.c,v $
 * Revision 7.0  89/11/23  22:25:55  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 "spkt.h"
#include "tailor.h"

/* \f

 */

struct	local_buf {
	char *top;				/* Top of buffer */
	char *ptr;				/* Pointer to working buffer */
	int pgi;				/* Offset of last PGI li */
	int left;				/* Number of bytes left */
	int li;					/* Running spdu length */
	int allocli;				/* Allocated li */
	int len;				/* Current buffer size */
};

/* \f

 */

#define PMASK_NODATA		0x000000
#define	PMASK_CN_ID		0x000001	/*   1: Connection ID */
#define	PMASK_CN_ITEMS		0x000002	/*   5: Connect/Accept Item */
#define	PMASK_SYNC		0x000004	/*  15: Sync Type Item */
#define	PMASK_TOKEN		0x000008	/*  16: Token Item */
#define	PMASK_TDISC		0x000010	/*  17: Transport Disc */
#define	PMASK_USER_REQ		0x000020	/*  20: Session User Req */
#define	PMASK_VERSION		0x000040	/*  22: Version Number */
#define	PMASK_PREPARE		0x000080	/*  24: Prepare type */
#define	PMASK_ENCLOSE		0x000100	/*  25: Enclosure Item */
#define PMASK_TOKEN_SET		0x000200	/*  26: Token Setting Item */
#define	PMASK_RESYNC		0x000400	/*  27: Resync type */
#define	PMASK_LINK		0x000800	/*  33: Linking information */
#define	PMASK_ACT_ID		0x001000	/*  41: Activity ID */
#define	PMASK_SERIAL		0x002000 	/*  42: Serial Number */
#define	PMASK_MIA_DATA		0x004000	/*  46: MIA User Data */
#define	PMASK_REFLECT		0x008000	/*  49: Reflect parameter */
#define	PMASK_REASON		0x010000	/*  50: Refusal Reason */
#define	PMASK_SSAP_CALLING	0x020000	/*  51: Calling SSAP ID */
#define	PMASK_SSAP_CALLED	0x040000	/*  52: Called SSAP ID */
#define	PMASK_UDATA		0x080000	/* 193: User data */
#define	PMASK_XDATA		0x100000	/* 194: Extended user data */

#define PMASK_VARLEN		0x800000	/* PI is Variable Len */
#define PMASK_NOTSUPPORTED	-1		/* Type not supported */


static int si_table[] = {
	PMASK_REFLECT,				/* 0x00: SPDU_ER */
	PMASK_ENCLOSE				/* 0x01: SPDU_GT & SPDU_DT */
	    | PMASK_TOKEN,
	PMASK_TOKEN				/* 0x02: SPDU_PT */
	    | PMASK_ENCLOSE
	    | PMASK_UDATA,
	PMASK_NOTSUPPORTED,			/* 0x03 */
	PMASK_NOTSUPPORTED,			/* 0x04 */
	PMASK_NODATA,				/* 0x05: SPDU_EX */
	PMASK_NOTSUPPORTED,			/* 0x06 */
	PMASK_PREPARE,				/* 0x07: SPDU_PR */
	PMASK_ENCLOSE				/* 0x08: SPDU_NF */
	    | PMASK_UDATA,
	PMASK_TDISC				/* 0x09: SPDU_FN */
	    | PMASK_ENCLOSE
	    | PMASK_UDATA,
	PMASK_ENCLOSE				/* 0x0a: SPDU_DN */
	    | PMASK_UDATA,
	PMASK_NOTSUPPORTED,			/* 0x0b */
	PMASK_CN_ID				/* 0x0c: SPDU_RF */
	    | PMASK_TDISC	
	    | PMASK_USER_REQ
	    | PMASK_VERSION
	    | PMASK_ENCLOSE
	    | PMASK_REASON,
	PMASK_CN_ID				/* 0x0d: SPDU_CN */
	    | PMASK_CN_ITEMS	
	    | PMASK_USER_REQ
	    | PMASK_VERSION
	    | PMASK_SSAP_CALLING
	    | PMASK_SSAP_CALLED
	    | PMASK_UDATA
	    | PMASK_XDATA,
	PMASK_CN_ID				/* 0x0e: SPDU_AC */
	    | PMASK_CN_ITEMS	
	    | PMASK_USER_REQ
	    | PMASK_VERSION
	    | PMASK_SSAP_CALLING
	    | PMASK_TOKEN
	    | PMASK_ENCLOSE
	    | PMASK_SSAP_CALLED
	    | PMASK_UDATA,
	PMASK_NOTSUPPORTED,			/* 0x0f */
	PMASK_NOTSUPPORTED,			/* 0x10 */
	PMASK_NOTSUPPORTED,			/* 0x11 */
	PMASK_NOTSUPPORTED,			/* 0x12 */
	PMASK_NOTSUPPORTED,			/* 0x13 */
	PMASK_NOTSUPPORTED,			/* 0x14 */
	PMASK_NODATA,				/* 0x15: SPDU_GTC */
	PMASK_NODATA,				/* 0x16: SPDU_GTA */
	PMASK_NOTSUPPORTED,			/* 0x17 */
	PMASK_NOTSUPPORTED,			/* 0x18 */
	PMASK_TDISC				/* 0x19: SPDU_AB & SPDU_AI */
	    | PMASK_REFLECT	
	    | PMASK_REASON
	    | PMASK_ENCLOSE
	    | PMASK_UDATA,
	PMASK_NODATA,				/* 0x1a: SPDU_AA & SPDU_AIA */
	PMASK_NOTSUPPORTED,			/* 0x1b */
	PMASK_NOTSUPPORTED,			/* 0x1c */
	PMASK_LINK				/* 0x1d: SPDU_AR */
	    | PMASK_ACT_ID
	    | PMASK_ENCLOSE
	    | PMASK_SERIAL
	    | PMASK_UDATA,			
	PMASK_NOTSUPPORTED,			/* 0x1e */
	PMASK_NOTSUPPORTED,			/* 0x1f */
	PMASK_NOTSUPPORTED,			/* 0x20 */
	PMASK_ENCLOSE,				/* 0x21: SPDU_TD */
	PMASK_TOKEN_SET				/* 0x22: SPDU_RA */
	    | PMASK_ENCLOSE
	    | PMASK_SERIAL	
	    | PMASK_UDATA,
	PMASK_NOTSUPPORTED,			/* 0x23 */
	PMASK_NOTSUPPORTED,			/* 0x24 */
	PMASK_NOTSUPPORTED,			/* 0x25 */
	PMASK_NOTSUPPORTED,			/* 0x26 */
	PMASK_NOTSUPPORTED,			/* 0x27 */
	PMASK_NOTSUPPORTED,			/* 0x28 */
	PMASK_SYNC				/* 0x29: SPDU_MAP & SPDU_AE */
	    | PMASK_ENCLOSE
	    | PMASK_SERIAL	
	    | PMASK_UDATA,
	PMASK_ENCLOSE				/* 0x2a: SPDU_MAA & SPDU_AEA */
	    | PMASK_SERIAL
	    | PMASK_UDATA,
	PMASK_NOTSUPPORTED,			/* 0x2b */
	PMASK_NOTSUPPORTED,			/* 0x2c */
	PMASK_ENCLOSE				/* 0x2d: SPDU_AS */
	    | PMASK_ACT_ID
	    | PMASK_UDATA,
	PMASK_NOTSUPPORTED,			/* 0x2e */
	PMASK_NOTSUPPORTED,			/* 0x2f */
	PMASK_ENCLOSE				/* 0x30: SPDU_ED */
	    | PMASK_REASON				
	    | PMASK_UDATA,
	PMASK_SYNC				/* 0x31: SPDU_MIP */
	    | PMASK_ENCLOSE	
	    | PMASK_SERIAL	
	    | PMASK_UDATA,			
	PMASK_ENCLOSE				/* 0x32: SPDU_MIA */
	    | PMASK_SERIAL				
	    | PMASK_MIA_DATA,
	PMASK_NOTSUPPORTED,			/* 0x33 */
	PMASK_NOTSUPPORTED,			/* 0x34 */
	PMASK_TOKEN_SET				/* 0x35: SPDU_RS */
	    | PMASK_ENCLOSE	
	    | PMASK_RESYNC	
	    | PMASK_SERIAL
	    | PMASK_UDATA,
	PMASK_NOTSUPPORTED,			/* 0x36 */
	PMASK_NOTSUPPORTED,			/* 0x37 */
	PMASK_NOTSUPPORTED,			/* 0x38 */
	PMASK_REASON,				/* 0x39: SPDU_AD */
	PMASK_NODATA,				/* 0x3a: SPDU_ADA */
	PMASK_NOTSUPPORTED,			/* 0x3b */
	PMASK_NOTSUPPORTED,			/* 0x3c */
	PMASK_ENCLOSE				/* 0x3d: SPDU_CD */
	    | PMASK_UDATA,
	PMASK_ENCLOSE				/* 0x3e: SPDU_CDA */
	    | PMASK_UDATA
};
#define	SI_TABLE_LEN		((sizeof si_table) / (sizeof si_table[0]))

/* \f

 */

#define	PGI_CN_ID		1
#define		PI_CALLED_SS	9
#define		PI_CALLING_SS	10
#define		PI_COMMON_REF	11
#define		PI_ADD_INFO	12
#define	PGI_CN_ITEMS		5
#define		PI_PROTOCOL_OPT	19
#define		PI_TSDU_MAXSIZ	21
#define		PI_VERSION	22
#define		PI_ISN		23
#define		PI_TOKEN_SET	26
#define		PI_ISN2		55
#define	PI_SYNC			15
#define	PI_TOKEN		16
#define	PI_TDISC		17
#define	PI_USER_REQ		20
#define	PI_PREPARE		24
#define	PI_ENCLOSE		25
#define	PI_RESYNC		27
#define	PGI_AR_LINK		33
#define		PI_AR_CALLED	9
#define		PI_AR_CALLING	10
#define		PI_AR_COMMON	11
#define		PI_AR_ADDT	12
#define		PI_AR_OLD	41
#define		PI_AR_SERIAL	42
#define	PI_ACT_ID		41
#define	PI_SERIAL		42
#define	PI_MIA_DATA		46
#define	PI_REFLECT		49
#define	PI_REASON		50
#define	PI_SSAP_CALLING		51
#define	PI_SSAP_CALLED		52
#define	PI_UDATA		193
#define	PI_XDATA		194


static int pi_table[] = {
	0,					/* 0x00 */
	PMASK_VARLEN | PMASK_CN_ID,		/* 0x01: Connection ID */
	0, 0, 0,				/* 0x02-04 */
	PMASK_VARLEN | PMASK_CN_ITEMS,		/* 0x05: Connect/Accept Item */
	0, 0, 0,				/* 0x06-08 */
	PMASK_VARLEN | PMASK_CN_ID | PMASK_LINK,/* 0x09: Called Session SS */
	PMASK_VARLEN | PMASK_CN_ID | PMASK_LINK,/* 0x0a: Calling Session SS */
	PMASK_VARLEN | PMASK_CN_ID | PMASK_LINK,/* 0x0b: Common Reference */
	PMASK_VARLEN | PMASK_CN_ID | PMASK_LINK,/* 0x0c: Additional Info */
	0, 0,					/* 0x0d-0e */
	PMASK_SYNC,				/* 0x0f: Sync Type Item */
	PMASK_TOKEN,				/* 0x10: Token Item */
	PMASK_TDISC,				/* 0x11: Transport Disc */
	0,					/* 0x12 */
	PMASK_CN_ITEMS,				/* 0x13: Protocol Option */
	PMASK_USER_REQ,				/* 0x14: Session User Req */
	PMASK_VARLEN | PMASK_CN_ITEMS,		/* 0x15: TSDU Max Size */
	PMASK_VERSION,				/* 0x16: Version Number */
	PMASK_VARLEN | PMASK_CN_ITEMS,		/* 0x17: Initial Serial Num */
	PMASK_PREPARE,				/* 0x18: Prepare Type */
	PMASK_ENCLOSE,				/* 0x19: Enclosure Item */
	PMASK_CN_ITEMS | PMASK_TOKEN_SET,	/* 0x1a: Token setting item */
	PMASK_RESYNC,				/* 0x1b: Resync type */
	0, 0, 0, 0, 0,				/* 0x1c-20 */
	PMASK_VARLEN | PMASK_LINK,		/* 0x21: Activity Link */
	0, 0, 0, 0, 0, 0, 0,			/* 0x22-28 */
	PMASK_VARLEN | PMASK_ACT_ID,		/* 0x29: Activity ID */
	PMASK_VARLEN | PMASK_SERIAL,		/* 0x2a: Serial Number */
	0, 0, 0,				/* 0x2b-2d */
	PMASK_VARLEN | PMASK_MIA_DATA,		/* 0x2e: MIA User Data */
	0, 0,					/* 0x2f-30 */
	PMASK_VARLEN | PMASK_REFLECT,		/* 0x31: Reflect parameter */
	PMASK_VARLEN | PMASK_REASON,		/* 0x32: Refusal Reason */
	PMASK_VARLEN | PMASK_SSAP_CALLING,	/* 0x33: Calling SSAP ID */
	PMASK_VARLEN | PMASK_SSAP_CALLED,	/* 0x34: Called SSAP ID */
	0, 0,					/* 0x35-36 */
	PMASK_VARLEN | PMASK_CN_ITEMS		/* 0x17: 2nd initial s/n */
};
#define	PI_TABLE_LEN		((sizeof pi_table) / (sizeof pi_table[0]))

/* \f

 */

static int pi_length[PI_TABLE_LEN] = {
	0,					/* 0x00 */
	SREF_USER_SIZE				/* 0x01: Connection ID */
	    + SREF_COMM_SIZE
	    + SREF_ADDT_SIZE
	    + 6,
	0, 0, 0,				/* 0x02-04 */
	1 + 4 + 1 + 6 + 1 + 10,			/* 0x05: Connect/Accept Item */
	0, 0, 0,				/* 0x06-08 */
	SREF_USER_SIZE,				/* 0x09: Called Session SS */
	SREF_USER_SIZE,				/* 0x0a: Calling Session SS */
	SREF_COMM_SIZE,				/* 0x0b: Common Reference */
	SREF_ADDT_SIZE,				/* 0x0c: Additional Info */
	0, 0,					/* 0x0d-0e */
	1,					/* 0x0f: Sync Type Item */
	1,					/* 0x10: Token Item */
	1,					/* 0x11: Transport Disc */
	0,					/* 0x12 */
	1,					/* 0x13: Protocol Option */
	2,					/* 0x14: Session User Req */
	4,					/* 0x15: TSDU Max Size */
	1,					/* 0x16: Version Number */
	SIZE_CN_ISN,				/* 0x17: Initial Serial Num */
	1,					/* 0x18: Prepare Type */
	1,					/* 0x19: Enclosure Item */
	1,					/* 0x1a: Token setting item */
	1,					/* 0x1b: Resync type */
	0, 0, 0, 0, 0,				/* 0x1c-20 */
	2 * SREF_USER_SIZE			/* 0x21: Activity Link */
	    + SREF_COMM_SIZE
	    + SREF_ADDT_SIZE
	    + SID_DATA_SIZE
	    + SIZE_CN_ISN
	    + 6 * 2,
	0, 0, 0, 0, 0, 0, 0,			/* 0x22-28 */
	SID_DATA_SIZE,				/* 0x29: Activity ID */
	SIZE_CN_ISN,				/* 0x2a: Serial Number */
	0, 0, 0,				/* 0x2b-2d */
	SEGMENT_MAX /* MIA_SIZE */,		/* 0x2e: MIA User Data */
	0, 0,					/* 0x2f-30 */
	SEGMENT_MAX,				/* 0x31: Reflect parameter */
	RF_SIZE,				/* 0x32: Refusal Reason */
	SSSIZE,					/* 0x33: Calling SSAP ID */
	SSSIZE,					/* 0x34: Called SSAP ID */
	0, 0,					/* 0x35-36 */
	SIZE_CN_ISN,				/* 0x37: 2nd initial s/n */
};

/* \f

 */

#define	If_Set(flag)	if (s -> s_mask & (flag))
#define If_Reset(flag)	if (!(s -> s_mask & (flag)))
#define Set(flag) 	s -> s_mask |= (flag)
#define Reset(flag) 	s -> s_mask &= ~(flag)

#define Put_Item(code,value) \
	put2spdu((code), pi_length[(code)], (value), &c)

#define Put_Ref(r,code) \
{ \
    start_pgi (PGI_CN_ID, &c); \
    if (r.sr_ulen) \
	put2spdu (code, (int) r.sr_ulen, r.sr_udata, &c); \
    if (r.sr_clen) \
	put2spdu (PI_COMMON_REF, (int) r.sr_clen, r.sr_cdata, &c); \
    if (r.sr_alen) \
	put2spdu (PI_ADD_INFO, (int) r.sr_alen, r.sr_adata, &c); \
    end_pgi (&c); \
}

#define	Put_SSN(code,ssn) \
{ \
    if ((ssn) > SERIAL_MAX + 1) { \
	if (c.len) \
	    free (c.top); \
	s -> s_errno = SC_PROTOCOL; \
	return NOTOK; \
    } \
    (void) sprintf (isn, "%lu", (ssn)); \
    put2spdu ((code), strlen (isn), isn, &c); \
}

/* this used to check

	if (s -> s_ulen > (csize)) {
	    if (c.len)
		free (c.top);
	    s -> s_errno = SC_PROTOCOL;
	    return NOTOK;
	}

   but with version 2 session, there's really no point... */

#define Put_UData(csize) \
{ \
    if (s -> s_udata) { \
	put2spdu (PI_UDATA, s -> s_ulen, s -> s_udata, &c); \
    } \
}

#define Put_XData(csize) \
{ \
    if (s -> s_udata) { \
	put2spdu (s -> s_ulen > csize ? PI_XDATA : PI_UDATA, s -> s_ulen, \
		  s -> s_udata, &c); \
    } \
}

#define Put_MData(csize) \
{ \
    if (s -> s_udata) { \
	put2spdu (PI_MIA_DATA, s -> s_ulen, s -> s_udata, &c); \
    } \
}

/* \f

 */

static start_spdu (s, c, basesize)
struct	ssapkt *s;
struct	local_buf *c;
int basesize;
{
    if (s -> s_udata)
	switch (s -> s_code) {
	    case SPDU_DT: 	/* caller responsible for this... */
	    case SPDU_EX: 
	    case SPDU_TD: 
		break;

	    default: 
		if (s -> s_ulen)
		    basesize += s -> s_ulen + (s -> s_ulen > 254 ? 4 : 2);
		break;
	}

    switch (s -> s_code) {
	case SPDU_CN: 
	case SPDU_AC: 
	    If_Set (SMASK_CN_REF) {
		basesize += 2;
		if (s -> s_cn_reference.sr_ulen)
		    basesize += 2 + s -> s_cn_reference.sr_ulen;
		if (s -> s_cn_reference.sr_clen)
		    basesize += 2 + s -> s_cn_reference.sr_clen;
		if (s -> s_cn_reference.sr_alen)
		    basesize += 2 + s -> s_cn_reference.sr_alen;
	    }
	    If_Set (SMASK_CN_CALLING)
		basesize += s -> s_callinglen + 2;
	    If_Set (SMASK_CN_CALLED)
		basesize += s -> s_calledlen + 2;
	    break;

	case SPDU_RF: 
	    If_Set (SMASK_RF_REF) {
		basesize += 2;
		if (s -> s_rf_reference.sr_ulen)
		    basesize += 2 + s -> s_rf_reference.sr_ulen;
		if (s -> s_rf_reference.sr_clen)
		    basesize += 2 + s -> s_rf_reference.sr_clen;
		if (s -> s_rf_reference.sr_alen)
		    basesize += 2 + s -> s_rf_reference.sr_alen;
	    }
	    break;

	case SPDU_AR: 
	    basesize += 2;
	    If_Set (SMASK_AR_REF) {
		if (s -> s_ar_reference.sr_ulen)
		    basesize += 2 + s -> s_ar_reference.sr_ulen;
		if (s -> s_ar_reference.sr_clen)
		    basesize += 2 + s -> s_ar_reference.sr_clen;
		if (s -> s_ar_reference.sr_alen)
		    basesize += 2 + s -> s_ar_reference.sr_alen;
		if (s -> s_ar_reference.sr_vlen)
		    basesize += 2 + s -> s_ar_reference.sr_vlen;
	    }
	    break;
    }

    if (basesize < 254)
	basesize = 254;
    c -> li = c -> pgi = 0;
    c -> len = basesize + ((basesize > 254) ? 4 : 2);
    if ((c -> top = malloc ((unsigned) c -> len)) == NULL) {
	c -> len = 0;
	s -> s_errno = SC_CONGEST;
    }
    else
	s -> s_errno = SC_ACCEPT;
    if ((c -> allocli = c -> left = basesize) > 254)
	c -> ptr = c -> top + 4;
    else
	c -> ptr = c -> top + 2;
}

/* \f

 */

static int end_spdu (code, c)
unsigned char code;
struct	local_buf *c;
{
    if (c -> len) {
	if (c -> allocli > 254) {
	    if (c -> li < 255) {
		bcopy ((c -> top + 2), c -> top, (c -> len - c -> left));
		*(c -> top + 1) = c -> li;
		c -> len = c -> li + 2;
	    }
	    else {
		*(c -> top + 1) = 255;
		*(c -> top + 2) = (c -> li >> 8) & 0xff;
		*(c -> top + 3) = c -> li & 0xff;
		c -> len = c -> li + 4;
	    }
	}
	else {
	    *(c -> top + 1) = c -> li;
	    c -> len = c -> ptr - c -> top;
	}
	*c -> top = code;
	return OK;
    }

    return NOTOK;
}

/* \f

 */

static start_pgi (code, c)
unsigned char code;
struct	local_buf *c;
{
    put2spdu ((int) code, 0, NULLCP, c);
    if (c -> len)
	c -> pgi = (c -> ptr - c -> top - 1);
}


static end_pgi (c)
struct	local_buf *c;
{
    if (c -> len)
	*(c -> top + c -> pgi) = (c -> len - c -> left) - (c -> pgi + 1);
}

/* \f

 */

static	put2spdu (code, li, value, c)
int code;
int li;
char *value;
struct	local_buf *c;
{
    int     cl = li;
    char   *p1,
           *p2;

    if (c -> len) {
	cl += (li < 255) ? 2 : 4;
	if (c -> left >= cl)
	    c -> left -= cl;
	else {
/* XXX:	this clause of Dwight's is all WRONG, WRONG, WRONG.  I think we
	should make start_spdu() smarter, if necessary and change this to

	c -> len = 0;
	return;
*/
	char   *cp;

	    if (c -> allocli < 255)
		cl += 2;
	    cp = realloc (c -> top, (unsigned) (c -> len += cl));
	    if (cp == NULL) {
		c -> len = 0;
		return;
	    }
	    c -> ptr = (c -> top = cp) + (c -> len - c -> left);
	    if (c -> allocli < 255) {
		c -> allocli += cl;
		cl = c -> len - c -> left + 2;
		for (p1 = c -> ptr, p2 = p1 + 2; cl; cl--)
		    *p2-- = *p1--;
		c -> pgi += 2;
		c -> left -= 2;
	    }
	}
	*c -> ptr++ = code & 0xff;
	if (li < 255) {
	    *c -> ptr++ = li;
	    c -> li += 2 + li;
	}
	else {
	    *c -> ptr++ = 255;
	    *c -> ptr++ = (li >> 8) & 0xff;
	    *c -> ptr++ = li & 0xff;
	    c -> li += 4 + li;
	}

	bcopy (value, c -> ptr, li);
	c -> ptr += li;
    }
}

/* \f

 */

int	spkt2tsdu (s, base, len)
register struct ssapkt *s;
char  **base;
int    *len;
{
    struct local_buf    c;
    char    isn[SIZE_CN_ISN + 1];

    c.len = 0;
    switch (s -> s_code) {
	case SPDU_CN: 
	    start_spdu (s, &c, CN_BASE_SIZE);
	    If_Set (SMASK_CN_REF)
		Put_Ref (s -> s_cn_reference, PI_CALLING_SS);
	    If_Set (SMASK_CN_OPT | SMASK_CN_TSDU | SMASK_CN_VRSN | SMASK_CN_ISN
		    | SMASK_CN_SET) {
		start_pgi (PGI_CN_ITEMS, &c);
		If_Set (SMASK_CN_OPT)
		    Put_Item (PI_PROTOCOL_OPT, (char *) &s -> s_options);
		If_Set (SMASK_CN_TSDU) {
		    u_long tsdu_maxsize = (s -> s_tsdu_init & 0xffff) << 16
			| s -> s_tsdu_resp & 0xffff;
		    tsdu_maxsize = htonl (tsdu_maxsize);
		    Put_Item (PI_TSDU_MAXSIZ, (char *) &tsdu_maxsize);
		}
		If_Set (SMASK_CN_VRSN)
		    Put_Item (PI_VERSION, (char *) &s -> s_cn_version);
		If_Set (SMASK_CN_ISN)
		    Put_SSN (PI_ISN, s -> s_isn);
		If_Set (SMASK_CN_SET)
		    Put_Item (PI_TOKEN_SET, (char *) &s -> s_settings);
		end_pgi (&c);
	    }
    	    If_Set (SMASK_CN_REQ) {
		u_short requirements = htons (s -> s_cn_require);
		Put_Item (PI_USER_REQ, (char *) &requirements);
	    }
	    If_Set (SMASK_CN_CALLING)
		put2spdu (PI_SSAP_CALLING, s -> s_callinglen, 
			    s -> s_calling, &c);
	    If_Set (SMASK_CN_CALLED)
		put2spdu (PI_SSAP_CALLED, s -> s_calledlen, 
			    s -> s_called, &c);
	    Put_XData (CN_SIZE);
	    break;

	case SPDU_AC: 
	    start_spdu (s, &c, AC_BASE_SIZE);
	    If_Set (SMASK_CN_REF)
		Put_Ref (s -> s_cn_reference, PI_CALLED_SS);
	    If_Set (SMASK_CN_OPT | SMASK_CN_TSDU | SMASK_CN_VRSN | SMASK_CN_ISN
		    | SMASK_CN_SET) {
		start_pgi (PGI_CN_ITEMS, &c);
		If_Set (SMASK_CN_OPT)
		    Put_Item (PI_PROTOCOL_OPT, (char *) &s -> s_options);
		If_Set (SMASK_CN_TSDU) {
		    u_long tsdu_maxsize = (s -> s_tsdu_init & 0xffff) << 16
			| s -> s_tsdu_resp & 0xffff;
		    tsdu_maxsize = htonl (tsdu_maxsize);
		    Put_Item (PI_TSDU_MAXSIZ, (char *) &tsdu_maxsize);
		}
		If_Set (SMASK_CN_VRSN)
		    Put_Item (PI_VERSION, (char *) &s -> s_cn_version);
		If_Set (SMASK_CN_ISN)
		    Put_SSN (PI_ISN, s -> s_isn);
		If_Set (SMASK_CN_SET)
		    Put_Item (PI_TOKEN_SET, (char *) &s -> s_settings);
		end_pgi (&c);
	    }
	    If_Set (SMASK_AC_TOKEN)
		Put_Item (PI_TOKEN, (char *) &s -> s_ac_token);
	    If_Set (SMASK_CN_REQ) {
		u_short requirements = htons (s -> s_cn_require);
		Put_Item (PI_USER_REQ, (char *) &requirements);
	    }
	    If_Set (SMASK_CN_CALLING)
		put2spdu (PI_SSAP_CALLING, s -> s_callinglen,
			    s -> s_calling, &c);
	    If_Set (SMASK_CN_CALLED)
		put2spdu (PI_SSAP_CALLED, s -> s_calledlen, 
			    s -> s_called, &c);
	    If_Set (SMASK_ENCLOSE)
		Put_Item (PI_ENCLOSE, (char *) &s -> s_enclose);
	    Put_UData (AC_SIZE);
	    break;

	case SPDU_RF: 
	    start_spdu (s, &c, RF_BASE_SIZE);
	    If_Set (SMASK_RF_REF)
		Put_Ref (s -> s_rf_reference, PI_CALLED_SS);
	    If_Set (SMASK_RF_DISC)
		Put_Item (PI_TDISC, (char *) &s -> s_rf_disconnect);
	    If_Set (SMASK_RF_REQ) {
		u_short requirements = htons (s -> s_rf_require);
		Put_Item (PI_USER_REQ, (char *) &requirements);
	    }
	    If_Set (SMASK_RF_VRSN)
		Put_Item (PI_VERSION, (char *) &s -> s_rf_version);
	    if (s -> s_rlen > RF_SIZE) {
		if (c.len)
		    free (c.top);
		s -> s_errno = SC_PROTOCOL;
		return NOTOK;
	    }
	    If_Set (SMASK_ENCLOSE)
		Put_Item (PI_ENCLOSE, (char *) &s -> s_enclose);
	    if (s -> s_rlen > 0)
		put2spdu (PI_REASON, s -> s_rlen, s -> s_rdata, &c);
	    break;

	case SPDU_FN: 
	    start_spdu (s, &c, FN_BASE_SIZE);
	    If_Set (SMASK_FN_DISC)
		Put_Item (PI_TDISC, (char *) &s -> s_fn_disconnect);
	    If_Set (SMASK_ENCLOSE)
		Put_Item (PI_ENCLOSE, (char *) &s -> s_enclose);
	    Put_UData (FN_SIZE);
	    break;

	case SPDU_DN: 
	    start_spdu (s, &c, DN_BASE_SIZE);
	    If_Set (SMASK_ENCLOSE)
		Put_Item (PI_ENCLOSE, (char *) &s -> s_enclose);
	    Put_UData (DN_SIZE);
	    break;

	case SPDU_NF: 
	    start_spdu (s, &c, NF_BASE_SIZE);
	    If_Set (SMASK_ENCLOSE)
		Put_Item (PI_ENCLOSE, (char *) &s -> s_enclose);
	    Put_UData (NF_SIZE);
	    break;

	case SPDU_AB: 
#ifdef	notdef
	case SPDU_AI:		/* aka SPDU_AB */
#endif
	    If_Set (SMASK_SPDU_AB) {
		start_spdu (s, &c, AB_BASE_SIZE);
		If_Reset (SMASK_AB_DISC) {
		    s -> s_errno = SC_PROTOCOL;
		    break;
		}
		Put_Item (PI_TDISC, (char *) &s -> s_ab_disconnect);
		If_Set (SMASK_AB_REFL)
		    put2spdu (PI_REFLECT, AB_REFL_SIZE,
				(char *) s -> s_reflect, &c);
		If_Set (SMASK_ENCLOSE)
		    Put_Item (PI_ENCLOSE, (char *) &s -> s_enclose);
		Put_UData (AB_SIZE);
		break;
	    }
	    start_spdu (s, &c, AI_BASE_SIZE);
	    If_Set (SMASK_AI_REASON)
		put2spdu (PI_REASON, 1, (char *) &s -> s_ai_reason, &c);
	    break;

	case SPDU_AA: 
#ifdef	notdef
	case SPDU_AIA:		/* aka SPDU_AA */
#endif
	    If_Set (SMASK_SPDU_AA) {
		start_spdu (s, &c, AA_BASE_SIZE);
		break;
	    }
	    start_spdu (s, &c, AIA_BASE_SIZE);
	    break;

	case SPDU_GT:
#ifdef	notdef
	case SPDU_DT:		/* aka SPDU_GT */
#endif
	    If_Set (SMASK_SPDU_GT) {
		start_spdu (s, &c, GT_BASE_SIZE);
		If_Set (SMASK_GT_TOKEN)
		    Put_Item (PI_TOKEN, (char *) &s -> s_gt_token);
		break;
	    }			/* else fall */
	    start_spdu (s, &c, DT_BASE_SIZE);
	    If_Set (SMASK_ENCLOSE)
		Put_Item (PI_ENCLOSE, (char *) &s -> s_enclose);
/* NB: caller responsible for mapping s -> s_udata to user info */
	    break;

	case SPDU_TD: 
	    start_spdu (s, &c, TD_BASE_SIZE);
	    If_Set (SMASK_ENCLOSE)
		Put_Item (PI_ENCLOSE, (char *) &s -> s_enclose);
/* NB: caller responsible for mapping s -> s_udata to user info */
	    break;

	case SPDU_EX: 
	    start_spdu (s, &c, EX_BASE_SIZE);
/* NB: caller responsible for mapping s -> s_udata to user info */
	    break;

	case SPDU_CD: 
	    start_spdu (s, &c, CD_BASE_SIZE);
	    If_Set (SMASK_ENCLOSE)
		Put_Item (PI_ENCLOSE, (char *) &s -> s_enclose);
	    Put_UData (CD_SIZE);
	    break;

	case SPDU_CDA: 
	    start_spdu (s, &c, CDA_BASE_SIZE);
	    If_Set (SMASK_ENCLOSE)
		Put_Item (PI_ENCLOSE, (char *) &s -> s_enclose);
	    Put_UData (CDA_SIZE);
	    break;

	case SPDU_PT: 
	    start_spdu (s, &c, PT_BASE_SIZE);
	    If_Set (SMASK_PT_TOKEN)
		Put_Item (PI_TOKEN, (char *) &s -> s_pt_token);
	    If_Set (SMASK_ENCLOSE)
		Put_Item (PI_ENCLOSE, (char *) &s -> s_enclose);
	    Put_UData (PT_SIZE);
	    break;

	case SPDU_GTC: 
	    start_spdu (s, &c, GTC_BASE_SIZE);
	    break;

	case SPDU_GTA: 
	    start_spdu (s, &c, GTA_BASE_SIZE);
	    break;

	case SPDU_MIP: 
	    start_spdu (s, &c, MIP_BASE_SIZE);
	    If_Set (SMASK_MIP_SYNC)
		Put_Item (PI_SYNC, (char *) &s -> s_mip_sync);
	    If_Reset (SMASK_MIP_SERIAL) {
		s -> s_errno = SC_PROTOCOL;
		break;
	    }
	    Put_SSN (PI_SERIAL, s -> s_mip_serial);
	    If_Set (SMASK_ENCLOSE)
		Put_Item (PI_ENCLOSE, (char *) &s -> s_enclose);
	    Put_UData (MIP_SIZE);
	    break;

	case SPDU_MAP: 
#ifdef	notdef
	case SPDU_AE:		/* aka SPDU_MAP */
#endif
	    If_Set (SMASK_MAP_SYNC) {
		start_spdu (s, &c, MAP_BASE_SIZE);
		Put_Item (PI_SYNC, (char *) &s -> s_map_sync);
	    }
	    else
		start_spdu (s, &c, AE_BASE_SIZE);
	    If_Reset (SMASK_MAP_SERIAL) {
		s -> s_errno = SC_PROTOCOL;
		break;
	    }
	    Put_SSN (PI_SERIAL, s -> s_map_serial);
	    If_Set (SMASK_ENCLOSE)
		Put_Item (PI_ENCLOSE, (char *) &s -> s_enclose);
	    Put_UData (MAP_SIZE);
	    break;

	case SPDU_MIA: 
	    start_spdu (s, &c, MIA_BASE_SIZE);
	    If_Reset (SMASK_MIA_SERIAL) {
		s -> s_errno = SC_PROTOCOL;
		break;
	    }
	    Put_SSN (PI_SERIAL, s -> s_mia_serial);
	    If_Set (SMASK_ENCLOSE)
		Put_Item (PI_ENCLOSE, (char *) &s -> s_enclose);
	    Put_MData (MIA_SIZE);
	    break;

	case SPDU_MAA: 
#ifdef	notdef
	case SPDU_AEA:		/* aka SPDU_MAA */
#endif
	    start_spdu (s, &c, MAA_BASE_SIZE);
	    If_Reset (SMASK_MAA_SERIAL) {
		s -> s_errno = SC_PROTOCOL;
		break;
	    }
	    Put_SSN (PI_SERIAL, s -> s_maa_serial);
	    If_Set (SMASK_ENCLOSE)
		Put_Item (PI_ENCLOSE, (char *) &s -> s_enclose);
	    Put_UData (MAA_SIZE);
	    break;

	case SPDU_RS:
	    start_spdu (s, &c, RS_BASE_SIZE);
	    If_Set (SMASK_RS_SET)
		Put_Item (PI_TOKEN_SET, (char *) &s -> s_rs_settings);
	    If_Reset (SMASK_RS_TYPE) {
		s -> s_errno = SC_PROTOCOL;
		break;
	    }
	    Put_Item (PI_RESYNC, (char *) &s -> s_rs_type);
	    If_Reset (SMASK_RS_SSN) {
		s -> s_errno = SC_PROTOCOL;
		break;
	    }
	    Put_SSN (PI_SERIAL, s -> s_rs_serial);
	    If_Set (SMASK_ENCLOSE)
		Put_Item (PI_ENCLOSE, (char *) &s -> s_enclose);
	    Put_UData (RS_SIZE);
	    break;

	case SPDU_RA:
	    start_spdu (s, &c, RA_BASE_SIZE);
	    If_Set (SMASK_RA_SET)
		Put_Item (PI_TOKEN_SET, (char *) &s -> s_ra_settings);
	    If_Reset (SMASK_RA_SSN) {
		s -> s_errno = SC_PROTOCOL;
		break;
	    }
	    Put_SSN (PI_SERIAL, s -> s_ra_serial);
	    If_Set (SMASK_ENCLOSE)
		Put_Item (PI_ENCLOSE, (char *) &s -> s_enclose);
	    Put_UData (RA_SIZE);
	    break;

	case SPDU_PR: 
	    start_spdu (s, &c, PR_BASE_SIZE);
	    If_Reset (SMASK_PR_TYPE) {
		s -> s_errno = SC_PROTOCOL;
		break;
	    }
	    Put_Item (PI_PREPARE, (char *) &s -> s_pr_type);
	    break;

	case SPDU_ER:		/* we don't do these! */
	    s -> s_errno = SC_PROTOCOL;
	    break;

	case SPDU_ED: 
	    start_spdu (s, &c, ED_BASE_SIZE);
	    If_Reset (SMASK_ED_REASON) {
		s -> s_errno = SC_PROTOCOL;
		break;
	    }
	    put2spdu (PI_REASON, 1, (char *) &s -> s_ed_reason, &c);
	    If_Set (SMASK_ENCLOSE)
		Put_Item (PI_ENCLOSE, (char *) &s -> s_enclose);
	    Put_UData (ED_SIZE);
	    break;

	case SPDU_AS: 
	    start_spdu (s, &c, AS_BASE_SIZE);
	    If_Reset (SMASK_AS_ID) {
		s -> s_errno = SC_PROTOCOL;
		break;
	    }
	    put2spdu (PI_ACT_ID, (int) s -> s_as_id.sd_len,
		s -> s_as_id.sd_data, &c);
	    If_Set (SMASK_ENCLOSE)
		Put_Item (PI_ENCLOSE, (char *) &s -> s_enclose);
	    Put_UData (AS_SIZE);
	    break;

	case SPDU_AR:
	    start_spdu (s, &c, AR_BASE_SIZE);
	    start_pgi (PGI_AR_LINK, &c);
	    If_Set (SMASK_AR_REF) {
		if (s -> s_ar_reference.sr_called_len)
		    put2spdu (PI_AR_CALLED,
			    (int) s -> s_ar_reference.sr_called_len,
			    s -> s_ar_reference.sr_called, &c);
		if (s -> s_ar_reference.sr_calling_len)
		    put2spdu (PI_AR_CALLING,
			    (int) s -> s_ar_reference.sr_calling_len,
			    s -> s_ar_reference.sr_calling, &c);
		if (s -> s_ar_reference.sr_clen)
		    put2spdu (PI_AR_COMMON, (int) s -> s_ar_reference.sr_clen,
			    s -> s_ar_reference.sr_cdata, &c);
		if (s -> s_ar_reference.sr_alen)
		    put2spdu (PI_AR_ADDT, (int) s -> s_ar_reference.sr_alen,
			    s -> s_ar_reference.sr_adata, &c);
	    }
	    If_Reset (SMASK_AR_OID) {
		s -> s_errno = SC_PROTOCOL;
		break;
	    }
	    put2spdu (PI_ACT_ID, (int) s -> s_ar_oid.sd_len,
		    s -> s_ar_oid.sd_data, &c);
	    If_Reset (SMASK_AR_SSN) {
		s -> s_errno = SC_PROTOCOL;
		break;
	    }
	    Put_SSN (PI_SERIAL, s -> s_ar_serial);
	    end_pgi (&c);	    
	    If_Reset (SMASK_AR_ID) {
		s -> s_errno = SC_PROTOCOL;
		break;
	    }
	    put2spdu (PI_ACT_ID, (int) s -> s_ar_id.sd_len,
		s -> s_ar_id.sd_data, &c);
	    If_Set (SMASK_ENCLOSE)
		Put_Item (PI_ENCLOSE, (char *) &s -> s_enclose);
	    Put_UData (AR_SIZE);
	    break;

	case SPDU_AD: 
	    start_spdu (s, &c, AD_BASE_SIZE);
	    If_Set (SMASK_AD_REASON) 
		put2spdu (PI_REASON, 1, (char *) &s -> s_ad_reason, &c);
	    break;

	case SPDU_ADA: 
	    start_spdu (s, &c, ADA_BASE_SIZE);
	    break;

	default: 
	    s -> s_errno = SC_PROTOCOL;
	    break;
    }

    if ((end_spdu (s -> s_code, &c) == NOTOK) || (s -> s_errno != SC_ACCEPT)) {
	if (s -> s_errno == SC_ACCEPT)
	    s -> s_errno = SC_CONGEST;
	if (c.len) {
	    free (c.top);
	    c.len = 0;
	}
	*base = NULL;
	*len = 0;
    }
    else {
	*base = c.top;
	*len = c.len;
	s -> s_li = c.li;
    }

#ifdef	DEBUG
    if (ssap_log -> ll_events & LLOG_PDUS)
	spkt2text (ssap_log, s, 0);
#endif

    return c.len ? OK : NOTOK;
}

/* \f

 */

static u_long str2ssn (s, n)
register char  *s;
register int	n;
{
    register u_long u;

    for (u = 0L; n > 0; n--)
	u = u * 10 + *s++ - '0';

    return u;
}

/* \f

 */

/* this is used to pull PCI, not user data... */

#define	advance(n) \
    if (base >= xbase) { \
	if ((base = pullqb (qb, (n))) == NULL) { \
	    s -> s_errno = SC_PROTOCOL; \
	    break; \
	} \
	xbase = base + (n); \
	nread += (n); \
    } \
    else

static char *pullqb (qb, n)
struct qbuf *qb;
int	n;
{
    register int    i;
    int	    once;
    register char  *cp;
    register struct qbuf *qp;
    static char *buffer = NULL;

    if (n > SEGMENT_MAX)
	return NULLCP;

    for (once = 1, cp = buffer, qp = NULL; n > 0; once = 0, cp += i, n -= i) {
	if (qp == NULL && (qp = qb -> qb_forw) == qb)
	    return NULLCP;

	i = min (qp -> qb_len, n);
	if (once && i == n) {	/* special case */
	    cp = qp -> qb_data;
	    qp -> qb_data += i, qp -> qb_len -= i;
	    return cp;
	}

	if (buffer == NULL) {
	    if ((buffer = malloc ((unsigned) SEGMENT_MAX)) == NULL)
		return NULLCP;
	    cp = buffer;
	}
	bcopy (qp -> qb_data, cp, i);

	qp -> qb_data += i, qp -> qb_len -= i;
	if (qp -> qb_len <= 0) {
	    remque (qp);

	    free ((char *) qp);
	    qp = NULL;
	}
    }

    return buffer;
}

/* \f

 */

struct ssapkt *tsdu2spkt (qb, len, cc)
struct qbuf *qb;
int	len,
       *cc;
{
    register int    li;
    int     cat0,
	    nread,
	    pktlen,
            pgilen,
	    pmask,
	    xlen;
    register char *base;
    char   *xbase;
    unsigned char   code,
                    si;
    register struct ssapkt  *s;

    if (cc) {
	cat0 = *cc;
	*cc = 0;
    }
    else
	cat0 = 1;
    if ((base = pullqb (qb, nread = 2)) == NULL
	    || (s = newspkt ((int) (si = *base++))) == NULL)
	return NULLSPKT;

    if (*((u_char *) base) == 255) {
	if ((base = pullqb (qb, 2)) == NULL) {
	    s -> s_errno = SC_PROTOCOL;
	    return s;
	}
	nread += 2;
	s -> s_li = 
		(*((u_char *) base) << 8) + *((u_char *) (base + 1));
    }
    else
	s -> s_li = *((u_char *) base);
    pgilen = pktlen = s -> s_li;

    if (cat0)
	switch (si) {
	    case SPDU_GT:
		Set (SMASK_SPDU_GT);
		break;

	    case SPDU_AB:
		Set (SMASK_SPDU_AB);
		break;

	    case SPDU_AA:
		Set (SMASK_SPDU_AA);
		break;

	    default:
		break;
	}

    if ((si >= SI_TABLE_LEN)
	    || ((pmask = si_table[si]) == PMASK_NOTSUPPORTED)) {
	s -> s_errno = SC_PROTOCOL;
	return s;
    }
    if (len < pktlen + nread) {
	s -> s_errno = SC_PROTOCOL;
	return s;
    }

    s -> s_errno = SC_ACCEPT;
    xbase = base;
    while (pktlen && (s -> s_errno == SC_ACCEPT)) {
	advance (2);
	code = *base++;
	if (*((u_char *) base) == 255) {
	    base++;
	    advance (2);
	    li = (*((u_char *) base) << 8) + *((u_char *) (base + 1));
	    xlen = 2;
	}
	else {
	    li = *((u_char *) base);
	    xlen = 1;
	}
	base += xlen;
	if (xlen > 1)
	    xlen += 2;
	else
	    xlen++;
	switch (code) {
	    case PI_UDATA:
	        if (!(pmask & PMASK_UDATA))
		    s -> s_errno = SC_PROTOCOL;
		break;

	    case PI_XDATA:
	        if (!(pmask & PMASK_XDATA))
		    s -> s_errno = SC_PROTOCOL;
		break;

	    default:
		if (code >= PI_TABLE_LEN || !(pmask & pi_table[code]))
		    s -> s_errno = SC_PROTOCOL;
		break;
	}
	if (s -> s_errno != SC_ACCEPT)
	    break;
	if (!pgilen)
	    pgilen = pktlen;
	pktlen -= (xlen + li);
	if (li > (pgilen -= xlen)) {
	    s -> s_errno = SC_PROTOCOL;
	    break;
	}
	pgilen -= li;
	if (li)
	    advance (li);
	if (code < PI_TABLE_LEN) {
	    if (li) {
		if (pi_table[code] & PMASK_VARLEN) {
		    if (li > pi_length[code]) {
			s -> s_errno = SC_PROTOCOL;
			break;
		    }
		}
		else
		    if (li != pi_length[code]) {
			s -> s_errno = SC_PROTOCOL;
			break;
		    }
	    }
	}

	switch (code) {
	    case PGI_AR_LINK:
		Set (SMASK_AR_OID);/* HACK! */
		goto do_pgi;

	    case PGI_CN_ID: 
		Set (SMASK_CN_REF);/* fall */
	    case PGI_CN_ITEMS: 
do_pgi: ;
		pktlen += li;
		pgilen = li;
		li = 0;
		break;

	    case PI_CALLED_SS: 
	    case PI_CALLING_SS: 
#ifdef	notdef
	    case PI_AR_CALLED:
	    case PI_AR_CALLING:
#endif
		switch (si) {
		    case SPDU_CN: 
		    case SPDU_AC: 
			s -> s_cn_reference.sr_ulen = li;
			bcopy (base, s -> s_cn_reference.sr_udata, li);
			Set (SMASK_CN_REF);
			break;
		    case SPDU_RF: 
			s -> s_rf_reference.sr_ulen = li;
			bcopy (base, s -> s_rf_reference.sr_udata, li);
			Set (SMASK_RF_REF);
			break;
		    case SPDU_AR:
			switch (code) {
			    case PI_AR_CALLED:
				s -> s_ar_reference.sr_called_len = li;
				bcopy (base, s -> s_ar_reference.sr_called,
					li);
				Set (SMASK_AR_REF);
				break;				
			    case PI_AR_CALLING:
				s -> s_ar_reference.sr_calling_len = li;
				bcopy (base, s -> s_ar_reference.sr_calling,
					li);
				Set (SMASK_AR_REF);
				break;
			    default:
				s -> s_errno = SC_PROTOCOL;
				break;
			}
		        break;
		    default: 
			s -> s_errno = SC_PROTOCOL;
			break;
		}
		base += li;
		break;

	    case PI_COMMON_REF: 
#ifdef	notdef
	    case PI_AR_COMMON:
#endif
		switch (si) {
		    case SPDU_CN: 
		    case SPDU_AC: 
			s -> s_cn_reference.sr_clen = li;
			bcopy (base, s -> s_cn_reference.sr_cdata, li);
			Set (SMASK_CN_REF);
			break;
		    case SPDU_RF: 
			s -> s_rf_reference.sr_clen = li;
			bcopy (base, s -> s_rf_reference.sr_cdata, li);
			Set (SMASK_RF_REF);
			break;
		    case SPDU_AR:
			s -> s_ar_reference.sr_clen = li;
			bcopy (base, s -> s_ar_reference.sr_cdata, li);
			Set (SMASK_AR_REF);
			break;
		    default: 
			s -> s_errno = SC_PROTOCOL;
			break;
		}
		base += li;
		break;

	    case PI_ADD_INFO: 
#ifdef	notdef
	    case PI_AR_ADDT:
#endif
		switch (si) {
		    case SPDU_CN: 
		    case SPDU_AC: 
			s -> s_cn_reference.sr_alen = li;
			bcopy (base, s -> s_cn_reference.sr_adata, li);
			Set (SMASK_CN_REF);
			break;
		    case SPDU_RF: 
			s -> s_rf_reference.sr_alen = li;
			bcopy (base, s -> s_rf_reference.sr_adata, li);
			Set (SMASK_RF_REF);
			break;
		    case SPDU_AR:
			s -> s_ar_reference.sr_alen = li;
			bcopy (base, s -> s_ar_reference.sr_adata, li);
			Set (SMASK_AR_REF);
			break;
		    default: 
			s -> s_errno = SC_PROTOCOL;
			break;
		}
		base += li;
		break;

	    case PI_PROTOCOL_OPT: 
		if ((s -> s_options = *base++) & ~CR_OPT_MASK)
		    s -> s_errno = SC_PROTOCOL;
		else
		    Set (SMASK_CN_OPT);
		break;

	    case PI_TSDU_MAXSIZ: 
		{
		    u_long tsdu_maxsize;
		    bcopy (base, (char *) &tsdu_maxsize,
			    pi_length[PI_TSDU_MAXSIZ]);
		    tsdu_maxsize = ntohl (tsdu_maxsize);
		    s -> s_tsdu_init = (tsdu_maxsize >> 16) & 0xffff;
		    s -> s_tsdu_resp = tsdu_maxsize & 0xffff;
		    Set (SMASK_CN_TSDU);
		}
		base += pi_length[PI_TSDU_MAXSIZ];
		break;

	    case PI_VERSION: 
		switch (si) {
		    case SPDU_CN: 
		    case SPDU_AC: 
			s -> s_cn_version = *base++;
			Set (SMASK_CN_VRSN);
			break;
		    case SPDU_RF: 
			s -> s_rf_version = *base++;
			Set (SMASK_RF_VRSN);
			break;
		    default: 
			s -> s_errno = SC_PROTOCOL;
			break;
		}
		break;

	    case PI_SYNC: 
		switch (si) {
		    case SPDU_MIP: 
			if ((s -> s_mip_sync = *base++) & ~MIP_SYNC_MASK)
			    s -> s_errno = SC_PROTOCOL;
			else
			    Set (SMASK_MIP_SYNC);
			break;
		    case SPDU_MAP: 
			if ((s -> s_map_sync = *base++) & ~MAP_SYNC_MASK)
			    s -> s_errno = SC_PROTOCOL;
			else
			    Set (SMASK_MAP_SYNC);
			break;
		}
		break;

	    case PI_TOKEN_SET: 
		switch (si) {
		    case SPDU_CN: 
		    case SPDU_AC: 
			s -> s_settings = *base++;
			Set (SMASK_CN_SET);
			break;
		    case SPDU_RS:
			s -> s_rs_settings = *base++;
			Set (SMASK_RS_SET);
			break;
		    case SPDU_RA:
			s -> s_ra_settings = *base++;
			Set (SMASK_RA_SET);
			break;
		    default: 
			s -> s_errno = SC_PROTOCOL;
			break;
		}
		break;

	    case PI_TOKEN: 
		switch (si) {
		    case SPDU_AC: 
			s -> s_ac_token = *base++;
			Set (SMASK_AC_TOKEN);
			break;
		    case SPDU_GT: 
			If_Reset (SMASK_SPDU_GT) {
			    s -> s_errno = SC_PROTOCOL;
			    break;
			}
			s -> s_gt_token = *base++;
			Set (SMASK_GT_TOKEN);
			break;
		    case SPDU_PT: 
			s -> s_pt_token = *base++;
			Set (SMASK_PT_TOKEN);
			break;
		    default: 
			s -> s_errno = SC_PROTOCOL;
			break;
		}
		break;

	    case PI_TDISC: 
		switch (si) {
		    case SPDU_RF: 
			if ((s -> s_rf_disconnect = *base++) & ~RF_DISC_MASK)
			    s -> s_errno = SC_PROTOCOL;
			else
			    Set (SMASK_RF_DISC);
			break;
		    case SPDU_FN: 
			if ((s -> s_fn_disconnect = *base++) & ~FN_DISC_MASK)
			    s -> s_errno = SC_PROTOCOL;
			else
			    Set (SMASK_FN_DISC);
			break;
		    case SPDU_AB: 
			If_Reset (SMASK_SPDU_AB) {
			    s -> s_errno = SC_PROTOCOL;
			    break;
			}
			if ((s -> s_ab_disconnect = *base++) & ~AB_DISC_MASK)
			    s -> s_errno = SC_PROTOCOL;
			else
			    Set (SMASK_AB_DISC);
			break;
		    default: 
			s -> s_errno = SC_PROTOCOL;
			break;
		}
		break;

	    case PI_USER_REQ: 
		{
		    u_short requirements;
		    bcopy (base, (char *) &requirements, 2);
		    requirements = ntohs (requirements);
		    if (si != SPDU_RF) {
			s -> s_cn_require = requirements;
			Set (SMASK_CN_REQ);
		    }
		    else {
			s -> s_rf_require = requirements;
			Set (SMASK_RF_REQ);
		    }
		}
		base += 2;
		break;

	    case PI_ISN: 
		switch (si) {
		    case SPDU_CN: 
		    case SPDU_AC: 
			s -> s_isn = str2ssn (base, li);
			Set (SMASK_CN_ISN);
			break;
		    default: 
			s -> s_errno = SC_PROTOCOL;
			break;
		}
	    case PI_ISN2:	/* not supported yet */
		base += li;
		break;

	    case PI_ENCLOSE:
		if ((si == SPDU_DT && (s -> s_mask & SMASK_SPDU_GT))
		        || (si == SPDU_AI && !(s -> s_mask & SMASK_SPDU_AB))) {
		    s -> s_errno = SC_PROTOCOL;
		    break;
		}
		if ((s -> s_enclose = *base++) & ~ENCL_MASK)
		    s -> s_errno = SC_PROTOCOL;
		else
		    Set (SMASK_ENCLOSE);
		break;

	    case PI_RESYNC:
		s -> s_rs_type = *base++;
		if (SYNC_OK (s -> s_rs_type))
		    Set (SMASK_RS_TYPE);
		else
		    s -> s_errno = SC_PROTOCOL;
		break;

	    case PI_ACT_ID:
		switch (si) {
		    case SPDU_AS:
			s -> s_as_id.sd_len = li;
			bcopy (base, s -> s_as_id.sd_data, li);
			Set (SMASK_AS_ID);
			break;

		    case SPDU_AR:
			if ((s -> s_mask & SMASK_AR_OID)
				&& s -> s_ar_oid.sd_len == 0) {
			    s -> s_ar_oid.sd_len = li;
			    bcopy (base, s -> s_ar_oid.sd_data, li);
			}
			else {
			    s -> s_ar_id.sd_len = li;
			    bcopy (base, s -> s_ar_id.sd_data, li);
			    Set (SMASK_AR_ID);
			}
			break;

		    default:
			s -> s_errno = SC_PROTOCOL;
			break;
		}
		base += li;
		break;

	    case PI_SERIAL: 
		switch (si) {
		    case SPDU_MIP: 
			s -> s_mip_serial = str2ssn (base, li);
			Set (SMASK_MIP_SERIAL);
			break;
		    case SPDU_MAP: 
			s -> s_map_serial = str2ssn (base, li);
			Set (SMASK_MAP_SERIAL);
			break;
		    case SPDU_MIA: 
			s -> s_mia_serial = str2ssn (base, li);
			Set (SMASK_MIA_SERIAL);
			break;
		    case SPDU_MAA: 
			s -> s_maa_serial = str2ssn (base, li);
			Set (SMASK_MAA_SERIAL);
			break;
		    case SPDU_RS: 
			s -> s_rs_serial = str2ssn (base, li);
			Set (SMASK_RS_SSN);
			break;
		    case SPDU_RA: 
			s -> s_ra_serial = str2ssn (base, li);
			Set (SMASK_RA_SSN);
			break;
		    case SPDU_AR: 
			s -> s_ar_serial = str2ssn (base, li);
			Set (SMASK_AR_SSN);
			break;
		    default: 
			s -> s_errno = SC_PROTOCOL;
			break;
		}
		base += li;
		break;

	    case PI_MIA_DATA: 
	    case PI_UDATA: 
	    case PI_XDATA: 
		Set (SMASK_UDATA_PGI);
		if (!li)
		    break;
		if (si == SPDU_AB && !(s -> s_mask & SMASK_SPDU_AB)) {
		    s -> s_errno = SC_PROTOCOL;
		    break;
		}
		else
		    if (li > (code != PI_XDATA ? SEGMENT_MAX : CONNECT_MAX)) {
			s -> s_errno = SC_PROTOCOL;
			break;
		    }
		s -> s_udata = malloc ((unsigned) (s -> s_ulen = li));
		if (s -> s_udata == NULL) {
		    s -> s_errno = SC_CONGEST;
		    break;
		}
		bcopy (base, s -> s_udata, li);
		base += li;
		break;

	    case PI_REASON: 
		switch (si) {
		    case SPDU_RF: 
			s -> s_rdata = malloc ((unsigned) (s -> s_rlen = li));
			if (s -> s_rdata == NULL) {
			    s -> s_errno = SC_CONGEST;
			    break;
			}
			bcopy (base, s -> s_rdata, li);
			base += li;
			break;
		    case SPDU_ED: 
			s -> s_ed_reason = *base++;
			if (li == 1 && SP_OK (s -> s_ed_reason))
			    Set (SMASK_ED_REASON);
			else
			    s -> s_errno = SC_PROTOCOL;
			break;
		    case SPDU_AI: 
			If_Set (SMASK_SPDU_AB) {
			    s -> s_errno = SC_PROTOCOL;
			    break;
			}
			s -> s_ai_reason = *base++;
			if (li == 1 && SP_OK (s -> s_ai_reason))
			    Set (SMASK_AI_REASON);
			else
			    s -> s_errno = SC_PROTOCOL;
			break;
		    case SPDU_AD: 
			s -> s_ad_reason = *base++;
			if (li == 1 && SP_OK (s -> s_ad_reason))
			    Set (SMASK_AD_REASON);
			else
			    s -> s_errno = SC_PROTOCOL;
			break;
		    default: 
			s -> s_errno = SC_PROTOCOL;
			break;
		}
		break;

	    case PI_REFLECT: 
		switch (si) {
		    case SPDU_AB: 
			If_Reset (SMASK_SPDU_AB) {
			    s -> s_errno = SC_PROTOCOL;
			    break;
			}
			if (li > AB_REFL_SIZE) {
			    s -> s_errno = SC_PROTOCOL;
			    break;
			}
			bcopy (base, (char *) s -> s_reflect, li);
			Set (SMASK_AB_REFL);
			break;
		    case SPDU_ER: 
			s -> s_udata = malloc ((unsigned) (s -> s_ulen = li));
			if (s -> s_udata == NULL) {
			    s -> s_errno = SC_CONGEST;
			    break;
			}
			bcopy (base, s -> s_udata, li);
			break;
		    default: 
			s -> s_errno = SC_PROTOCOL;
			break;
		}
		base += li;
		break;

	    case PI_SSAP_CALLING: 
		bcopy (base, s -> s_calling, s -> s_callinglen = li);
		Set (SMASK_CN_CALLING);
		base += li;
		break;

	    case PI_SSAP_CALLED: 
		bcopy (base, s -> s_called, s -> s_calledlen = li);
		Set (SMASK_CN_CALLED);
		base += li;
		break;

	    case PI_PREPARE: 
		if ((s -> s_pr_type = *base++) > PR_MAX)
		    s -> s_errno = SC_PROTOCOL;
		else
		    Set (SMASK_PR_TYPE);
		break;

	    default: 
		s -> s_errno = SC_PROTOCOL;
		break;
	}
    }
/* NB: caller responsible for mapping user info to s -> s_qbuf */

    if (cc)
	*cc = nread;
    {				/* "dangling" qbuf */
	register struct qbuf *qp;

	if ((qp = qb -> qb_forw) != qb && qp -> qb_len <= 0) {
	    remque (qp);

	    free ((char *) qp);
	}
    }

    switch (s -> s_code) {
	case SPDU_AB: 
	    If_Set (SMASK_SPDU_AB) {
		If_Reset (SMASK_AB_DISC)
		    s -> s_errno = SC_PROTOCOL;
	    }
	    break;

	case SPDU_MIP: 
	    If_Reset (SMASK_MIP_SERIAL)
		s -> s_errno = SC_PROTOCOL;
	    break;

	case SPDU_MAP: 
	    If_Reset (SMASK_MAP_SERIAL)
		s -> s_errno = SC_PROTOCOL;
	    break;

	case SPDU_MIA: 
	    If_Reset (SMASK_MIA_SERIAL)
		s -> s_errno = SC_PROTOCOL;
	    break;

	case SPDU_MAA: 
	    If_Reset (SMASK_MAA_SERIAL)
		s -> s_errno = SC_PROTOCOL;
	    break;

	case SPDU_RS: 
	    If_Reset (SMASK_RS_TYPE)
		s -> s_errno = SC_PROTOCOL;
	    If_Reset (SMASK_RS_SSN)
		s -> s_errno = SC_PROTOCOL;
	    break;

	case SPDU_RA: 
	    If_Reset (SMASK_RA_SSN)
		s -> s_errno = SC_PROTOCOL;
	    break;

	case SPDU_PR: 
	    If_Reset (SMASK_PR_TYPE)
		s -> s_errno = SC_PROTOCOL;
	    break;

	case SPDU_ED: 
	    If_Reset (SMASK_ED_REASON)
		s -> s_errno = SC_PROTOCOL;
	    break;

	case SPDU_AS: 
	    If_Reset (SMASK_AS_ID)
		s -> s_errno = SC_PROTOCOL;
	    break;

	case SPDU_AR: 
	    If_Reset (SMASK_AR_OID)
		s -> s_errno = SC_PROTOCOL;
	    If_Reset (SMASK_AR_SSN)
		s -> s_errno = SC_PROTOCOL;
	    If_Reset (SMASK_AR_ID)
		s -> s_errno = SC_PROTOCOL;
	    break;
    }

#ifdef	DEBUG
    if (ssap_log -> ll_events & LLOG_PDUS)
	spkt2text (ssap_log, s, 1);
#endif

    return s;
}

/* \f

 */

struct ssapkt *newspkt (code)
int	code;
{
    register struct ssapkt *s;

    s = (struct ssapkt *) calloc (1, sizeof *s);
    if (s == NULL)
	return NULL;

    s -> s_code = code;
    s -> s_qbuf.qb_forw = s -> s_qbuf.qb_back = &s -> s_qbuf;

    return s;
}


int	freespkt (s)
register struct ssapkt *s;
{
    if (s == NULL)
	return;

    switch (s -> s_code) {
	case SPDU_RF: 
	    if (s -> s_rdata)
		free (s -> s_rdata);/* and fall... */

	default: 
	    if (s -> s_udata)
		free (s -> s_udata);
	    QBFREE (&s -> s_qbuf);
	    break;
    }

    free ((char *) s);
}