OpenSS7
SS7 for the
Common Man

© Copyright 1997-2004,OpenSS7 Corporation, All Rights Reserved.
Last modified:

Home Overview Status News Documentation Resources About
   
 Overview
 Status
 News
 Documentation
 Resources
 About

   
Home Index Prev Next More Download Info FAQ Mail   Home -> Resources -> Browse Source -> strss7/drivers/sscop/sscop.c


File /code/strss7/drivers/sscop/sscop.c



#ident "@(#) $RCSfile: sscop.c,v $ $Name:  $($Revision: 0.8.2.2 $) $Date: 2003/04/14 12:13:33 $"

static char const ident[] =
    "$RCSfile: sscop.c,v $ $Name:  $($Revision: 0.8.2.2 $) $Date: 2003/04/14 12:13:33 $";

/*
 *  This driver provides the functionality of SSCOP-MCE over a connectionless
 *  network provider (NPI).  It is suitable for use with an IP network
 *  provider or a UDP network provider.
 */

#define SSCOP_DESCRIP	"SSCOPMCE/IP STREAMS DRIVER."
#define SSCOP_COPYRIGHT	"Copyright (c) 1997-2002 OpenSS7 Corporation.  All Rights Reserved."
#define SSCOP_DEVICE	"Part of the OpenSS7 Stack for LiS STREAMS."
#define SSCOP_CONTACT	"Brian Bidulock <bidulock@openss7.org>"
#define SSCOP_LICENSE	"GPL"
#define SSCOP_BANNER	SSCOP_DESCRIP	"\n" \
			SSCOP_COPYRIGHT	"\n" \
			SSCOP_DEVICE	"\n" \
			SSCOP_CONTACT	"\n"

#ifdef MODULE
MODULE_AUTHOR(SSCOP_CONTACT);
MODULE_DESCRIPTION(SSCOP_DESCRIP);
MODULE_SUPPORTED_DEVICE(SCCOP_DEVICE);
#ifdef MODULE_LICENSE
MODULE_LICENSE(SSCOP_LICENSE);
#endif
#define MODULE_STATIC static
#else
#define MOD_INC_USE_COUNT
#define MOD_DEC_USE_COUNT
#endif

#ifdef SCCOP_DEBUG
static int sscop_debug = SSCOP_DEBUG;
#else
static int sscop_debug = 2;
#endif

#ifndef SSCOP_CMAJOR
#define SSCOP_CMAJOR 240
#endif
#define SSCOP_NMINOR 255

#ifdef LIS_2_12
#define INT int
#else
#define INT void
#endif

/*
 *  =========================================================================
 *
 *  STREAMS Defintions
 *
 *  =========================================================================
 */

static struct module_info sscop_minfo = {
	0,				/* Module ID number */
	"sscop-mce",			/* Module name */
	1,				/* Min packet size accepted */
	512,				/* Max packet size accepted */
	8 * 512,			/* Hi water mark */
	1 * 512				/* Lo water mark */
};

static INT sscop_rput(queue_t *, mblk_t *);
static INT sscop_rsrv(queue_t *);
static int sscop_open(queue_t *, dev_t *, int, int, cred_t *);
static int sscop_close(queue_t *, int, cred_t *);

static struct qinit sscop_rinit = {
	sscop_rput,			/* Read put (msg from below) */
	sscop_rsrv,			/* Read queue service */
	sscop_open,			/* Each open */
	sscop_close,			/* Last close */
	NULL,				/* Admin (not used) */
	&sscop_minfo,			/* Information */
	NULL				/* Statistics */
};

static INT sscop_wput(queue_t *, mblk_t *);
static INT sscop_wsrv(queue_t *);

static struct qinit sscop_winit = {
	sscop_wput,			/* Write put (msg from above) */
	sscop_wsrv,			/* Write queue service */
	NULL,				/* Each open */
	NULL,				/* Last close */
	NULL,				/* Admin (not used) */
	&sscop_minfo,			/* Information */
	NULL				/* Statistics */
};

MODULE_STATIC struct streamtab sscop_info = {
	&sscop_rinit,			/* Upper read queue */
	&sscop_winit,			/* Upper write queue */
	NULL,				/* Lower read queue */
	NULL				/* Lower write queue */
};

/*
 *  =========================================================================
 *
 *  SSCOP Private Structures
 *
 *  =========================================================================
 */

#define AA_ESTABLISH_REQ		0
#define AA_ESTABLISH_RES		1
#define AA_RELEASE_REQ			2
#define AA_DATA_REQ			3
#define AA_INFO_REQ			5
#define AA_BIND_REQ			6
#define AA_UNBIND_REQ			7
#define AA_UNITDATA_REQ			8
#define AA_OPTMGMT_REQ			9

#define AA_ESTABLISH_IND		11
#define AA_ESTABLISH_CON		12
#define AA_RELEASE_IND			13
#define AA_DATA_IND			14
#define AA_INFO_ACK			16
#define AA_BIND_ACK			17
#define AA_ERROR_ACK			18
#define AA_OK_ACK			19
#define AA_UNITDATA_IND			20

#define AA_DATACK_REQ			23
#define AA_DATACK_IND			24
#define AA_RESYNC_REQ			25
#define AA_RESYNC_IND			26
#define AA_RESYNC_RES			27
#define AA_RESYNC_CON			28

#define AA_RECOVER_IND			21
#define AA_RECOVER_RES			22
#define AA_RETRIEVE_REQ			29
#define AA_RETRIEVE_IND			30
#define AA_RETRIEVE_COMPLETE_IND	31

//#define AA_UDERROR_IND    mapped to MAA_ERROR_IND
//#define AA_EXDATA_REQ
//#define AA_EXDATA_IND
//
#define MAA_ERROR_IND
#define MAA_UNITDATA_REQ
#define MAA_UNITDATA_IND
//#define MAA_SET_TIMER_REQ
//#define MAA_ADD_LINK_REQ
//#define MAA_REMOVE_LINK_REQ
//#define MAA_REMOVE_LINK_IND

#define A_UNINIT		0
#define A_UNBND			1
#define	A_IDLE			2
#define A_OUTCON		3
#define A_INCON			4
#define A_DATAXFER		5
#define A_OUTREL		6
#define A_INREL			7	(not used)
#define A_FAKE			8	(not used)
#define A_HACK			12
#define A_OUTRES		16
#define A_INRES			17
#define A_OUTREC		18
#define A_INREC			19
#define A_RECOVERY		20

#define AS_UNBND		0
#define AS_WACK_BREQ		1
#define AS_WACK_UREQ		2
#define AS_IDLE			3
#define AS_WACK_OPTREQ		4
#define AS_WACK_RRES		5
#define AS_WCON_CREQ		6
#define AS_WRES_CIND		7
#define AS_WACK_CRES		8
#define AS_DATA_XFER		9
#define AS_WCON_RREQ		10
#define AS_WRES_RIND		11
#define AS_WACK_DREQ6		12
#define AS_WACK_DREQ7		13
#define AS_WACK_DREQ9		14
#define AS_WACK_DREQ10		15
#define AS_WACK_DREQ11		16
#define AS_WIND_ERROR		17
#define AS_WRES_VIND		18

#define AE_PDU_BGAK		    (1<<0)
#define AE_PDU_BGN		    (1<<1)
#define AE_PDU_BGREJ		    (1<<2)
#define AE_PDU_BREJ		    (1<<3)
#define AE_PDU_END		    (1<<4)
#define AE_PDU_ENDAK		    (1<<5)
#define AE_PDU_ER		    (1<<6)
#define AE_PDU_ERAK		    (1<<7)
#define AE_PDU_MD		    (1<<8)
#define AE_PDU_POLL		    (1<<9)
#define AE_PDU_RS		    (1<<10)
#define AE_PDU_RSAK		    (1<<11)
#define AE_PDU_SD		    (1<<12)
#define AE_PDU_STAT		    (1<<13)
#define AE_PDU_UD		    (1<<14)
#define AE_PDU_USTAT		    (1<<15)

#define AE_INFO_REQ		    (1<<0)
#define AE_INFO_ACK		    (1<<1)
#define AE_BIND_REQ		    (1<<2)
#define AE_BIND_ACK		    (1<<3)
#define AE_UNBIND_REQ		    (1<<4)
#define AE_OPTMGMT_REQ		    (1<<5)
#define AE_ERROR_ACK		    (1<<6)
#define AE_OK_ACK		    (1<<7)
#define AE_ESTABLISH_REQ	    (1<<8)
#define AE_ESTABLISH_IND	    (1<<9)
#define AE_ESTABLISH_RES	    (1<<10)
#define AE_ESTABLISH_CON	    (1<<11)
#define AE_RELEASE_REQ		    (1<<12)
#define AE_RELEASE_IND		    (1<<13)
#define AE_DATA_REQ		    (1<<14)
#define AE_DATA_IND		    (1<<15)
#define AE_DATACK_REQ		    (1<<16)
#define AE_DATACK_IND		    (1<<17)
#define AE_RESYNC_REQ		    (1<<18)
#define AE_RESYNC_IND		    (1<<19)
#define AE_RESYNC_RES		    (1<<20)
#define AE_RESYNC_CON		    (1<<21)
#define AE_RECOVER_IND		    (1<<22)
#define AE_RECOVER_RES		    (1<<23)
#define AE_UNITDATA_REQ		    (1<<24)
#define AE_UNITDATA_IND		    (1<<25)
#define AE_RETRIEVE_REQ		    (1<<26)
#define AE_RETRIEVE_IND		    (1<<27)
#define AE_RETRIEVE_COMPLETE_IND    (1<<28)

#define AE_TIMEOUT_CC		    (1<<29)
#define AE_TIMEOUT_POLL		    (1<<30)

#define SSCOP_BGN	0x01
#define SSCOP_BGAK	0x02
#define SSCOP_END	0x03
#define SSCOP_ENDAK	0x04
#define SSCOP_RS	0x05
#define SSCOP_RSAK	0x06
#define SSCOP_BGREJ	0x07
#define SSCOP_SD	0x08
#define SSCOP_ER	0x09
#define SSCOP_POLL	0x0a
#define SSCOP_STAT	0x0b
#define SSCOP_USTAT	0x0c
#define SSCOP_UD	0x0d
#define SSCOP_MD	0x0e
#define SSCOP_ERAK	0x0f

/*
 *  AA_INFO_REQ
 */
struct AA_info_req {
	ulong PRIM_type;
};
/*
 *  AA_INFO_ACK
 */
struct AA_info_ack {
	ulong PRIM_type;
	ulong NSDU_size;		/* maximum NSDU size */
	ulong ENSDU_size;		/* maximum ENSDU size */
	ulong CDATA_size;		/* connect data size */
	ulong DDATA_size;		/* discon data size */
	ulong ADDR_size;		/* address size */
	ulong ADDR_length;		/* address length */
	ulong ADDR_offset;		/* address offset */
	ulong QOS_length;		/* QOS values length */
	ulong QOS_offset;		/* QOS values offset */
	ulong QOS_range_length;		/* length of QOS values' range */
	ulong QOS_range_offset;		/* offset of QOS values' range */
	ulong OPTIONS_flags;		/* bit masking for options supported */
	ulong NIDU_size;		/* network i/f data unit size */
	long SERV_type;			/* service type */
	ulong CURRENT_state;		/* current state */
	ulong PROVIDER_type;		/* type of NS provider */
	ulong NODU_size;		/* optimal NSDU size */
	ulong PROTOID_length;		/* length of bound protocol ids */
	ulong PROTOID_offset;		/* offset of bound protocol ids */
	ulong NPI_version;		/* version # of npi that is supported */
};
/*
 *  AA_BIND_REQ
 */
struct AA_bind_req {
	ulong PRIM_type;		/* always AA_BIND_REQ */
	ulong ADDR_length;		/* length of address */
	ulong ADDR_offset;		/* offset of address */
	ulong CONIND_number;		/* requested # of connect-indications to be queued */
	ulong BIND_flags;		/* bind flags */
	ulong PROTOID_length;		/* length of bound protocol ids */
	ulong PROTOID_offset;		/* offset of bound protocol ids */
};
/*
 *  AA_BIND_ACK
 */
struct AA_bind_ack {
	ulong PRIM_type;		/* always N_BIND_ACK */
	ulong ADDR_length;		/* address length */
	ulong ADDR_offset;		/* offset of address */
	ulong CONIND_number;		/* connection indications */
	ulong TOKEN_value;		/* value of "token" assigned to stream */
	ulong PROTOID_length;		/* length of bound protocol ids */
	ulong PROTOID_offset;		/* offset of bound protocol ids */
};
/*
 *  AA_UNBIND_REQ
 */
struct AA_unbind_req {
	ulong PRIM_type;
};
/*
 *  AA_OPTMGMT_REQ
 */
struct AA_optmgmt_req {
	ulong PRIM_type;
	ulong QOS_length;
	ulong QOS_offset;
	ulong OPTMGMT_flags;
};
/*
 *  AA_ERROR_ACK
 */
struct AA_error_ack {
	ulong PRIM_type;		/* always N_ERROR_ACK */
	ulong ERROR_prim;		/* primitive in error */
	ulong NPI_error;		/* NPI error code */
	ulong UNIX_error;		/* UNIX error code */
};
/*
 *  AA_OK_ACK
 */
struct AA_ok_ack {
	np_ulong PRIM_type;		/* always N_OK_ACK */
	np_ulong CORRECT_prim;		/* primitive being acknowledged */
};
/*
 *  AA_ESTABLISH_REQ (M_PROTO, 0 or more M_DATA)
 */
struct AA_establish_req {
	ulong PRIM_type;
	ulong DEST_length;
	ulong DEST_offset;
	ulong CONN_flags;		/* BR option */
	ulong QOS_length;
	ulong QOS_offset;
};
/*
 *  AA_ESTABLISH_IND (M_PROTO, 0 or more M_DATA)
 */
struct AA_establish_ind {
	ulong PRIM_type;
	ulong DEST_length;
	ulong DEST_offset;
	ulong SRC_length;
	ulong SRC_offset;
	ulong SEQ_number;
	ulong CONN_flags;
	ulong QOS_length;
	ulong QOS_offset;
};
/*
 *  AA_ESTABLISH_RES (M_PROTO, 0 or more M_DATA)
 */
struct AA_establish_res {
	ulong PRIM_type;
	ulong TOKEN_value;
	ulong RES_length;
	ulong RES_offset;
	ulong SEQ_number;
	ulong CONN_flags;		/* BR option */
	ulong QOS_length;
	ulong QOS_offset;
};
/*
 *  AA_ESTABLISH_CON (M_PROTO, 0 or more M_DATA)
 */
struct AA_establish_con {
	ulong PRIM_type;
	ulong RES_length;
	ulong RES_offset;
	ulong CONN_flags;
	ulong QOS_length;
	ulong QOS_offset;
};
/*
 *  AA_RELEASE_REQ (M_PROTO, 0 or more M_DATA)
 */
struct AA_release_req {
	ulong PRIM_type;
	ulong DISCON_reason;
	ulong RES_length;
	ulong RES_offset;
	ulong SEQ_number;
};
/*
 *  AA_RELEASE_IND (M_PROTO, 0 or more M_DATA)
 */
struct AA_release_ind {
	ulong PRIM_type;
	ulong DISCON_orig;		/* Source */
	ulong RES_length;
	ulong RES_offset;
	ulong SEQ_number;
};
/*
 *  AA_DATA_REQ (M_PROTO, 1 or more M_DATA )
 */
struct AA_data_req {
	ulong PRIM_type;
	ulong DATA_xfer_flags;		/* OOS */
};
/*
 *  AA_DATA_IND (M_PROTO, 1 or more M_DATA)
 */
struct AA_data_ind {
	ulong PRIM_type;
	ulong DATA_xfer_flags;		/* OOS */
	ulong PDU_sequence;		/* SN *//* in addition to NPI */
};
/*
 *  AA_DATACK_REQ (M_PROTO)
 */
struct AA_datack_req {
	ulong PRIM_type;
};
/*
 *  AA_DATACK_IND (M_PROTO) (not used)
 */
struct AA_datack_ind {
	ulong PRIM_type;
	ulong PDU_sequence;		/* SN *//* in addition to NPI */
};
/*
 *  AA_RESYNC_REQ (M_PROTO, 0 or more M_DATA)
 */
struct AA_resync_req {
	ulong PRIM_type;
	ulong RESET_reason;		/* not used */
};
/*
 *  AA_RESYNC_IND (M_PROTO, 0 or more M_DATA)
 */
struct AA_resync_ind {
	ulong PRIM_type;
	ulong RESET_orig;
	ulong RESET_reason;
};
/*
 *  AA_RESYNC_RES (M_PROTO)
 */
struct AA_resync_res {
	ulong PRIM_type;
};
/*
 *  AA_RESYNC_CON (M_PROTO)
 */
struct AA_resync_con {
	ulong PRIM_type;
};
/*
 *  AA_RECOVER_IND (M_PROTO)	(not in NPI)
 */
struct AA_recover_ind {
	ulong PRIM_type;
};
/*
 *  AA_RECOVER_RES (M_PROTO)	(not in NPI)
 */
struct AA_recover_res {
	ulong PRIM_type;
};
/*
 *  AA_UNITDATA_REQ (M_PROTO, 0 or more M_DATA)
 */
struct AA_unitdata_req {
	ulong PRIM_type;
	ulong DEST_length;
	ulong DEST_offset;
	ulong RESERVED_field[2];
};
/*
 *  AA_UNITDATA_IND (M_PROTO, 0 or more M_DATA)
 */
struct AA_unitdata_req {
	ulong PRIM_type;
	ulong DEST_length;
	ulong DEST_offset;
	ulong SRC_length;
	ulong SRC_offset;
	ulong RESERVED_field;
};
/*
 *  AA_RETRIEVE_REQ (M_PROTO)	(not in NPI)
 */
struct AA_retieve_req {
	ulong PRIM_type;
	ulong RETRIEVE_sequence;
};
/*
 *  AA_RETRIEVE_IND (M_PROTO, 0 or more M_DATA)	(not in NPI)
 */
struct AA_retrieve_ind {
	ulong PRIM_type;
};
/*
 *  AA_RETRIEVE_COMPLETE_IND (M_PROTO)	(not in NPI)
 */
struct AA_retrieve_complete_ind {
	ulong PRIM_type;
};

/*
 *  MAA_ERROR_IND   (M_PROTO)	(not in NPI)
 */
struct MAA_error_ind {
	ulong PRIM_type;
	ulong DEST_length;
	ulong DEST_offset;
	ulong RESERVED_field;
	ulong ERROR_type;
	ulong ERROR_count;		/* not in NPI */
};
/*
 *  MAA_UNITDATA_REQ (M_PROTO, 0 or more M_DATA)
 */
#define MAA_unitdata_req    AA_unitdata_req
/*
 *  MAA_UNITDATA_IND (M_PROTO, 0 or more M_DATA)
 */
#define MAA_unitdata_ind    AA_unitdata_ind

/*
 *  =========================================================================
 *
 *  SSCOP Message Structures
 *
 *  =========================================================================
 */

/*
 *  =========================================================================
 *
 *  SSCOP AA-Provider --> AA-User Primitives
 *
 *  =========================================================================
 */
/*
 *  AA_INFO_ACK
 *  -------------------------------------------------------------------------
 */
static __inline__ mblk_t *aa_info_ack(queue_t * q)
{
	mblk_t *mp;
	struct AA_info_ack *p;
	sscop_t *sp = (sscop_t *) q->q_ptr;
	if ((mp = allocb(sizeof(*p) + add_len + qos_len + rng_len + pro_len, BPRI_MED))) {
		mp->b - datap->db_type = M_PCPROTO;
		p = (struct AA_info_ack *) mp->b_wptr;
		p->PRIM_type = AA_INFO_ACK;
		p->NSDU_size = -1;
		p->ENSDU_size = 0;
		p->CDATA_size = -1;
		p->DDATA_size = -1;
		p->ADDR_size = sizeof(uint16_t) + sizeof(uint32_t);
		p->ADDR_length = add_len;
		p->ADDR_offset = add_len ? sizeof(*p) : 0;
		p->QOS_length = qos_len;
		p->QOS_offset = qos_len ? sizeof(*p) + add_len : 0;
		p->QOS_range_length = rng_len;
		p->QOS_range_offset = rng_len ? sizeof(*p) + add_len + qos_len : 0;
		p->OPTIONS_flags = 0;
		p->NIDU_size = -1;
		p->SERV_type = FIXME;
		p->CURRENT_state = sp->state;
		p->PROVIDER_type = FIXME;
		p->NODU_size = FIXME;
		p->PROTOID_length = pro_len;
		p->PROTOID_offset = pro_len ? sizeof(*p) + add_len + qos_len + rng_len : 0;
		p->NPI_version = FIXME;
		mp->b_wptr += sizeof(*p);
		bcopy(add_ptr, mp->b_wptr, add_len);
		mp->b_wptr += add_len;
		bcopy(qos_ptr, mp->b_wptr, qos_len);
		mp->b_wptr += qos_len;
		bcopy(rng_ptr, mp->b_wptr, rng_len);
		mp->b_wptr += rng_len;
		bcopy(pro_ptr, mp->b_wptr, pro_len);
		mp->b_wptr += pro_len;
	}
	return (mp);
}

/*
 *  AA_BIND_ACK
 *  -------------------------------------------------------------------------
 */
static __inline__ mblk_t *aa_bind_ack()
{
	mblk_t *mp;
	struct AA_bind_req *p;
	if ((mp = allocb(sizeof(*p) + add_len + pro_len, BPRI_MED))) {
		mp->b_datap->db_type = M_PCPROTO;
		p = (struct AA_bind_req *) mp->b_wptr;
		p->PRIM_type = AA_BIND_ACK;
		p->ADDR_length = add_len;
		p->ADDR_offset = add_len ? sizeof(*p) : 0;
		p->CONIND_number = sp->cons;
		p->BIND_flags = FIXME;
		p->PROTOID_length = pro_len;
		p->PROTOID_offset = pro_len ? sizeof(*p) + add_len : 0;
		mp->b_wptr += sizeof(*p);
		bcopy(add_ptr, mp->b_wptr, add_len);
		mp->b_wptr += add_len;
		bcopy(pro_ptr, mp->b_wptr, pro_len);
		mp->b_wptr += pro_len;
	}
	return (mp);
}

/*
 *  AA_ERROR_ACK
 *  -------------------------------------------------------------------------
 */
static __inline__ mblk_t *aa_error_ack(ulong prim, long err)
{
	mblk_t *mp;
	struct AA_error_ack *p;
	if ((mp = allocb(sizeof(*p), BPRI_MED))) {
		mp->b_datap->db_type = M_PCPROTO;
		p = (struct AA_error_ack *) mp->b_wptr;
		p->PRIM_type = AA_ERROR_ACK;
		p->ERROR_prim = prim;
		p->NPI_error = err > 0 ? err : AASYSERR;
		p->UNIX_error = err < 0 ? -err : 0;
		mp->b_wptr += sizeof(*p);
	}
	return (mp);
}

/*
 *  AA_OK_ACK
 *  -------------------------------------------------------------------------
 */
static __inline__ mblk_t *aa_ok_ack(ulong prim)
{
	mblk_t *mp;
	struct AA_ok_ack *p;
	if ((mp = allocb(sizeof(*p), BPRI_MED))) {
		mp->b_datap->db_type = M_PCPROTO;
		p = (struct AA_ok_ack *) mp->b_wptr;
		p->PRIM_type = AA_OK_ACK;
		p->CORRECT_prim = prim;
		mp->b_wptr += sizeof(*p);
	}
	return (mp);
}

/*
 *  AA_ESTABLISH_IND
 *  -------------------------------------------------------------------------
 */
static __inline__ mblk_t *aa_establish_ind(dst_ptr, dst_len, src_ptr, src_len,
					   seq, flags, qos_ptr, qos_len, db)
	caddr_t dst_ptr;
	size_t dst_len;
	caddr_t src_ptr;
	size_t src_len;
	ulong seq;
	ulong flags;
	caddr_t qos_ptr;
	size_t qos_len;
	mblk_t *db;
{
	mblk_t *mp;
	struct AA_establish_ind *p;
	if ((mp = allocb(sizeof(*p) + dst_len + src_len + qos + len, BPRI_MED))) {
		mp->b_datap->db_type = M_PROTO;
		p = (struct AA_establish_ind *) mp->b_wptr;
		p->PRIM_type = AA_ESTABLISH_IND;
		p->DEST_length = dst_len;
		p->DEST_offset = dst_len ? sizeof(*p) : 0;
		p->SRC_length = src_len;
		p->SRC_offset = src_len ? sizeof(*p) + dst_len : 0;
		p->SEQ_number = seq;
		p->CONN_flags = flags;
		p->QOS_length = qos_len;
		p->QOS_offset = qos_len ? sizeof(*p) + dst_len + src_len : 0;
		mp->b_wptr += sizeof(*p);
		bcopy(dst_ptr, mp->b_wptr, dst_len);
		mp->b_wptr += dst_len;
		bcopy(src_ptr, mp->b_wptr, src_len);
		mp->b_wptr += src_len;
		bcopy(qos_ptr, mp->b_wptr, qos_len);
		mp->b_wptr += qos_len;
		mp->b_cont = db;
	}
	return (mp);
}

/*
 *  AA_ESTABLISH_CON
 *  -------------------------------------------------------------------------
 */
static __inline__ mblk_t *aa_establish_con(res_ptr, res_len, flags, qos_ptr, qos_len, db)
	caddr_t res_ptr;
	size_t res_len;
	uint flags;
	caddr_t qos_ptr;
	size_t qos_len;
	mblk_t *db;
{
	mblk_t *mp;
	struct AA_establish_con *p;
	if ((mp = allocb(sizeof(*p) + res_len + qos_len, BPRI_MED))) {
		mp->b_datap->db_type = M_PROTO;
		p = (struct AA_establish_con *) mp->b_wptr;
		p->PRIM_type = AA_ESTABLISH_CON;
		p->RES_length = res_len;
		p->RES_offset = res_len ? sizeof(*p) : 0;
		p->CONN_flags = flags;
		p->QOS_length = res_len;
		p->QOS_offset = res_len ? sizeof(*p) : 0;
		mp->b_wptr += sizeof(*p);
		bcopy(res_ptr, mp->b_wptr, res_len);
		mp->b_wptr += res_len;
		bcopy(qos_ptr, mp->b_wptr, qos_len);
		mp->b_wptr += qos_len;
		mp->b_cont = db;
	}
	return (mp);
}

/*
 *  AA_RELEASE_IND
 *  -------------------------------------------------------------------------
 */
static __inline__ mblk_t *aa_release_ind(orig, res_ptr, res_len, seq, db)
	uint orig;
	caddr_t res_ptr;
	size_t res_len;
	uint seq;
	mblk_t *db;
{
	mblk_t *mp;
	struct AA_release_ind *p;
	if ((mp = allocb(sizeof(*p) + res_len, BPRI_MED))) {
		mp->b_datap->db_type = M_PROTO;
		p = (struct AA_release_ind *) mp->b_wptr;
		p->PRIM_type = AA_RELEASE_IND;
		p->DISCON_orig = orig;
		p->RES_length = res_len;
		p->RES_offset = res_len ? sizeof(*p) : 0;
		p->SEQ_number = seq;
		mp->b_wptr += sizeof(*p);
		bcopy(res_ptr, mp->b_wptr, res_len);
		mp->b_wptr += res_len;
		mp->b_cont = db;
	}
	return (mp);
}

/*
 *  AA_DATA_IND
 *  -------------------------------------------------------------------------
 */
static __inline__ mblk_t *aa_data_ind(flags, seqno, db)
	ulong flags;
	ulong seqno;
	mblk_t *db;
{
	mblk_t *mp;
	struct AA_data_ind *p;
	if ((mp = allocb(sizeof(*p), BPRI_MED))) {
		mp->b_datap->db_type = M_PROTO;
		p = (struct AA_data_ind *) mp->b_wptr;
		p->PRIM_type = AA_DATA_IND;
		p->DATA_xfer_flags = flags;
		p->PDU_sequence = seqno;
		mp->b_wptr += sizeof(*p);
	}
	return (mp);
}

/*
 *  AA_DATACK_IND
 *  -------------------------------------------------------------------------
 */
static __inline__ mblk_t *aa_datack_ind(seqno, db)
	ulong seqno;
	mblk_t *db;
{
	mblk_t *mp;
	struct AA_datack_ind *p;
	if ((mp = allocb(sizeof(*p), BPRI_MED))) {
		mp->b_datap->db_type = M_PROTO;
		p = (struct AA_datack_ind *) mp->b_wptr;
		p->PRIM_type = AA_DATACK_IND;
		p->PDU_sequence = seqno;
		mp->b_wptr += sizeof(*p);
	}
	return (mp);
}

/*
 *  AA_RESYNC_IND
 *  -------------------------------------------------------------------------
 */
static __inline__ mblk_t *aa_resync_ind(orig, reason, db)
	ulong orig;
	ulong reason;
	mblk_t *db;
{
	mblk_t *mp;
	struct AA_resync_ind *p;
	if ((mp = allocb(sizeof(*p), BPRI_MED))) {
		mp->b_datap->db_type = M_PROTO;
		p = (struct AA_resync_ind *) mp->b_wptr;
		p->PRIM_type = AA_RESYNC_IND;
		mp->b_wptr += sizeof(*p);
		mp->b_cont = db;
	}
      return (mp):
}

/*
 *  AA_RESYNC_IND
 *  -------------------------------------------------------------------------
 */
static __inline__ mblk_t *aa_resync_ind(orig, reason, db)
	ulong orig;
	ulong reason;
	mblk_t *db;
{
	mblk_t *mp;
	struct AA_resync_ind *p;
	if ((mp = allocb(sizeof(*p), BPRI_MED))) {
		mp->b_datap->db_type = M_PROTO;
		p = (struct AA_resync_ind *) mp->b_wptr;
		p->PRIM_type = AA_RESYNC_IND;
		mp->b_wptr += sizeof(*p);
		mp->b_cont = db;
	}
      return (mp):
}

/*
 *  AA_RECOVER_IND
 *  -------------------------------------------------------------------------
 */
static __inline__ mblk_t *aa_recover_ind(void)
{
	mblk_t *mp;
	struct AA_recover_ind *p;
	if ((mp = allocb(sizoef(*p), BPRI_MED))) {
		mp->b_datap->db_type = M_PROTO;
		p = (struct AA_recover_ind *) mp->b_wptr;
		p->PRIM_type = AA_RECOVER_IND;
		mp->b_wptr += sizeof(*p);
	}
	return (mp);
}

/*
 *  AA_UNITDATA_IND
 *  -------------------------------------------------------------------------
 */
static __inline__ mblk_t *aa_unitdata_ind(dst_ptr, dst_len, src_ptr, src_len, db)
	caddr_t dst_ptr;
	size_t dst_len;
	caddr_t src_ptr;
	size_t src_len;
	mblk_t *db;
{
	mblk_t *mp;
	struct AA_unitdata_ind *p;
	if ((mp = allocb(sizeof(*p) + dst_len + src_len, BPRI_MED))) {
		mp->b_datap->db_type = M_PROTO;
		p = (struct AA_unitdata_ind *) mp->b_wptr;
		p->PRIM_type = AA_UNITDATA_IND;
		p->DEST_length = dst_len;
		p->DEST_offset = dst_len ? sizeof(*p) : 0;
		p->SRC_length = src_len;
		p->SRC_offset = src_len ? sizeof(*p) + dst_len : 0;
		mp->b_wptr += sizeof(*p);
		bcopy(dst_ptr, mp->b_wptr, dst_len);
		mp->b_wptr += dst_len;
		bcopy(src_ptr, mp->b_wptr, src_len);
		mp->b_wptr += src_len;
		mp->b_cont = db;
	}
	return (mp);
}

/*
 *  AA_RETRIEVE_IND
 *  -------------------------------------------------------------------------
 */
static __inline__ mblk_t *aa_retrieve_ind(db)
	mblk_t *db;
{
	mblk_t *mp;
	struct AA_retrieve_ind *p;
	if ((mp = allocb(sizeof(*p), BPRI_MED))) {
		mp->b_datap->db_type = M_PROTO;
		p = (struct AA_retrieve_ind *) mp->b_wptr;
		p->PRIM_type = AA_RETRIEVE_IND;
		mp->b_wptr += sizeof(*p);
		mp->b_cont = db;
	}
	return (mp);
}

/*
 *  AA_RETRIEVE_COMPLETE
 *  -------------------------------------------------------------------------
 */
static __inline__ mblk_t *aa_retrieve_complete_ind(void)
{
	mblk_t *mp;
	struct AA_retrieve_complete_ind *p;
	if ((mp = allocb(sizeof(*p), BPRI_MED))) {
		mp->b_datap->db_type = M_PROTO;
		p = (struct AA_retrieve_complete_ind *) mp->b_wptr;
		p->PRIM_type = AA_RETRIEVE_COMPLETE_IND;
		mp->b_wptr += sizeof(*p);
	}
	return (mp);
}

/*
 *  MAA_ERROR_IND
 *  -------------------------------------------------------------------------
 */
static __inline__ mblk_t *maa_error_ind(dst_ptr, dst_len, code, count)
	caddr_t dst_ptr;
	size_t dst_len;
	uint code;
	uint count;
{
	mblk_t *mp;
	struct MAA_error_ind *p;
	if ((mp = allocb(sizeof(*p) + dst_len, BPRI_MED))) {
		mp->b_datap->db_type = M_PROTO;
		p = (struct MAA_error_ind *) mp->b_wptr;
		p->PRIM_type = MAA_ERROR_IND;
		p->DEST_length = dst_len;
		p->DEST_offset = dst_len ? sizeof(*p) : 0;
		p->RESERVED_field = 0;
		p->ERROR_type = code;
		p->ERROR_count = count;
		mp->b_wptr += sizeof(*p);
	}
	return (mp);
}

/*
 *  MAA_UNITDATA_IND
 *  -------------------------------------------------------------------------
 */
static __inline__ mblk_t *maa_unitdata_ind(dst_ptr, dst_len, src_ptr, src_len, db)
	caddr_t dst_ptr;
	size_t dst_len;
	caddr_t src_ptr;
	size_t src_len;
	mblk_t *db;
{
	mblk_t *mp;
	struct MAA_unitdata_ind *p;
	if ((mp = allocb(sizeof(*p) + dst_len + src_len, BPRI_MED))) {
		mp->b_datap->db_type = M_PROTO;
		p = (struct MAA_unitdata_ind *) mp->b_wptr;
		p->PRIM_type = MAA_UNITDATA_IND;
		p->DEST_length = dst_len;
		p->DEST_offset = dst_len ? sizeof(*p) : 0;
		p->SRC_length = src_len;
		p->SRC_offset = src_len ? sizeof(*p) + dst_len : 0;
		mp->b_wptr += sizeof(*p);
		bcopy(dst_ptr, mp->b_wptr, dst_len);
		mp->b_wptr += dst_len;
		bcopy(src_ptr, mp->b_wptr, src_len);
		mp->b_wptr += src_len;
		mp->b_cont = db;
	}
	return (mp);
}

/*
 *  =========================================================================
 *
 *  SSCOP AA-Provider --> N-User (UDP or IP) Primitive
 *
 *  =========================================================================
 */
static __inline__ mblk_t *n_info_req(void)
{
	mblk_t *mp;
	N_info_req_t *p;
	if ((mp = allocb(sizeof(*p), BPRI_MED))) {
		mp->b_datap->db_type = M_PCPROTO;
		p = (N_info_req_t *) mp->b_wptr;
		p->PRIM_type = N_INFO_REQ;
		mp->b_wptr += sizeof(*p);
	}
	return (mp);
};
static __inline__ mblk_t *n_bind_req(add_ptr, add_len, cons, flags, pro_ptr, pro_len)
	caddr_t add_ptr;
	size_t add_len;
	uint cons;
	uint flags;
	caddr_t pro_ptr;
	size_t pro_len;
{
	mblk_t *mp;
	N_bind_req_t *p;
	if ((mp = allocb(sizeof(*p) + add_len + pro_len, BPRI_MED))) {
		mp->b_datap->db_type = M_PCPROTO;
		p = (N_bind_req_t *) mp->b_wptr;
		p->PRIM_type = N_BIND_REQ;
		p->ADDR_length = add_len;
		p->ADDR_offset = add_len ? sizeof(*p) : 0;
		p->CONIND_number = cons;
		p->BIND_flags = flags;
		p->PROTOID_length = pro_len;
		p->PROTOID_offset = pro_len ? sizeof(*p) + add_len : 0;
		mp->b_wptr += sizeof(*p);
		bcopy(add_ptr, mp->b_wptr, add_len);
		mp->b_wptr += add_len;
		bcopy(pro_ptr, mp->b_wptr, pro_len);
		mp->b_wptr += pro_len;
	}
	return (mp);
}
static __inline__ mblk_t *n_unbind_req(void)
{
	mblk_t *mp;
	N_unbind_req_t *p;
	if ((mp = allocb(sizeof(*p), BPRI_MED))) {
		mp->b_datap->db_type = M_PCPROTO;
		p = (N_unbind_req_t *) mp->b_wptr;
		p->PRIM_type = N_UNBIND_REQ;
		mp->b_wptr += sizeof(*p);
	}
	return (mp);
}
static __inline__ mblk_t *n_optmgmt_req(qos_ptr, qos_len, flags)
	caddr_t qos_ptr;
	size_t qos_len;
	uint flags;
{
	mblk_t *mp;
	N_optmgmt_req_t *p;
	if ((mp = allocb(sizeof(*p) + qos_len, BPRI_MED))) {
		mp->b_datap->db_type = M_PCPROTO;
		p = (N_optmgmt_req_t *) mp->b_wptr;
		p->PRIM_type = N_OPTMGMT_REQ;
		p->QOS_length = qos_len;
		p->QOS_offset = qos_len ? sizeof(*p) : 0;
		p->OPTMGMT_flags = flags;
		bcopy(qos_ptr, mp->b_wptr, qos_len);
		mp->b_wptr += qos_len;
	}
	return (mp);
}
static __inline__ mblk_t *n_conn_req(dst_ptr, dst_len, flags, qos_ptr, qos_len)
	caddr_t dst_ptr;
	size_t dst_len;
	uint flags;
	caddr_t qos_ptr;
	size_t qos_len;
{
	mblk_t *mp;
	N_conn_req_t *p;
	if ((mp = allocb(sizeof(*p) + dst_len + qos_len, BPRI_MED))) {
		mp->b_datap->db_type = M_PROTO;
		p = (N_conn_req_t *) mp->b_wptr;
		p->PRIM_type = N_CONN_REQ;
		p->DEST_length = dst_len;
		p->DEST_offset = dst_len ? sizeof(*p) : 0;
		p->CONN_flags = flags;
		p->QOS_length = qos_len;
		p->QOS_offset = qos_len ? sizeof(*p) + dst_len : 0;
		mp->b_wptr += sizeof(*p);
		bcopy(dst_ptr, mp->b_wptr, dst_len);
		mp->b_wptr += dst_len;
		bcopy(qos_ptr, mp->b_wptr, qos_len);
		mp->b_wptr += qos_len;
	}
	return (mp);
}
static __inline__ mblk_t *n_data_req(uint flags, mblk_t * db)
{
	mblk_t *mp;
	N_data_req_t *p;
	if ((mp = allocb(sizeof(*p), BPRI_MED))) {
		mp->b_datap->db_type = M_PROTO;
		p = (N_data_req_t *) mp->b_wptr;
		p->PRIM_type = N_DATA_REQ;
		p->DATA_xfer_flags = flags;
		mp->b_wptr += sizeof(*p);
		mp->b_cont = db;
	}
	return (mp);
}
static __inline__ mblk_t *n_discon_req(reason, res_ptr, res_len, seq)
	uint reason;
	caddr_t res_ptr;
	size_t res_len;
	uint seq;
{
	mblk_t *mp;
	if ((mp = allocb(sizeof(*p) + res_len, BPRI_MED))) {
		mp->b_datap->db_type = M_PROTO;
		p = (N_discon_req_t *) mp->b_wptr;
		p->PRIM_type = N_DISCON_REQ;
		p->DISCON_reason = reason;
		p->RES_length = res_len;
		p->RES_offset = res_len ? sizeof(*p) : 0;
		p->SEQ_number = seq;
		mp->b_wptr += sizeof(*p);
		bcopy(res_ptr, mp->b_wptr, res_len);
		mp->b_wptr += res_len;
	}
	return (mp);
}
static __inline__ mblk_t *n_unitdata_req(dst_ptr, dst_len)
	caddr_t dst_ptr;
	size_t dst_len;
{
	mblk_t *mp;
	if ((mp = allocb(sizeof(*p) + dst_len, BPRI_MED))) {
		mp->b_datap->db_type = M_PROTO;
		p = (N_unitdata_req_t *) mp->b_wptr;
		p->PRIM_type = N_UNITDATA_REQ;
		p->DEST_length = dst_len;
		p->DEST_offset = dst_len ? sizeof(*p) : 0;
		p->RESERVED_field[0] = 0;
		p->RESERVED_field[1] = 0;
		mp->b_wptr += sizeof(*p);
	}
	return (mp);
}

/*
 *  ========================================================================
 *
 *  SSCOP --> SSCOP Peer Send Messages
 *
 *  ========================================================================
 */
/*
 *  SEND
 *  -------------------------------------------------------------------------
 */
static __inline__ int s_send_msg(queue_t * q, mblk_t * mp)
{
	mblk_t *pp;
	if ((pp = n_data_req(0))) {
		pp->b_cont = mp;
		putnext(q, pp);
		return (0);
	}
	freemsg(mp);
	return (-ENOBUFS);
}

/*
 *  SEND BGN.request N(W), N(SQ), N(S), SSCOP-UU
 *  -------------------------------------------------------------------------
 */
static __inline__ int s_send_bgn(queue_t * q, uint n_sq, uint n_mr, mblk_t * db)
{
	mblk_t *mp;
	size_t plen = 4 - ((db ? msgdsize(db) : 0) & 0x3);
	const uint32_t ptype = ((plen << 6) | SSCOP_BGN) << 24;
	if ((mp = allocb(12, BPRI_MED))) {
		mp->b_datap->db_type = M_DATA;
		mp->b_rptr += plen;
		*((uint32_t *) mp->b_wptr)++ = 0;
		*((uint32_t *) mp->b_wptr)++ = htonl(n_sq & 0xff);
		*((uint32_t *) mp->b_wptr)++ = htonl(ptype | (n_mr & 0xffffff));
		linkb(db, mp);
		return s_send_msg(WR(q), db);
	}
	return (-ENOBUFS);
}

/*
 *  SEND BGAK.request N(W), N(SQ), N(S), SSCOP-UU
 *  -------------------------------------------------------------------------
 */
static __inline__ int s_send_bgak(queue_t * q, uint n_mr, mblk_t * db)
{
	mblk_t *mp;
	size_t plen = 4 - ((db ? msgdsize(db) : 0) & 0x3);
	const uint32_t ptype = ((plen << 6) | SSCOP_BGAK) << 24;
	if ((mp = allocb(12, BPRI_MED))) {
		mp->b_datap->db_type = M_DATA;
		mp->b_rptr += plen;
		*((uint32_t *) mp->b_wptr)++ = 0;
		*((uint32_t *) mp->b_wptr)++ = 0;
		*((uint32_t *) mp->b_wptr)++ = htonl(ptype | (n_mr & 0xffffff));
		linkb(db, mp);
		return s_send_msg(WR(q), db);
	}
	return (-ENOBUFS);
}

/*
 *  SEND BGREJ.request SSCOP-UU
 *  -------------------------------------------------------------------------
 */
static __inline__ int s_send_bgrej(queue_t * q, mblk_t * db)
{
	mblk_t *mp;
	size_t plen = 4 - ((db ? msgdsize(db) : 0) & 0x3);
	const uint32_t ptype = ((plen << 6) | SSCOP_BGREJ) << 24;
	if ((mp = allocb(12, BPRI_MED))) {
		mp->b_datap->db_type = M_DATA;
		mp->b_rptr += plen;
		*((uint32_t *) mp->b_wptr)++ = 0;
		*((uint32_t *) mp->b_wptr)++ = 0;
		*((uint32_t *) mp->b_wptr)++ = htonl(ptype);
		linkb(db, mp);
		return s_send_msg(WR(q), db);
	}
	return (-ENOBUFS);
}

/*
 *  SEND END.request [src] SSCOP-UU
 *  -------------------------------------------------------------------------
 */
static __inline__ int s_send_end(queue_t * q, uint s, mblk_t * db)
{
	mblk_t *mp;
	size_t plen = 4 - ((db ? msgdsize(db) : 0) & 0x3);
	uint32_t ptype = (((plen << 2) | ((s & 1)) << 4) | SSCOP_END) << 24;
	if ((mp = allocb(12, BPRI_MED))) {
		mp->b_datap->db_type = M_DATA;
		mp->b_rptr += plen;
		*((uint32_t *) mp->b_wptr)++ = 0;
		*((uint32_t *) mp->b_wptr)++ = 0;
		*((uint32_t *) mp->b_wptr)++ = htonl(ptype);
		linkb(db, mp);
		return s_send_msg(WR(q), db);
	}
	return (-ENOBUFS);
}

/*
 *  SEND ENDAK.request ()
 *  -------------------------------------------------------------------------
 */
static __inline__ int s_send_endak(queue_t * q)
{
	mblk_t *mp;
	const uint32_t ptype = SSCOP_ENDAK << 24;
	if ((mp = allocb(8, BPRI_MED))) {
		mp->b_datap->db_type = M_DATA;
		*((uint32_t *) mp->b_wptr)++ = 0;
		*((uint32_t *) mp->b_wptr)++ = htonl(ptype);
		return s_send_msg(WR(q), mp);
	}
	return (-ENOBUFS);
}

/*
 *  SEND RS.request N(W), N(SQ), N(S), SSCOP-UU
 *  -------------------------------------------------------------------------
 */
static __inline__ int s_send_rs(queue_t * q, uint n_w, uint n_sq, uint n_s, mblk_t * db)
{
	mblk_t *mp;
	size_t plen = 4 - ((db ? msgdsize(db) : 0) & 0x3);
	const uint32_t ptype = ((plen << 6) | SSCOP_RS) << 24;
	if ((mp = allocb(12, BPRI_MED))) {
		mp->b_datap->db_type = M_DATA;
		mp->b_rptr += plen;
		*((uint32_t *) mp->b_wptr)++ = 0;
		*((uint32_t *) mp->b_wptr)++ = htonl(n_sq & 0xff);
		*((uint32_t *) mp->b_wptr)++ = htonl(ptype | (n_mr & 0xffffff));
		linkb(db, mp);
		return s_send_msg(WR(q), db);
	}
	return (-ENOBUFS);
}

/*
 *  SEND RSAK.request N(W), N(SQ), N(S)
 *  -------------------------------------------------------------------------
 */
static __inline__ int s_send_rsak(queue_t * q, uint n_mr)
{
	mblk_t *mp;
	const uint32_t ptype = (SSCOP_RSAK) << 24;
	if ((mp = allocb(8, BPRI_MED))) {
		mp->b_datap->db_type = M_DATA;
		*((uint32_t *) mp->b_wptr)++ = 0;
		*((uint32_t *) mp->b_wptr)++ = htonl(ptype | (n_mr & 0xffffff));
		return s_send_msg(WR(q), mp);
	}
	return (-ENOBUFS);
}

/*
 *  SEND ER.request N(W), N(SQ), N(S)
 *  -------------------------------------------------------------------------
 */
static __inline__ int s_send_er(queue_t * q, uint n_sq, uint n_mr)
{
	mblk_t *mp;
	const uint32_t ptype = (SSCOP_ER) << 24;
	if ((mp = allocb(8, BPRI_MED))) {
		mp->b_datap->db_type = M_DATA;
		*((uint32_t *) mp->b_wptr)++ = htonl(n_sq & 0xff);
		*((uint32_t *) mp->b_wptr)++ = htonl(ptype | (n_mr & 0xffffff));
		return s_send_msg(WR(q), mp);
	}
	return (-ENOBUFS);
}

/*
 *  SEND ERAK.request N(W), N(SQ), N(S)
 *  -------------------------------------------------------------------------
 */
static __inline__ int s_send_erak(queue_t * q, uint n_mr)
{
	mblk_t *mp;
	const uint32_t ptype = (SSCOP_ERAK) << 24;
	if ((mp = allocb(8, BPRI_MED))) {
		mp->b_datap->db_type = M_DATA;
		*((uint32_t *) mp->b_wptr)++ = 0;
		*((uint32_t *) mp->b_wptr)++ = htonl((n_mr & 0xffffff) | ptype);
		return s_send_msg(WR(q), mp);
	}
	return (-ENOBUFS);
}

/*
 *  SEND SD.request N(S), OOS, MU
 *  -------------------------------------------------------------------------
 */
static __inline__ int s_send_sd(queue_t * q, uint n_s, mblk_t * db)
{
	mblk_t *mp;
	size_t plen = 4 - ((db ? msgdsize(db) : 0) & 0x3);
	const uint32_t ptype = ((plen << 6) | SSCOP_SD) << 24;
	if ((mp = allocb(8, BPRI_MED))) {
		mp->b_datap->db_type = M_DATA;
		mp->b_rptr += plen;
		*((uint32_t *) mp->b_wptr)++ = 0;
		*((uint32_t *) mp->b_wptr)++ = htonl((n_s & 0xffffff) | ptype);
		linkb(db, mp);
		return s_send_msg(WR(q), db);
	}
	return (-ENOBUFS);
}

/*
 *  SEND POLL.request N(S), N(PS), N(SQ)
 *  -------------------------------------------------------------------------
 */
static __inline__ int s_send_poll(queue_t * q, uint n_ps, uint n_s)
{
	mblk_t *mp;
	const uint32_t ptype = (SSCOP_POLL) << 24;
	if ((mp = allocb(8, BPRI_MED))) {
		mp->b_datap->db_type = M_DATA;
		*((uint32_t *) mp->b_wptr)++ = htonl(n_ps & 0xffffff);
		*((uint32_t *) mp->b_wptr)++ = htonl((n_s & 0xffffff) | ptype);
		return s_send_msg(WR(q), mp);
	}
	return (-ENOBUFS);
}

/*
 *  SEND STAT.indicaiton N(R), N(MR), N(PS), N(SQ), N(SS), [list]
 *  -------------------------------------------------------------------------
 */
static __inline__ int s_send_stat(queue_t * q, uint n_r, uint n_mr, uint n_ps)
{
	mblk_t *mp;
	const uint32_t ptype = (SSCOP_STAT) << 24;
	if ((mp = allocb(12 + 4 * lnum, BPRI_MED))) {
		int i;
		mp->b_datap->db_type = M_DATA;
		for (i = 0; i < lnum; i++)
			*((uint32_t *) mp->b_wptr)++ = htonl(sp->le[i] & 0xffffff);
		*((uint32_t *) mp->b_wptr)++ = htonl(n_ps & 0xffffff);
		*((uint32_t *) mp->b_wptr)++ = htonl(n_mr & 0xffffff);
		*((uint32_t *) mp->b_wptr)++ = htonl((n_r & 0xffffff) | ptype);
		return s_send_msg(WR(q), mp);
	}
	return (-ENOBUFS);
}

/*
 *  SEND USTAT.request N(R), N(MR), N(PS), N(SQ), N(SS), [list]
 *  -------------------------------------------------------------------------
 */
static __inline__ int s_send_ustat(queue_t * q, uint n_r, uint n_mr)
{
	mblk_t *mp;
	const uint32_t ptype = (SSCOP_USTAT) << 24;
	if ((mp = allocb(16, BPRI_MED))) {
		mp->b_datap->db_type = M_DATA;
		*((uint32_t *) mp->b_wptr)++ = htonl(sp->le[0] & 0xffffff);
		*((uint32_t *) mp->b_wptr)++ = htonl(sp->le[1] & 0xffffff);
		*((uint32_t *) mp->b_wptr)++ = htonl(n_mr & 0xffffff);
		*((uint32_t *) mp->b_wptr)++ = htonl((n_r & 0xffffff) | ptype);
		return s_send_msg(WR(q), mp);
	}
	return (-ENOBUFS);
}

/*
 *  SEND UD.request MU
 *  -------------------------------------------------------------------------
 */
static __inline__ int s_send_ud(queue_t * q, mblk_t * mp)
{
	mblk_t *mp;
	size_t plen = 4 - ((db ? msgdsize(db) : 0) & 0x3);
	const uint32_t ptype = ((plen << 6) | SSCOP_UD) << 24;
	if ((mp = allocb(8, BPRI_MED))) {
		mp->b_datap->db_type = M_DATA;
		mp->b_rptr += plen;
		*((uint32_t *) mp->b_wptr)++ = 0;
		*((uint32_t *) mp->b_wptr)++ = htonl(ptype);
		return s_send_msg(WR(q), mp);
	}
	return (-ENOBUFS);
}

/*
 *  SEND MD.request MU
 *  -------------------------------------------------------------------------
 */
static __inline__ int s_send_md(queue_t * q, mblk_t * mp)
{
	mblk_t *mp;
	size_t plen = 4 - ((db ? msgdsize(db) : 0) & 0x3);
	const uint32_t ptype = ((plen << 6) | SSCOP_MD) << 24;
	if ((mp = allocb(8, BPRI_MED))) {
		mp->b_datap->db_type = M_DATA;
		mp->b_rptr += plen;
		*((uint32_t *) mp->b_wptr)++ = 0;
		*((uint32_t *) mp->b_wptr)++ = htonl(ptype);
		return s_send_msg(WR(q), mp);
	}
	return (-ENOBUFS);
}

/*
 *  ========================================================================
 *
 *  SSCOP State Machines
 *
 *  ========================================================================
 */

static int aa_idle_msg(queue_t * q, mblk_t * mp)
{
	mblk_t *bp;
	sscop_t *sp = (sscop_t *) q->q_ptr;
	const uint prim = (ntohl(*(((uint32_t *) mp->b_wptr) - 1) >> 24)) & 0xf;
	uint cause;
	switch (prim) {
	case SSCOP_BGN:
	case SSCOP_ENDAK:
		goto aa_idle_msg_ignore;
	case SSCOP_END:
	case SSCOP_ER:
		cause = A_CAUSE_L;
		break;
	case SSCOP_POLL:
		cause = A_CAUSE_G;
		break;
	case SSCOP_SD:
		cause = A_CAUSE_A;
		break;
	case SSCOP_BGAK:
		cause = A_CAUSE_C;
		break;
	case SSCOP_ERAK:
		cause = A_CAUSE_M;
		break;
	case SSCOP_STAT:
		cause = A_CAUSE_M;
		break;
	case SCCOP_USTAT:
		cause = A_CAUSE_I;
		break;
	case SSCOP_RS:
		cause = A_CAUSE_J;
		break;
	case SSCOP_RSAK:
		cause = A_CAUSE_K;
		break;
	case SSCOP_BGREJ:
		cause = A_CAUSE_D;
		break;
	default:
		cause = A_CAUSE_X;
		break;
	}
	if ((err = s_send_end(q, 1, NULL)))
		return (err);
	freemsg(mp);
	if (mgmt_queue)
		putnext(mgmt_queue, maa_error_ind(cause, 0));
	return (0);
      aa_idle_msg_ignore:
	freemsg(mp);
	return (0);
}

static int aa_idle_sig(queue_t * q, mblk_t * mp)
{
	mblk_t *bp;
	sscop_t *sp = (sscop_t *) q->q_ptr;
	const uint sig = ((union AA_signals *) mp->b_rptr)->signal;
	switch (sig) {
	case AA_ESTABLISH_REQ:
		/* clear transmitter */
		sp->clear_buffers = p->CONN_flags;
		sp->VT.CC = 1;
		sp->VT.SQ++;
		sp->VR.MR = FIXME;	/* initialize */
		sp->cdata = mp->b_cont;
		s_send_bgn(q, sp->VT.SQ, sp->VR.MR, dupmsg(mp->b_cont));
		mod_timeout(&sp->timer_cc, sscop_timeout_cc, sp->timer_cc_val);
		sp->a_state = AS_WCON_CREQ;
		break;
	case AA_RETRIEVE_REQ:
		/* data retrieval */
		break;
	case AA_DATA_REQ:
		/* queue SD */
		break;
	}
      aa_idle_sig_ignore:
	freemsg(mp);
	return (0);
}

static int aa_outcon_msg(queue_t * q, mblk_t * mp)
{
	mblk_t *bp;
	sscop_t *sp = (sscop_t *) q->q_ptr;
	const uint prim = (ntohl(*(((uint32_t *) mp->b_wptr) - 1) >> 24)) & 0xf;
	switch (prim) {
	case SSCOP_BGN:
		/* 
		 *  FIXME:
		 */
		return (0);
	case SSCOP_BGAK:
		/* 
		 * FIXME
		 */
		linkb(bp, mp->b_cont);
		putnext(q, bp);
		freeb(mp);
		sp->a_state = AS_DATA_XFER;
		return (0);
	case SSCOP_BGREJ:
		untimeoyt(xchg(&sp->timer_cc, 0));
		if (!(bp = aa_release_ind(q, 0, mp)))
			return -ENOBUFS;
		linkb(bp, mp->b_cont);
		putnext(q, bp);
		freeb(mp);
		sp->a_state = AS_IDLE;
		return (0);
	case SSCOP_ENDAK:
		break;
	case SSCOP_SD:
		break;
	case SSCOP_ERAK:
		break;
	case SSCOP_END:
		break;
	case SSCOP_STAT:
		break;
	case SSCOP_USTAT:
		break;
	case SSCOP_POLL:
		break;
	case SSCOP_SD:
		break;
	case SSCOP_ER:
		break;
	case SSCOP_RSAK:
		break;
	case SSCOP_RS:
		break;
	}
      aa_outcon_msg_ignore:
	freemsg(mp);
	return (0);
}

static int aa_outcon_sig(queue_t * q, mblk_t * mp)
{
	sscop_t *sp = (sscop_t *) q->q_ptr;
	const uint sig = ((union AA_signals *) mp->b_rptr)->signal;
	switch (sig) {
	case AA_RELEASE_REQ:
		if ((err = s_send_end(q)))
			return (err);
		sp->VT.CC = 1;
		mod_timeout(&sp->timer_cc, aa_cc_timeout, sp->timer_cc_val);
		sp->a_state = AS_WIND_DREQ;
		freemsg(mp);
		return (0);
	default:
		freemsg(mp);
		return (0);
	}
}

static int aa_incon_msg(queue_t * q, mblk_t * mp)
{
	mblk_t *bp, *ap;
	sscop_t *sp = (sscop_t *) q->q_ptr;
	const uint prim = (ntohl(*(((uint32_t *) mp->b_wptr) - 1) >> 24)) & 0xf;
	switch (prim) {
	case SSCOP_BGAK:
		freemsg(mp);
		putq(mgmt_queue, maa_error_ind(A_CAUSE_C, 0));
	return case SSCOP_BGREJ:
	{
		sscop_t *cp;
		if (!(bp = maa_error_ind(A_CAUSE_D, 0)))
			return (-ENOBUFS);
		/* 
		 *  FIXME:  Find incoming connection indication to which the
		 *  BGREJ applies.
		 */
		if (!(ap = aa_release_ind(A_SOURCE_SSCOP, NULL, 0, cp->seq, NULL))) {
			freeb(bp);
			return (-ENOBUFS);
		}
		/* 
		 *  FIXME:  Remove the incoming connection indication from the
		 *  listener's list.
		 */
		if (!sp->outcnt)
			sp->a_state = AS_IDLE;
		putq(mgmt_queue, bp);
		putnext(q, ap);
		freemsg(mp);
		return (0);
	}
	case SSCOP_END:
	{
		sscop_t *cp;
		/* 
		 *  FIXME:  Find incoming connection indication to which the
		 *  BGREJ applies.
		 */
		if (!(ap = aa_release_ind(AA_SOURCE_USER, NULL, 0, cp->seq, NULL)))
			return (-ENOBUFS);
		if ((err = s_send_endak(q))) {
			freemsg(ap);
			return (err);
		}
		/* 
		 *  FIXME:  Remove the incoming connection indication from the
		 *  listener's list.
		 */
		if (!sp->outcnt)
			sp->a_state = AS_IDLE;
		putnext(q, ap);
		freemsg(mp);
		return (0);
	}
	case SSCOP_SD:
		cause = A_CAUSE_A;
		break;
	case SSCOP_USTAT:
		cause = A_CAUSE_I;
		break;
	case SSCOP_STAT:
		cause = A_CAUSE_H;
		break;
	case SSCOP_POLL:
		cause = A_CAUSE_G;
		break;
	case SSCOP_ERAK:
		cause = A_CAUSE_M;
		break;
	case SSCOP_RSAK:
		cause = A_CAUSE_K;
		break;
	case SSCOP_RS:
		cause = A_CAUSE_J;
		break;
	}
	if (mgmt_queue && !(bp = maa_error_ind(cause, 0)))
		return (-ENOBUFS);
	/* 
	 *  FIXME:  Find incoming connection indication to which the
	 *  BGREJ applies.
	 */
	if (!(ap = aa_release_ind(A_SOURCE_SSCOP, NULL, 0, sp->seq, NULL))) {
		if (bp)
			freemsg(bp);
		return (-ENOBUFS);
	}
	if ((err = s_send_end(q, 1, NULL))) {
		if (bp)
			freemsg(bp);
		if (ap)
			freemsg(ap);
		return (err);
	}
	/* 
	 *  FIXME:  Remove the incoming connection indication from the
	 *  listener's list.
	 */
	if (!sp->outcnt)
		sp->a_state = AS_IDLE;
	if (mgmt_queue)
		putnext(mgmt_queue, bp);
	freemsg(mp);
	return (0);

      aa_incon_msg_report:
	freemsg(mp);
	if (mgmt_queue)
		putnext(mgmt_queue, maa_error_ind(cause, 0));
	return (0);
}

static int aa_incon_sig(queue_t * q, mblk_t * mp)
{
	sscop_t *sp = (sscop_t *) q->q_ptr;
	const uint sig = ((union AA_signals *) mp->b_rptr)->signal;
	switch (sig) {
	case AA_ESTABLISH_RES:
		/* clear transmitter */
		sp->clear_buffers = FIXME;	/* get br from flags */
		/* initialize VR.MR */
		if ((err = s_send_bgak(q, sp->VT.MR, mp->b_cont)))
			return (err);
		/* initialize state variables */
		/* set data transfer times */
		sp->a_state = AS_DATA_XFER;
		break;
	case AA_RELEASE_REQ:
	{
		sscop_t *cp;
		/* 
		 *  FIXME:  Find incoming connection indication to thwich the
		 *  AA_RELEASE_REQ applies (use seq number).
		 */
		if ((err = s_send_bgrej(cp->q)))
			return (err);
		/* 
		 *  FIXME:  Remove the incoming connection indication from the
		 *  listener's list.
		 */
		if (!sp->outcnt)
			sp->a_state = AS_IDLE;
		putnext(q, ap);
		break;
	}
	case AA_RETRIEVE_REQ:
		/* data retrieval */
		break;
	case AA_DATA_REQ:
		/* queue SD */
		break;
	}
	freemsg(mp);
      return (0):
}

static int aa_outdis_msg(queue_t * q, mblk_t * mp)
{
	mblk_t *bp, *ap;
	sscop_t *sp = (sscop_t *) q->q_ptr;
	const uint prim = (ntohl(*(((uint32_t *) mp->b_wptr) - 1) >> 24)) & 0xf;
	switch (prim) {
	case SSCOP_BGN:
		/* 
		 *  FIXME:
		 */
		return (0);
	case SSCOP_END:
		if ((err = s_send_endak(q)))
			return (err);
		/* fall through */
	case SSCOP_ENDAK:
	case SSCOP_BGREJ:
		untimeout(xchg(&sp->timer_cc, 0));
		if (!(ap = aa_release_confirm()))
			return (-ENOBUFS);
		putnext(q, ap);
		freemsg(mp);
		sp->a_state = AS_IDLE;
		return (0);
	default:
	case SSCOP_SD:
	case SSCOP_BGAK:
	case SSCOP_POLL:
	case SSCOP_STAT:
	case SSCOP_USTAT:
	case SSCOP_ERAK:
	case SSCOP_RS:
	case SSCOP_RSAK:
	case SSCOP_ER:
		break;
	}
	freemsg(mp);
	return (0);
}

static int aa_outdis_sig(queue_t * q, mblk_t * mp)
{
	mblk_t *bp, *ap;
	sscop_t *sp = (sscop_t *) q->q_ptr;
	const uint sig = ((union AA_signals *) mp->b_rptr)->signal;
	switch (sig) {
	case AA_ESTABLISH_REQ:
		if ((err = s_send_bgn()))
			return (err);
		/* clear transmitter */
		sp->clear_buffers = FIXME;	/* BR from message */
		sp->VT.CC = 1;
		sp->VT.SQ++;
		sp->VR.MR = FIXME;	/* initialize VR.MR */
		mod_timeout(&sp->timer_cc, aa_timeout_cc, sp->timer_cc_val);
		sp->a_state = AS_WCON_CREQ;

	case AA_RETRIEVE_REQ:
		/* data retrieval */
		freemsg(mp);
		return (0);
	}
}

/*
 *  =========================================================================
 *
 *  N-Provider (UDP or IP) --> AA-Provider
 *
 *  =========================================================================
 */
static int n_info_ack(q, mp)
	const queue_t *q;
	const mblk_t *mp;
{
	sscop_t *sp = (sscop_t *) q->q_ptr;
	N_info_ack_t *p = (N_info_ack_t *) mp->b_rptr;
	sp->nsdu_size = p->NSDU_size;
	sp->ensdu_size = p->ENSDU_size;
	sp->cdata_size = p->CDATA_size;
	sp->ddata_size = p->DDATA_size;
	sp->nidu_size = p->NIDU_size;
	sp->serv_type = p->SERV_type;
	sp->n_state = p->CURRENT_state;
	sp->prov_type = p->PROVIDER_type;
	sp->nodu_size = p->NODU_size;
	sp->npi_version = p->NPI_version;
	freemsg(mp);
	return (0);
}
static int n_bind_ack(q, mp)
	const queue_t *q;
	const mblk_t *mp;
{
	sscop_t *sp = (sscop_t *) q->q_ptr;
	N_bind_ack_t *p = (N_bind_ack_t *) mp->b_rptr;
	caddr_t add_ptr;
	size_t add_len;
	caddr_t pro_ptr;
	size_t pro_len;
	add_len = p->ADDR_length;
	add_ptr = p->ADDR_offset + mp->b_rptr;
	pro_len = p->PROTOID_length;
	pro_ptr = p->PROTOID_offset + mp->b_rptr;
	sp->bport = *((uint16_t *) add_ptr)++;
	sp->baddr = *((uint32_t *) add_ptr)++;
	sp->proto = *((uint16_t *) pro_ptr)++;
	freemsg(mp);
	return (0);
}
static int n_error_ack(q, mp)
	const queue_t *q;
	const mblk_t *mp;
{
	sscop_t *sp = (sscop_t *) q->q_ptr;
	N_error_ack_t *p = (N_error_ack_t *) mp->b_rptr;
	switch (sp->n_state) {
		/* 
		 *  FIXME
		 *  abort state transition
		 */
	}
	freemsg(mp);
	return (0);
}
static int n_ok_ack(q, mp)
	const queue_t *q;
	const mblk_t *mp;
{
	sscop_t *sp = (sscop_t *) q->q_ptr;
	N_ok_ack_t *p = (N_ok_ack_t *) mp->b_rptr;
	switch (sp->n_state) {
		/* 
		 *  FIXME
		 *  complete state transition
		 */
	}
	freemsg(mp);
	return (0);
}
static int n_conn_con(q, mp)
	const queue_t *q;
	const mblk_t *mp;
{
	sscop_t *sp = (sscop_t *) q->q_ptr;
	N_conn_con_t *p = (N_conn_con_t *) mp->b_rptr;
	if (sp->n_state == NS_WCON_CREQ) {
		sp->n_state = NS_DATA_XFER;
		freemsg(mp);
		return (0);
	}
	return -EPROTO;
}
static int n_discon_ind(q, mp)
	const queue_t *q;
	const mblk_t *mp;
{
	sscop_t *sp = (sscop_t *) q->q_ptr;
	N_discon_ind_t *p = (N_discon_ind_t *) mp->b_rptr;
	if (sp->n_state == NS_DATA_XFER) {
		sp->n_state = NS_IDLE;
		/* 
		 *  FIXME
		 *  indicate disconnection to AA-user
		 */
		if (sp->buf_ret) {
			sp->a_state = AS_WRES_VIND;
			/* 
			 *  FIXME
			 */
		}
	}
	return -EPROTO;
}
static int n_unitdata_ind(q, mp)
	const queue_t *q;
	const mblk_t *mp;
{
	sscop_t *sp = (sscop_t *) q->q_ptr;
	N_unitdata_ind_t *p = (N_unitdata_ind_t *) mp->b_rptr;
	if (sp->n_state == NS_IDLE) {
	}
	return -EPROTO;
}
static int n_uderror_ind(q, mp)
	const queue_t *q;
	const mblk_t *mp;
{
	sscop_t *sp = (sscop_t *) q->q_ptr;
	N_uderror_ind_t *p = (N_uderror_ind_t *) q->q_ptr;
	if (sp->n_state == NS_IDLE) {
	}
	return -EPROTO;
}

static int (*n_prim[]) (queue_t *, mblk_t *) = {
	NULL,			/* N_CONN_REQ 0 */
	    NULL,		/* N_CONN_RES 1 */
	    NULL,		/* N_DISCON_REQ 2 */
	    NULL,		/* N_DATA_REQ 3 */
	    NULL,		/* N_ExDATA_REQ 4 */
	    NULL,		/* N_INFO_REQ 5 */
	    NULL,		/* N_BIND_REQ 6 */
	    NULL,		/* N_UNBIND_REQ 7 */
	    NULL,		/* N_UNITDATA_REQ 8 */
	    NULL,		/* N_OPTMGMT_REQ 9 */
	    NULL,		/* not used 10 */
	    NULL,		/* N_CONN_IND 11 */
	    NULL,		/* N_CONN_CON 12 */
	    NULL,		/* N_DISCON_IND 13 */
	    NULL,		/* N_DATA_IND 14 */
	    NULL,		/* N_EXDATA_IND 15 */
	    &n_info_ack,	/* N_INFO_ACK 16 */
	    &n_bind_ack,	/* N_BIND_ACK 17 */
	    &n_error_ack,	/* N_ERROR_ACK 18 */
	    &n_ok_ack,		/* N_OK_ACK 19 */
	    &n_unitdata_ind,	/* N_UNITDATA_IND 20 */
	    &n_uderror_ind,	/* N_UDERROR_IND 21 */
	    NULL,		/* not used 22 */
	    NULL,		/* N_DATACK_REQ 23 */
	    NULL,		/* N_DATACK_IND 24 */
	    NULL,		/* N_RESET_REQ 25 */
	    NULL,		/* N_RESET_IND 26 */
	    NULL,		/* N_RESET_RES 27 */
	    NULL		/* N_RESET_CON 28 */
};

/*
 *  =========================================================================
 *
 *  AA-User --> AA-Provider Primitives (M_CTL, M_PROTO, M_PCPROTO)
 *
 *  =========================================================================
 */
static int aa_info_req(queue_t * q, mblk_t * mp)
{
	mblk_t *ap;
	(void) mp;
	if (!(ap = aa_info_ack(q)))
		return (-EAGAIN);
	qreply(q, ap);
	return (0);
}
static int aa_bind_req(queue_t * q, mblk_t * mp)
{
	mblk_t *ap;
	sscop_t *sp = (sscop_t *) q->q_ptr;
	AA_bind_req_t *p = (AA_bind_req_t *) mp->b_rptr;
	caddr_t add_ptr;
	size_t add_len;

	/* 
	 *  FIXME: more...
	 *  FIXME: more...
	 *  FIXME: more...
	 */
}
static int aa_unbind_req(queue_t * q, mblk_t * mp)
{
}
static int aa_unitdata_req(queue_t * q, mblk_t * mp)
{
}
static int aa_optmgmt_req(queue_t * q, mblk_t * mp)
{
}
static int aa_establish_req(queue_t * q, mblk_t * mp)
{
}
static int aa_establish_res(queue_t * q, mblk_t * mp)
{
}
static int aa_release_req(queue_t * q, mblk_t * mp)
{
}
static int aa_data_req(queue_t * q, mblk_t * mp)
{
}
static int aa_exdata_req(queue_t * q, mblk_t * mp)
{
}
static int aa_datack_req(queue_t * q, mblk_t * mp)
{
}
static int aa_resync_req(queue_t * q, mblk_t * mp)
{
}
static int aa_resync_res(queue_t * q, mblk_t * mp)
{
}
static int aa_recover_res(queue_t * q, mblk_t * mp)
{
}
static int aa_retrieve_req(queue_t * q, mblk_t * mp)
{
}
static int maa_set_timer_req(queue_t * q, mblk_t * mp)
{
}
static int maa_add_link_req(queue_t * q, mblk_t * mp)
{
}
static int maa_remove_link_req(queue_t * q, mblk_t * mp)
{
}

static int (*n_prim[]) (queue_t *, mblk_t *) = {
	&aa_establish_req,	/* AA_ESTABLISH_REQ 0 */
	    &aa_establish_res,	/* AA_ESTABLISH_RES 1 */
	    &aa_release_req,	/* AA_RELEASE_REQ 2 */
	    &aa_data_req,	/* AA_DATA_REQ 3 */
	    &aa_exdata_req,	/* AA_ExDATA_REQ 4 */
	    &aa_info_req,	/* AA_INFO_REQ 5 */
	    &aa_bind_req,	/* AA_BIND_REQ 6 */
	    &aa_unbind_req,	/* AA_UNBIND_REQ 7 */
	    &aa_unitdata_req,	/* AA_UNITDATA_REQ 8 */
	    &aa_optmgmt_req,	/* AA_OPTMGMT_REQ 9 */
	    NULL,		/* AA_RELEASE_CON 10 */
	    NULL,		/* AA_ESTABLISH_IND 11 */
	    NULL,		/* AA_ESTABLISH_CON 12 */
	    NULL,		/* AA_RELEASE_IND 13 */
	    NULL,		/* AA_DATA_IND 14 */
	    NULL,		/* AA_EXDATA_IND 15 */
	    NULL,		/* AA_INFO_ACK 16 */
	    NULL,		/* AA_BIND_ACK 17 */
	    NULL,		/* AA_ERROR_ACK 18 */
	    NULL,		/* AA_OK_ACK 19 */
	    NULL,		/* AA_UNITDATA_IND 20 */
	    NULL,		/* MAA_ERROR_IND 21 */
	    NULL,		/* not used 22 */
	    &aa_datack_req,	/* AA_DATACK_REQ 23 */
	    NULL,		/* AA_DATACK_IND 24 */
	    &aa_resync_req,	/* AA_RESET_REQ 25 */
	    NULL,		/* AA_RESET_IND 26 */
	    &aa_resync_res,	/* AA_RESET_RES 27 */
	    NULL,		/* AA_RESET_CON 28 */
	    NULL,		/* AA_RECOVER_IND 29 */
	    &aa_recover_res,	/* AA_RECOVER_RES 30 */
	    &aa_retrieve_req,	/* AA_RETRIEVE_REQ 31 */
	    NULL,		/* AA_RETRIEVE_IND 32 */
	    NULL,		/* AA_RETRIEVE_COMPLETE_IND 33 */
	    &maa_set_timer_req,	/* MAA_SET_TIMER_REQ 34 */
	    &maa_add_link_req,	/* MAA_ADD_LINK_REQ 35 */
	    &maa_remove_link_req,	/* MAA_REMOVE_LINK_REQ 36 */
	    NULL		/* MAA_REMOVE_LINK_IND 37 */
};

/*
 *  =========================================================================
 *
 *  SCTP IOCTLs
 *
 *  =========================================================================
 */
static int (*aa_ioctl[]) (queue_t *, uint, void *) = {
};

/*
 *  =========================================================================
 *
 *  SCTP STREAMS Message Handling
 *
 *  =========================================================================
 *
 *  M_DATA Handling
 *
 *  -------------------------------------------------------------------------
 */
static inline int sscop_w_data(queue_t * q, mblk_t * mp)
{
	return sscop_write_data(q, mp);
}
static inline int sscop_r_data(queue_t * q, mblk_t * mp)
{
	return sscop_recv_data(q, mp);
}

/*
 *  -------------------------------------------------------------------------
 *
 *  M_PROTO, M_PCPROTO Handling
 *
 *  -------------------------------------------------------------------------
 */
static inline int sscop_w_proto(queue_t * q, mblk_t * mp)
{
	int sig = ((union AA_signals *) (mp->b_rptr))->type;
	if (0 <= sig && sig < sizeof(aa_sigs) / sizeof(void *))
		if (aa_sigs[sig])
			return (*aa_sigs[sig]) (q, mp);
	return (-EOPNOTSUPP);
}
static inline int sscop_r_proto(queue_t * q, mblk_t * mp)
{
	int prim = ((union N_primitives *) (mp->b_rptr))->type;
	if (0 <= prim && prim <= sizeof(n_prim) / sizeof(void *))
		if (n_prim[prim])
			return (*n_prim[prim]) (q, mp);
	return (-EOPNOTSUPP);
}
static inline int sscop_w_pcproto(queue_t * q, mblk_t * mp)
{
	return sscop_w_proto(q, mp);
}
static inline int sscop_r_pcproto(queue_t * q, mblk_t * mp)
{
	return sscop_r_proto(q, mp);
}

/*
 *  -------------------------------------------------------------------------
 *
 *  M_CTL Handling
 *
 *  -------------------------------------------------------------------------
 */
static inline int sscop_w_ctl(queue_t * q, mblk_t * mp)
{
	(void) q;
	(void) mp;
	return (-EOPNOTSUPP);
}
static inline int sscop_r_ctl(queue_t * q, mblk_t * mp)
{
	(void) q;
	(void) mp;
	return (-EOPNOTSUPP);
}

/*
 *  -------------------------------------------------------------------------
 *
 *  M_IOCTL Handling
 *
 *  -------------------------------------------------------------------------
 */
static inline int sscop_w_ioctl(queue_t * q, mblk_t * mp)
{
	int ret;
	struct iocblk *iocp = (struct iocblk *) mp->b_rptr;
	int cmd = iocp->ioc_cmd;
	void *arg = mp->b_cont ? mp->b_cont->b_rptr : NULL;
	int type = _IOC_TYPE(cmd);
	int nr = _IOC_NR(cmd);
	int size = _IOC_SIZE(cmd);
	switch (type) {
	case __SID:
		switch (cmd) {
		case I_LINK:
		case I_PLINK:
		case I_UNLINK:
		case I_PUNLINK:
		case I_FDINSERT:
			ret = -EINVAL;
		}
		break;

	case SSCOP_IOC_MAGIC:
		if (iocp->ioc_count >= size) {
			if (0 <= nr && nr < sizeof(aa_ioctl) / sizeof(void *)) {
				if (aa_ioctl[nr])
					ret = (*aa_ioctl[nr]) (q, cmd, arg);
				else
					ret = -EOPNOTSUPP;
			}
		} else
			return = -EINVAL;
		break;

	default:
		if (q->q_next) {
			putnext(q, mp);
			return (0);
		}
		ret = -EOPNOTSUPP;
	}
	mp->b_datap->db_type = ret ? M_IOCNAK : M_IOCACK;
	iocp->ioc_error = -ret;
	iocp->ioc_rval = ret ? -1 : 0;
	qreply(q, mp);
	return (0);
}

/*
 *  -------------------------------------------------------------------------
 *
 *  M_FLUSH Handling
 *
 *  -------------------------------------------------------------------------
 */
static inline void sscop_w_flush(queue_t * q, mblk_t * mp)
{
	if (*mp->b_rptr & M_FLUSHW) {
		flushq(q, FLUSHALL);
		if (q->q_next) {
			putnext(q, mp);
			return;
		}
		*mp->b_rptr &= ~FLUSHW;
	}
	if (*mp->b_rptr & FLUSHR) {
		flushq(RD(q), FLUSHALL);
		qreply(q, mp);
		return;
	}
	if (q->q_next) {
		putnext(q, mp);
		return;
	}
}

/*
 *  -------------------------------------------------------------------------
 *
 *  M_ERROR Handling
 *
 *  -------------------------------------------------------------------------
 */
static inline void sscop_r_error(queue_t * q, mblk_t * mp)
{
	sscop_t *sp = (sscop_t *) q->q_ptr;
	sp->a_state = AA_UNUSABLE;
	if (q->q_next) {
		putnext(q, mp);
		return;
	}
}

/*
 *  =========================================================================
 *
 *  STREAMS QUEUE PUT AND QUEUE SERVICE routines
 *
 *  =========================================================================
 *
 *  READ QUEUE PUT and SRV routinges
 *
 *  -------------------------------------------------------------------------
 *
 *  SSCOP RPUT - Message from below.
 *  -------------------------------------------------------------------------
 *  If the message is a priority message we attempt to process it immediately.
 *  If the message is a non-priority message, but there are no messages on the
 *  queue yet, we attempt to process it immediately.  If the message is not
 *  supported, we pass it down-queue if possible.  If the message cannot be
 *  processed immediately we place it on the queue.
 */
static INT sscop_rput(q, mp)
	queue_t *q;
	mblk_t *mp;
{
	int err = -EOPNOTSUPP;

	if (mp->b_datap->db_type < QPCTL && q->q_count) {
		putq(q, mp);
		return (0);
	}
	switch (mp->b_datap->db_type) {
	case M_DATA:
		if ((err = sscop_r_data(q, mp)))
			break;
		return (0);
	case M_PROTO:
		if ((err = sscop_r_proto(q, mp)))
			break;
		return (0);
	case M_PCPROTO:
		if ((err = sscop_r_pcproto(q, mp)))
			break;
		return (0);
	case M_CTL:
		if ((err = sscop_r_ctl(q, mp)))
			break;
		return (0);
	case M_ERROR:
		sscop_r_error(q, mp);
		return (0);
	}
	switch (err) {
	case -EAGAIN:
		putq(q, mp);
		return (0);
	case -EOPNOTSUPP:
		if (q->q_next) {
			putnext(q, mp);
			return (0);
		}
	}
	freemsg(mp);
	return (err);
}

/*
 *  SSCOP RSRV - Queued message from below.
 *  -------------------------------------------------------------------------
 *  If the message is a priority message we attempt to process it immediately
 *  and without flow control.  If the message is a non-priority message and
 *  the next queue is flow controlled, we put the message back on the queue
 *  and wait.  If we cannot process a prority message immediately we cannot
 *  place it back on the queue and discard it.  We requeue the non-priority
 *  messages which cannot be processed immediately.  Unrecognized messages are
 *  passwed down-queue.
 */
static INT sscop_rsrv(q)
	queue_t *q;
{
	mblk_t *mp;
	int err = -EOPNOTSUPP;
	while ((mp = getq(q))) {
		if (mp->b_datap->db_type < QPCTL && !canputnext(q)) {
			putbq(q, mp);
			return (0);
		}
		switch (mp->b_datap->db_type) {
		case M_DATA:
			if ((err = sscop_r_data(q, mp)))
				break;
			continue;
		case M_PROTO:
			if ((err = sscop_r_proto(q, mp)))
				break;
			continue;
		case M_PCPROTO:
			if ((err = sscop_r_pcproto(q, mp)))
				break;
			continue;
		case M_CTL:
			if ((err = sscop_r_ctl(q, mp)))
				break;
			continue;
		}
		switch (err) {
		case -EAGAIN:
			if (mp->b_datap->db_type < QPCTL) {
				putbq(q, mp);
				return (0);
			}
		case -EOPNOTSUPP:
			if (q->q_next) {
				putnext(q, mp);
				continue;
			}
		}
		freemsg(mp);
	}
	return (0);
}

/*
 *  =========================================================================
 *
 *  OPEN and CLOSE
 *  
 *  =========================================================================
 */

/*
 *  Private structure allocation and deallocation.  We use Linux hardware
 *  aligned cache here for speedy access to information contained in the
 *  private data structure.
 */
kmem_cache_t *sscop_cachep = NULL;

static sscop_t *sscop_alloc_priv(queue_t * q)
{
	sscop_t *sp;
	if ((sscop = kmem_cache_alloc(sscop_cachep))) {
		bzero(sscop, sizeof(*sp));
		RD(q)->q_ptr = WR(q)->q_ptr = sp;
		sp->rq = RD(q);
		sp->wq = WR(q);
	}
	return (sp);
}

static void sscop_init_priv(void)
{
	if (!(sscop_cachep = kmem_find_general_cachep(sizeof(sscop_t)))) {
		/* allocate a new cachep */
	}
	return;
}

/*
 *  -------------------------------------------------------------------------
 *
 *  OPEN - Each open
 *
 *  -------------------------------------------------------------------------
 */
static int sscop_open(queue_t * q, drv_t * devp, int flag, int sflag, cred_t * crp)
{
	(void) crp;
	if (q->q_ptr != NULL)
		return (0);	/* open already */
	if (sflag == MODOPEN || WR(q)->q_next != NULL) {
		/* 
		 *  TODO: check to make sure that the module we are being
		 *  pushed over is compatible (i.e., it is of the right kind
		 *  of transport module.
		 */
		if (!(sscop_alloc_priv(q)))
			return ENOMEM;
		return (0);
	}
	return EIO;
}

/*
 *  -------------------------------------------------------------------------
 *
 *  CLOSE - Last close
 *
 *  -------------------------------------------------------------------------
 */
static int sscop_close(queue_t * q, int flag, cred_t * crp)
{
	(void) flag;
	(void) crp;
	sscop_free_priv(q);
	return (0);
}

/*
 *  =========================================================================
 *
 *  LiS MODULE INITIATLIZATION
 *
 *  =========================================================================
 */
static in sscop_initialized = 0;

#ifndef LIS_REGISTERED
static inline void sscop_init(void)
#else
__initfunc(void sscop_init(void))
#endif
{
	if (sscop_initialized)
		return;
	printk(KERN_INFO SSCOP_BANNER);	/* console splash */
#ifndef LIS_REGISTERED
	if (!(sscop_minfo.mi_idnum = lis_register_strmod(&sscop_info, sscop_minfo.mi_idname))) {
		cmn_err(CE_NOTE "sscop: couldn't register as module\n");
		sscop_minfo.mi_idnum = 0;
	}
#endif
}

#ifndef LIS_REGISTERED
static inline void sscop_terminate(void)
#else
__initfunc(void sscop_terminate(void))
#endif
{
	if (!sscop_initialized)
		return;
	sscop_initialized = 0;
#ifndef LIS_REGISTERED
	if (sscop_minfo.mi_idnum)
		if ((sccop_minfo.mi_idnum = lis_unregister_strmod(&sscop_minfo)))
			cmn_err(CE_WARN, "sscop: couldn't unregister as module!\n");
#endif
}

/*
 *  =========================================================================
 *
 *  LINUX KERNEL MODULE INITIALIZATION
 *
 *  =========================================================================
 */

#ifdef MODULE
int init_module(void)
{
	sscop_init();
	return (0);
}
void cleanup_module(void)
{
	sscop_terminate();
	return;
}
#endif


Home Index Prev Next More Download Info FAQ Mail   Home -> Resources -> Browse Source -> strss7/drivers/sscop/sscop.c

OpenSS7
SS7 for the
Common Man
Home Overview Status News Documentation Resources About

© Copyright 1997-2004,OpenSS7 Corporation, All Rights Reserved.
Last modified: