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/m2ua2/m2ua_as.c


File /code/strss7/drivers/m2ua2/m2ua_as.c



#ident "@(#) $RCSfile: m2ua_as.c,v $ $Name:  $($Revision: 0.8.2.4 $) $Date: 2003/06/16 09:03:54 $"

static char const ident[] =
    "$RCSfile: m2ua_as.c,v $ $Name:  $($Revision: 0.8.2.4 $) $Date: 2003/06/16 09:03:54 $";

/*
 *  This is an M2UA Client Module
 */

#include <linux/config.H>
#include <linux/version.h>
#ifdef MODVERSIONS
#include <linux/modversions.h>
#endif
#include <linux/module.h>

#include <sys/stream.h>
#include <sys/stropts.h>
#include <sys/cmn_err.h>
#include <sys/dki.h>

#include <sys/npi.h>
#include <sys/npi_sctp.h>

#include <ss7/lmi.h>
#include <ss7/lmi_ioctl.h>
#include <ss7/sli.h>
#include <ss7/sli_ioctl.h>

#include "../debug.h"

#define M2UA_DESCRIP	"M2UA/SCTP SIGNALLING LINK (SL) STREAMS MODULE."
#define M2UA_COPYRIGHT	"Copyright (c) 1997-2002 OpenSS7 Corporation.  All Rights Reserved."
#define M2UA_DEVICE	"Part of the OpenSS7 Stack for LiS STREAMS."
#define M2UA_CONTACT	"Brian Bidulock <bidulock@openss7.org>"
#define M2UA_LICENSE	"GPL"
#define M2UA_BANNER	M2UA_DESCRIP	"\n" \
			M2UA_COPYRIGHT	"\n" \
			M2UA_DEVICE	"\n" \
			M2UA_CONTACT	"\n"

MODULE_AUTHOR(M2UA_CONTACT);
MODULE_DESCRIPTION(M2UA_DESCRIP);
MODULE_SUPPORTED_DEVICE(M2UA_DEVICE);
#ifdef MODULE_LICENSE
MODULE_LICENSE(M2UA_LICENSE);
#endif

#ifndef INT
#define INT void
#endif

typedef void (*bufcall_fnc_t) (long);

/*
 *  =========================================================================
 *
 *  STREAMS Definitions
 *
 *  =========================================================================
 */
static struct module_info sl_minfo = {
	0,				/* Module ID number */
	"m2ua-sl",			/* Module name */
	0,				/* Min packet size accepted *//* FIXME */
	INFPSZ,				/* Max packet size accepted *//* FIXME */
	1 << 15,			/* Hi water mark *//* FIXME */
	1 << 10				/* Lo water mark *//* FIXME */
};

static int sl_open(queue_t *, dev_t *, int, int, cred_t *);
static int sl_close(queue_t *, int, cred_t *);
static INT sl_rput(queue_t *, mblk_t *);
static INT sl_wput(queue_t *, mblk_t *);

static struct qinit sl_rinit = {
	sl_rput,			/* Read put (msg from below) */
	NULL,				/* Read queue service */
	sl_open,			/* Each open */
	sl_close,			/* Last close */
	NULL,				/* Admin (not used) */
	&sl_minfo,			/* Information */
	NULL				/* Statistics */
};

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

static struct streamtab sl_info = {
	&sl_rinit,			/* Upper read queue */
	&sl_winit,			/* Upper write queue */
	NULL,				/* Lower read queue */
	NULL				/* Lower write queue */
};

/*
 *  =========================================================================
 *
 *  M2UA-SL Private Structure
 *
 *  =========================================================================
 */
typedef struct sl {
	queue_t *rq;
	queue_t *wq;
	uint i_state;			/* SL interface state */
	uint state;			/* link state */
} sl_t;

/*
 *  =========================================================================
 *
 *  M2UA PDU Message Definitions
 *
 *  =========================================================================
 */

/*
 *  =========================================================================
 *
 *  OUTPUT Events
 *
 *  =========================================================================
 *  -------------------------------------------------------------------------
 *
 *  SL Provider (M2UA) -> SL User Primitives
 *
 *  -------------------------------------------------------------------------
 *
 *  LMI_INFO_ACK
 *  ---------------------------------------------
 */
static int lmi_info_ack(sl_t * sl)
{
	mblk_t *mp;
	lmi_info_ack_t *p;
	if ((mp = allocb(sizeof(*p), BPRI_MED))) {
		mp->b_datap->db_type = M_PCPROTO;
		p = ((lmi_info_ack_t *) mp->b_wptr)++;
		p->lmi_primitive = LMI_INFO_ACK;
		p->lmi_version = 1;
		p->lmi_state = sl->i_state;
		p->lmi_max_sdu = -1;
		p->lmi_min_sdu = 0;
		p->lmi_header_len = 0;
		p->lmi_ppa_style = LMI_STYLE1;
		putnext(sl->rq, mp);
		return (0);
	}
	rare();
	return (-ENOBUFS);
}

/*
 *  LMI_OK_ACK
 *  ---------------------------------------------
 */
static int lmi_ok_ack(sl_t * sl, long prim, mblk_t * mp)
{
	lmi_ok_ack_t *p;
	mp->b_datap->db_type = M_PCPROTO;
	mp->b_wptr = mp->b_rptr = mp->b_datap->db_base;
	p = ((typeof(p)) mp->b_wptr)++;
	p->lmi_primitive = LMI_OK_ACK;
	p->lmi_correct_primitive = prim;
	switch (sl->i_state) {
	case LMI_ATTACH_PENDING:
		sl->i_state = LMI_DISABLED;
		break;
	case LMI_DETACH_PENDING:
		sl->i_state = LMI_UNATTACHED;
		break;
		/* default is don't change state */
	}
	p->lmi_state = sl->i_state;
	putnext(sl->rq, mp);
	return (1);
}

/*
 *  LMI_ERROR_ACK
 *  ---------------------------------------------
 */
static int lmi_error_ack(sl_t * sl, long prim, long err, mblk_t * mp)
{
	lmi_error_ack_t *p;
	mp->b_datap->db_type = M_PCPROTO;
	mp->b_wptr = mp->b_rptr = mp->b_datap->db_base;
	p = ((typeof(p)) mp->b_wptr)++;
	p->lmi_primitive = LMI_ERROR_ACK;
	p->lmi_errno = err < 0 ? -err : 0;
	p->lmi_reason = err < 0 ? LMI_SYSERR : err;
	p->lmi_error_primitive = prim;
	switch (sl->i_state) {
	case LMI_ATTACH_PENDING:
		sl->i_state = LMI_UNATTACHED;
		break;
	case LMI_DETACH_PENDING:
		sl->i_state = LMI_DISABLED;
		break;
	case LMI_ENABLE_PENDING:
		sl->i_state = LMI_DISABLED;
		break;
	case LMI_DISABLE_PENDING:
		sl->i_state = LMI_ENABLED;
		break;
		/* 
		 *  Default is not to change state.
		 */
	}
	p->lmi_state = sl->i_state;
	putnext(sl->rq, mp);
	return (1);
}

/*
 *  LMI_ENABLE_CON
 *  ---------------------------------------------
 */
static int lmi_enable_con(sl_t * sl)
{
	mblk_t *mp;
	lmi_enable_con_t *p;
	ensure(sl->i_state == LMI_ENABLE_PENDING, return (-EFAULT));
	if (canputnext(sl->rq)) {
		if ((mp = allocb(sizeof(*p), BPRI_MED))) {
			mp->b_datap->db_type = M_PROTO;
			p = ((lmi_enable_con_t *) mp->b_wptr)++;
			p->lmi_primitive = LMI_ENABLE_CON;
			p->lmi_state = sl->i_state = LMI_ENABLED;
			putnext(sl->rq, mp);
			return (0);
		}
		rare();
		return (-ENOBUFS);
	}
	rare();
	return (-EBUSY);
}

/*
 *  LMI_DISABLE_CON
 *  ---------------------------------------------
 */
static int lmi_disable_con(sl_t * sl)
{
	mblk_t *mp;
	lmi_disable_con_t *p;
	ensure(sl->i_state == LMI_DISABLE_PENDING, return (-EFAULT));
	if (canputnext(sl->rq)) {
		if ((mp = allocb(sizeof(*p), BPRI_MED))) {
			mp->b_datap->db_type = M_PROTO;
			p = ((lmi_disable_con_t *) mp->b_wptr)++;
			p->lmi_primitive = LMI_DISABLE_CON;
			p->lmi_state = sl->i_state = LMI_DISABLED;
			putnext(sl->rq, mp);
			return (0);
		}
		rare();
		return (-ENOBUFS);
	}
	rare();
	return (-EBUSY);
}

/*
 *  LMI_OPTMGMT_ACK
 *  ---------------------------------------------
 */
static int lmi_optmgmt_ack(sl_t * sl, ulong flags, void *opt_ptr, size_t opt_len)
{
	mblk_t *mp;
	lmi_optmgmt_ack_t *p;
	if ((mp = allocb(sizeof(*p), BPRI_MED))) {
		mp->b_datap->db_type = M_PCPROTO;
		p = ((lmi_optmgmt_ack_t *) mp->b_wptr)++;
		p->lmi_primitive = LMI_OPTMGMT_ACK;
		p->lmi_opt_length = opt_len;
		p->lmi_opt_offset = opt_len ? sizeof(*p) : 0;
		p->lmi_mgmt_flags = flags;
		bcopy(opt_ptr, mp->b_wptr, opt_len);
		mp->b_wptr += opt_len;
		putnext(sl->rq, mp);
		return (0);
	}
	rare();
	return (-ENOBUFS);
}

/*
 *  LMI_ERROR_IND
 *  ---------------------------------------------
 */
static int lmi_error_ind(sl_t * sl, long err)
{
	mblk_t *mp;
	lmi_error_ind_t *p;
	if ((mp = allocb(sizeof(*p), BPRI_MED))) {
		mp->b_datap->db_type = M_PCPROTO;
		p = ((lmi_error_ind_t *) mp->b_wptr)++;
		p->lmi_primitive = LMI_ERROR_IND;
		p->lmi_errno = err < 0 ? -err : 0;
		p->lmi_reason = err < 0 ? LMI_SYSERR : err;
		p->lmi_state = sl->i_state;
		putnext(sl->rq, mp);
		return (0);
	}
	rare();
	return (-ENOBUFS);
}

/*
 *  LMI_STATS_IND
 *  ---------------------------------------------
 */
static int lmi_stats_ind(sl_t * sl, ulong interval, ulong timestamp)
{
	mblk_t *mp;
	lmi_stats_ind_t *p;
	if (canputnext(sl->rq)) {
		if ((mp = allocb(sizeof(*p), BPRI_MED))) {
			mp->b_datap->db_type = M_PROTO;
			p = ((lmi_stats_ind_t *) mp->b_wptr)++;
			p->lmi_primitive = LMI_STATS_IND;
			p->lmi_interval = interval;
			p->lmi_timestamp = timestamp;
			putnext(sl->rq, mp);
			return (0);
		}
		rare();
		return (-ENOBUFS);
	}
	seldom();
	return (-EBUSY);
}

/*
 *  LMI_EVENT_IND
 *  ---------------------------------------------
 */
static int lmi_event_ind(sl_t * sl, ulong oid, ulong severity, void *inf_ptr, size_t inf_len)
{
	mblk_t *mp;
	lmi_event_ind_t *p;
	if (canputnext(sl->rq)) {
		if ((mp = allocb(sizeof(*p) + inf_len, BPRI_MED))) {
			mp->b_datap->db_type = M_PROTO;
			p = ((lmi_event_ind_t *) mp->b_wptr)++;
			p->lmi_primitive = LMI_EVENT_IND;
			p->lmi_objectid = oid;
			p->lmi_timestamp = jiffies;
			p->lmi_severity = severity;
			bcopy(mp->b_wptr, inf_ptr, inf_len);
			mp->b_wptr += inf_len;
			putnext(sl->rq, mp);
			return (0);
		}
		rare();
		return (-ENOBUFS);
	}
	seldom();
	return (-EBUSY);
}

/*
 *  SL_PDU_IND
 *  ---------------------------------------------
 */
static int sl_pdu_ind(sl_t * sl, mblk_t * dp)
{
	mblk_t *mp;
	sl_pdu_ind_t *p;
	if (canputnext(sl->rq)) {
		if ((mp = allocb(sizeof(*p), BPRI_MED))) {
			mp->b_datap->db_type = M_PROTO;
			p = ((sl_pdu_ind_t *) mp->b_wptr)++;
			p->sl_primitive = SL_PDU_IND;
			mp->b_cont = dp;
			ptrace(("Delivering mp = %u\n", (uint) mp));
			putnext(sl->rq, mp);
			return (0);
		}
		rare();
		return (-ENOBUFS);
	}
	seldom();
	return (-EBUSY);
}

/*
 *  SL_LINK_CONGESTED_IND
 *  ---------------------------------------------
 */
static int sl_link_congested_ind(sl_t * sl, ulong cong, ulong disc)
{
	mblk_t *mp;
	sl_link_cong_ind_t *p;
	if (canputnext(sl->rq)) {
		if ((mp = allocb(sizeof(*p), BPRI_MED))) {
			mp->b_datap->db_type = M_PROTO;
			p = ((sl_link_cong_ind_t *) mp->b_wptr)++;
			p->sl_primitive = SL_LINK_CONGESTED_IND;
			p->sl_timestamp = jiffies;
			p->sl_cong_status = cong;
			p->sl_disc_status = disc;
			putnext(sl->rq, mp);
			return (0);
		}
		rare();
		return (-ENOBUFS);
	}
	seldom();
	return (-EBUSY);
}

/*
 *  SL_LINK_CONGESTION_CEASED_IND
 *  ---------------------------------------------
 */
static int sl_link_congestion_ceased_ind(sl_t * sl, ulong cong, ulong disc)
{
	mblk_t *mp;
	sl_link_cong_ceased_ind_t *p;
	if (canputnext(sl->rq)) {
		if ((mp = allocb(sizeof(*p), BPRI_MED))) {
			mp->b_datap->db_type = M_PROTO;
			p = ((sl_link_cong_ceased_ind_t *) mp->b_wptr)++;
			p->sl_primitive = SL_LINK_CONGESTION_CEASED_IND;
			p->sl_timestamp = jiffies;
			p->sl_cong_status = cong;
			p->sl_disc_status = disc;
			putnext(sl->rq, mp);
			return (0);
		}
		rare();
		return (-ENOBUFS);
	}
	seldom();
	return (-EBUSY);
}

/*
 *  SL_RETRIEVED_MESSAGE_IND
 *  ---------------------------------------------
 */
static int sl_retrieved_message_ind(sl_t * sl, mblk_t * dp)
{
	mblk_t *mp;
	sl_retrieved_msg_ind_t *p;
	if (canputnext(sl->rq)) {
		if ((mp = allocb(sizeof(*p), BPRI_MED))) {
			mp->b_datap->db_type = M_PROTO;
			p = ((sl_retrieved_msg_ind_t *) mp->b_wptr)++;
			p->sl_primitive = SL_RETRIEVED_MESSAGE_IND;
			mp->b_cont = dp;
			putnext(sl->rq, mp);
			return (0);
		}
		rare();
		return (-ENOBUFS);
	}
	seldom();
	return (-EBUSY);
}

/*
 *  SL_RETRIEVAL_COMPLETE_IND
 *  ---------------------------------------------
 */
static int sl_retrieval_complete_ind(sl_t * sl)
{
	mblk_t *mp;
	sl_retrieval_comp_ind_t *p;
	if (canputnext(sl->rq)) {
		if ((mp = allocb(sizeof(*p), BPRI_MED))) {
			mp->b_datap->db_type = M_PROTO;
			p = ((sl_retrieval_comp_ind_t *) mp->b_wptr)++;
			p->sl_primitive = SL_RETRIEVAL_COMPLETE_IND;
			putnext(sl->rq, mp);
			return (0);
		}
		rare();
		return (-ENOBUFS);
	}
	seldom();
	return (-EBUSY);
}

/*
 *  SL_RB_CLEARED_IND
 *  ---------------------------------------------
 */
static int sl_rb_cleared_ind(sl_t * sl)
{
	mblk_t *mp;
	sl_rb_cleared_ind_t *p;
	if (canputnext(sl->rq)) {
		if ((mp = allocb(sizeof(*p), BPRI_MED))) {
			mp->b_datap->db_type = M_PROTO;
			p = ((sl_rb_cleared_ind_t *) mp->b_wptr)++;
			p->sl_primitive = SL_RB_CLEARED_IND;
			putnext(sl->rq, mp);
			return (0);
		}
		rare();
		return (-ENOBUFS);
	}
	seldom();
	return (-EBUSY);
}

/*
 *  SL_BSNT_IND
 *  ---------------------------------------------
 */
static int sl_bsnt_ind(sl_t * sl, ulong bsnt)
{
	mblk_t *mp;
	sl_bsnt_ind_t *p;
	if (canputnext(sl->rq)) {
		if ((mp = allocb(sizeof(*p), BPRI_MED))) {
			mp->b_datap->db_type = M_PROTO;
			p = ((sl_bsnt_ind_t *) mp->b_wptr)++;
			p->sl_primitive = SL_BSNT_IND;
			p->sl_bsnt = bsnt;
			putnext(sl->rq, mp);
			return (0);
		}
		rare();
		return (-ENOBUFS);
	}
	seldom();
	return (-EBUSY);
}

/*
 *  SL_IN_SERVICE_IND
 *  ---------------------------------------------
 */
static int sl_in_service_ind(sl_t * sl)
{
	mblk_t *mp;
	sl_in_service_ind_t *p;
	if (canputnext(sl->rq)) {
		if ((mp = allocb(sizeof(*p), BPRI_MED))) {
			mp->b_datap->db_type = M_PROTO;
			p = ((sl_in_service_ind_t *) mp->b_wptr)++;
			p->sl_primitive = SL_IN_SERVICE_IND;
			putnext(sl->rq, mp);
			return (0);
		}
		rare();
		return (-ENOBUFS);
	}
	seldom();
	return (-EBUSY);
}

/*
 *  SL_OUT_OF_SERVICE_IND
 *  ---------------------------------------------
 */
static int sl_out_of_service_ind(sl_t * sl, ulong reason)
{
	mblk_t *mp;
	sl_out_of_service_ind_t *p;
	if (canputnext(sl->rq)) {
		if ((mp = allocb(sizeof(*p), BPRI_MED))) {
			mp->b_datap->db_type = M_PROTO;
			p = ((sl_out_of_service_ind_t *) mp->b_wptr)++;
			p->sl_primitive = SL_OUT_OF_SERVICE_IND;
			p->sl_timestamp = jiffies;
			p->sl_reason = reason;
			putnext(sl->rq, mp);
			return (0);
		}
		rare();
		return (-ENOBUFS);
	}
	seldom();
	return (-EBUSY);
}

/*
 *  SL_REMOTE_PROCESSOR_OUTAGE_IND
 *  ---------------------------------------------
 */
static int sl_remote_processor_outage_ind(sl_t * sl)
{
	mblk_t *mp;
	sl_rem_proc_out_ind_t *p;
	if (canputnext(sl->rq)) {
		if ((mp = allocb(sizeof(*p), BPRI_MED))) {
			mp->b_datap->db_type = M_PROTO;
			p = ((sl_rem_proc_out_ind_t *) mp->b_wptr)++;
			p->sl_primitive = SL_REMOTE_PROCESSOR_OUTAGE_IND;
			p->sl_timestamp = jiffies;
			putnext(sl->rq, mp);
			return (0);
		}
		rare();
		return (-ENOBUFS);
	}
	seldom();
	return (-EBUSY);
}

/*
 *  SL_REMOTE_PROCESSOR_RECOVERED_IND
 *  ---------------------------------------------
 */
static int sl_remote_processor_recovered_ind(sl_t * sl)
{
	mblk_t *mp;
	sl_rem_proc_recovered_ind_t *p;
	if (canputnext(sl->rq)) {
		if ((mp = allocb(sizeof(*p), BPRI_MED))) {
			mp->b_datap->db_type = M_PROTO;
			p = ((sl_rem_proc_recovered_ind_t *) mp->b_wptr)++;
			p->sl_primitive = SL_REMOTE_PROCESSOR_RECOVERED_IND;
			p->sl_timestamp = jiffies;
			putnext(sl->rq, mp);
			return (0);
		}
		rare();
		return (-ENOBUFS);
	}
	seldom();
	return (-EBUSY);
}

/*
 *  SL_RTB_CLEARED_IND
 *  ---------------------------------------------
 */
static int sl_rtb_cleared_ind(sl_t * sl)
{
	mblk_t *mp;
	sl_rtb_cleared_ind_t *p;
	if (canputnext(sl->rq)) {
		if ((mp = allocb(sizeof(*p), BPRI_MED))) {
			mp->b_datap->db_type = M_PROTO;
			p = ((sl_rtb_cleared_ind_t *) mp->b_wptr)++;
			p->sl_primitive = SL_RTB_CLEARED_IND;
			putnext(sl->rq, mp);
			return (0);
		}
		rare();
		return (-ENOBUFS);
	}
	seldom();
	return (-EBUSY);
}

/*
 *  SL_RETRIEVAL_NOT_POSSIBLE_IND
 *  ---------------------------------------------
 */
static int sl_retrieval_not_possible_ind(sl_t * sl)
{
	mblk_t *mp;
	sl_retrieval_not_poss_ind_t *p;
	if (canputnext(sl->rq)) {
		if ((mp = allocb(sizeof(*p), BPRI_MED))) {
			mp->b_datap->db_type = M_PROTO;
			p = ((sl_retrieval_not_poss_ind_t *) mp->b_wptr)++;
			p->sl_primitive = SL_RETRIEVAL_NOT_POSSIBLE_IND;
			putnext(sl->rq, mp);
			return (0);
		}
		rare();
		return (-ENOBUFS);
	}
	seldom();
	return (-EBUSY);
}

/*
 *  SL_BSNT_NOT_RETRIEVABLE_IND
 *  ---------------------------------------------
 */
static int sl_bsnt_not_retrievable_ind(sl_t * sl, ulong bsnt)
{
	mblk_t *mp;
	sl_bsnt_not_retr_ind_t *p;
	if (canputnext(sl->rq)) {
		if ((mp = allocb(sizeof(*p), BPRI_MED))) {
			mp->b_datap->db_type = M_PROTO;
			p = ((sl_bsnt_not_retr_ind_t *) mp->b_wptr)++;
			p->sl_primitive = SL_BSNT_NOT_RETRIEVABLE_IND;
			p->sl_bsnt = bsnt;
			putnext(sl->rq, mp);
			return (0);
		}
		rare();
		return (-ENOBUFS);
	}
	seldom();
	return (-EBUSY);
}

/*
 *  -------------------------------------------------------------------------
 *
 *  NPI User (M2UA) -> NPI Provider (SCTP) Primitives
 *
 *  -------------------------------------------------------------------------
 *
 *  N_DATA_REQ
 *  ---------------------------------------------
 */
static int n_data_req(sl_t * sl, ulong flags, void *qos_ptr, size_t qos_len, mblk_t * dp)
{
	mblk_t *mp;
	N_data_req_t *p;
	if (canputnext(sl->wq)) {
		if ((mp = allocb(sizeof(*p) + qos_len, 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;
			bcopy(qos_ptr, mp->b_wptr, qos_len);
			mp->b_wptr += qos_len;
			mp->b_cont = dp;
			putnext(sl->wq, mp);
			return (0);
		}
		rare();
		return (-ENOBUFS);
	}
	seldom();
	return (-EBUSY);
}

/*
 *  N_EXDATA_REQ
 *  ---------------------------------------------
 */
static int n_exdata_req(sl_t * sl, void *qos_ptr, size_t qos_len, mblk_t * dp)
{
	mblk_t *mp;
	N_exdata_req_t *p;
	if (bcanputnext(sl->wq, 1)) {
		if ((mp = allocb(sizeof(*p) + qos_len, BPRI_MED))) {
			mp->b_datap->db_type = M_PROTO;
			p = ((N_exdata_req_t *) mp->b_wptr)++;
			p->PRIM_type = N_EXDATA_REQ;
			bcopy(qos_ptr, mp->b_wptr, qos_len);
			mp->b_wptr += qos_len;
			mp->b_cont = dp;
			putnext(sl->wq, mp);
			return (0);
		}
		rare();
		return (-ENOBUFS);
	}
	seldom();
	return (-EBUSY);
}

/*
 *  -------------------------------------------------------------------------
 *
 *  SL Peer (M2UA) -> SL Peer Sent Messages
 *
 *  -------------------------------------------------------------------------
 *
 *  M2UA SEND PROVING
 *  ---------------------------------------------
 */
static int sl_send_proving(sl_t * sl, size_t plen)
{
	int err;
	mblk_t *mp;
	N_qos_sel_data_sctp_t qos = { N_QOS_SEL_DATA_SCTP, M2UA_PPI, M2UA_DATA_STREAM, };
	if ((mp = allocb(2 * sizeof(uint32_t) + plen, BPRI_MED))) {
		mp->b_datap->db_type = M_DATA;
		*((uint32_t *) mp->b_wptr)++ = M2UA_PROVING_MESSAGE;
		*((uint32_t *) mp->b_wptr)++ = __constant_htonl(2 * sizeof(uint32_t) + plen);
		fixme(("We should include a test pattern.\n"));
		bzero(mp->b_wptr, plen);
		mp->b_wptr += plen;
		if (!(err = n_data_req(sl, 0, &qos, sizeof(qos), mp)))
			return (0);
		freeb(mp);
		return (err);
	}
	return (-ENOBUFS);
}

/*
 *  M2UA SEND STATUS
 *  ---------------------------------------------
 */
static int sl_send_status(sl_t * sl, uint32_t status)
{
	int err;
	mblk_t *mp;
	N_qos_sel_data_sctp_t qos = { N_QOS_SEL_DATA_SCTP, M2UA_PPI, M2UA_STATUS_STREAM, };
	if ((mp = allocb(3 * sizeof(uint32_t), BPRI_MED))) {
		mp->b_datap->db_type = M_DATA;
		*((uint32_t *) mp->b_wptr)++ = M2UA_STATUS_MESSAGE;
		*((uint32_t *) mp->b_wptr)++ = __constant_htonl(3 * sizeof(uint32_t));
		*((uint32_t *) mp->b_wptr)++ = status;
		if (!(err = n_data_req(sl, 0, &qos, sizeof(qos), mp)))
			return (0);
		assert(mp->b_datap->db_ref);
		freeb(mp);
		return (err);
	}
	return (-ENOBUFS);
}

/*
 *  M2UA SEND ACK
 *  ---------------------------------------------
 */
static int sl_send_ack(sl_t * sl, ulong count)
{
	int err;
	mblk_t *mp;
	N_qos_sel_data_sctp_t qos = { N_QOS_SEL_DATA_SCTP, M2UA_PPI, M2UA_DATA_STREAM, };
	if ((mp = allocb(3 * sizeof(uint32_t), BPRI_MED))) {
		mp->b_datap->db_type = M_DATA;
		*((uint32_t *) mp->b_wptr)++ = M2UA_ACK_MESSAGE;
		*((uint32_t *) mp->b_wptr)++ = __constant_htonl(3 * sizeof(uint32_t));
		*((uint32_t *) mp->b_wptr)++ = htonl(count);
		if ((err = n_exdata_req(sl, &qos, sizeof(qos), mp))) {
			assert(mp->b_datap->db_ref);
			freeb(mp);
			return (err);
		}
		return (0);
	}
	return (-ENOBUFS);
}

/*
 *  M2UA SEND DATA
 *  ---------------------------------------------
 */
static int sl_send_data(sl_t * sl, mblk_t * dp)
{
	int err;
	mblk_t *mp, *db;
	ulong rcpt = sl->version < M2UA_VERSION_DRAFT4 ? N_RC_FLAG : 0;
	size_t dlen = msgdsize(dp);
	N_qos_sel_data_sctp_t qos = { N_QOS_SEL_DATA_SCTP, M2UA_PPI, M2UA_DATA_STREAM, };
	if (!(db = dupmsg(dp)))
		return (-ENOBUFS);
	if ((mp = allocb(2 * sizeof(uint32_t), BPRI_MED))) {
		mp->b_datap->db_type = M_DATA;
		*((uint32_t *) mp->b_wptr)++ = M2UA_DATA_MESSAGE;
		*((uint32_t *) mp->b_wptr)++ = __constant_htonl(dlen + 2 * sizeof(uint32_t));
		mp->b_cont = db;
		pullupmsg(mp, -1);
		if ((err = n_data_req(sl, rcpt, &qos, sizeof(qos), mp))) {
			assert(mp->b_datap->db_ref);
			freemsg(mp);
			return (err);
		}
		return (0);
	}
	freemsg(db);
	return (-ENOBUFS);
}

/*
 *  =========================================================================
 *
 *  M2UA State Machines
 *
 *  =========================================================================
 */

/*
 *  =========================================================================
 *
 *  INPUT Events
 *
 *  =========================================================================
 */
/*
 *  -------------------------------------------------------------------------
 *
 *  SL Peer -> SL Peer (M2UA) Received Messages
 *
 *  -------------------------------------------------------------------------
 */
static int m2ua_attach_req(sl_t * sl, mblk_t * mp)
{
}
static int m2ua_clear_buffers(sl_t * sl, mblk_t * mp)
{
}
static int m2ua_clear_rtb(sl_t * sl, mblk_t * mp)
{
}
static int m2ua_congestion_accept(sl_t * sl, mblk_t * mp)
{
}
static int m2ua_congestion_discard(sl_t * sl, mblk_t * mp)
{
}
static int m2ua_detach_req(sl_t * sl, mblk_t * mp)
{
}
static int m2ua_disable(sl_t * sl, mblk_t * mp)
{
}
static int m2ua_emergency_ceases(sl_t * sl, mblk_t * mp)
{
}
static int m2ua_emergency(sl_t * sl, mblk_t * mp)
{
}
static int m2ua_enable(sl_t * sl, mblk_t * mp)
{
}
static int m2ua_local_processor_outage(sl_t * sl, mblk_t * mp)
{
}
static int m2ua_no_congestion(sl_t * sl, mblk_t * mp)
{
}
static int m2ua_power_on(sl_t * sl, mblk_t * mp)
{
}
static int m2ua_recv_msg(sl_t * sl, mblk_t * mp)
{
}
static int m2ua_recv_msg(sl_t * sl, mblk_t * mp)
{
}
static int m2ua_resume(sl_t * sl, mblk_t * mp)
{
}
static int m2ua_retrieval_request_and_fsnc(sl_t * sl, mblk_t * mp, ulong fsnc)
{
}
static int m2ua_retrieve_bsnt(sl_t * sl, mblk_t * mp)
{
}
static int m2ua_send_msg(sl_t * sl, mblk_t * mp)
{
}
static int m2ua_start(sl_t * sl, mblk_t * mp)
{
}
static int m2ua_stop(sl_t * sl, mblk_t * mp)
{
}

/*
 *  =========================================================================
 */

/*
 *  -------------------------------------------------------------------------
 *
 *  SL User -> SL Provider (M2UA) Primitives
 *
 *  -------------------------------------------------------------------------
 *
 *  LMI_INFO_REQ
 *  ---------------------------------------------
 */
static int lmi_info_req(sl_t * sl, mblk_t * mp)
{
	(void) mp;
	return lmi_info_ack(sl);
}

/*
 *  LMI_ATTACH_REQ
 *  ---------------------------------------------
 */
static int lmi_attach_req(sl_t * sl, mblk_t * mp)
{
	int err;
	size_t mlen = mp->b_wptr - mp->b_rptr;
	lmi_attach_req_t *p = (lmi_attach_req_t *) mp->b_rptr;
	do {
		if (mlen >= sizeof(*p)) {
			if (sl->i_state == LMI_UNATTACHED) {
				sl->i_state = LMI_ATTACH_PENDING;
				return m2ua_attach_req(sl, mp);
			}
			seldom();
			err = LMI_OUTSTATE;
			break;	/* would place interface out of state */
		}
		seldom();
		err = LMI_PROTOSHORT;
		break;		/* M_PROTO block too short */
	} while (0);
	seldom();
	return lmi_error_ack(sl, LMI_ATTACH_REQ, err, mp);
}

/*
 *  LMI_DETACH_REQ
 *  ---------------------------------------------
 */
static int lmi_detach_req(sl_t * sl, mblk_t * mp)
{
	int err;
	size_t mlen = mp->b_wptr - mp->b_rptr;
	lmi_detach_req_t *p = (lmi_detach_req_t *) mp->b_rptr;
	do {
		if (mlen >= sizeof(*p)) {
			if (sl->i_state == LMI_DISABLED) {
				sl->i_state = LMI_DETACH_PENDING;
				return m2ua_detach_req(sl, mp);
			}
			seldom();
			err = LMI_OUTSTATE;
			break;	/* would place interface out of state */
		}
		seldom();
		err = LMI_PROTOSHORT;
		break;		/* M_PROTO block too short */
	} while (0);
	seldom();
	return lmi_error_ack(sl, LMI_DETACH_REQ, err, mp);
}

/*
 *  LMI_ENABLE_REQ
 *  ---------------------------------------------
 */
static int lmi_enable_req(sl_t * sl, mblk_t * mp)
{
	int err;
	size_t mlen = mp->b_wptr - mp->b_rptr;
	lmi_enable_req_t *p = (lmi_enable_req_t *) mp->b_rptr;
	do {
		if (mlen >= sizeof(*p)) {
			if (sl->i_state == LMI_DISABLED) {
				sl->i_state = LMI_ENABLE_PENDING;
				return m2ua_enable(sl, mp);
			}
			seldom();
			err = LMI_OUTSTATE;
			break;	/* would place interface out of state */
		}
		seldom();
		err = LMI_PROTOSHORT;
		break;		/* M_PROTO block too short */
	} while (0);
	seldom();
	return lmi_error_ack(sl, LMI_ENABLE_REQ, err, mp);
}

/*
 *  LMI_DISABLE_REQ
 *  ---------------------------------------------
 */
static int lmi_disable_req(sl_t * sl, mblk_t * mp)
{
	int err;
	size_t mlen = mp->b_wptr - mp->b_rptr;
	lmi_disable_req_t *p = (lmi_disable_req_t *) mp->b_rptr;
	do {
		if (mlen >= sizeof(*p)) {
			if (sl->i_state == LMI_ENABLE_PENDING) {
				sl->i_state = LMI_DISABLED;
				return lmi_disable_con(sl, mp);
			}
			if (sl->i_state == LMI_ENABLED) {
				sl->i_state = LMI_DISABLE_PENDING;
				return m2ua_disable(sl, mp);
			}
			seldom();
			err = LMI_OUTSTATE;
			break;	/* would place interface out of state */
		}
		seldom();
		err = LMI_PROTOSHORT;
		break;		/* M_PROTO block too short */
	} while (0);
	seldom();
	return lmi_error_ack(sl, LMI_DISABLE_REQ, err, mp);
}

/*
 *  LMI_OPTMGMT_REQ
 *  ---------------------------------------------
 */
static int lmi_optmgmt_req(sl_t * sl, mblk_t * mp)
{
	int err;
	size_t mlen = mp->b_wptr - mp->b_rptr;
	lmi_optmgmt_req_t *p = (lmi_optmgmt_req_t *) mp->b_rptr;
	do {
		if (mlen >= sizeof(*p)) {
			lmi_error_ack(sl, LMI_OPTMGMT_REQ, LMI_NOTSUPP, mp);
		}
		seldom();
		err = LMI_PROTOSHORT;
		break;		/* M_PROTO block too short */
	} while (0);
	seldom();
	return lmi_error_ack(sl, LMI_OPTMGMT_REQ, err, mp);
}

/*
 *  SL_PDU_REQ
 *  ---------------------------------------------
 */
#ifndef abs
#define abs(x) ((x)<0 ? -(x):(x))
#endif
static int m_error_reply(sl_t * sl, int err, mblk_t * mp)
{
	mp->b_datap->db_type = M_ERROR;
	mp->b_wptr = mp->b_rptr;
	*(mp->b_wptr)++ = abs(err);
	*(mp->b_wptr)++ = abs(err);
	putnext(sl->rq, mp);
	return (1);
}
static int sl_pdu_req(sl_t * sl, mblk_t * mp)
{
	int err;
	mblk_t *dp;
	size_t mlen = mp->b_wptr - mp->b_rptr;
	sl_pdu_req_t *p = (sl_pdu_req_t *) mp->b_rptr;
	do {
		if (mlen >= sizeof(*p)) {
			if ((dp = mp->b_cont)) {
				if ((err = m2pa_send_msg(sl, dp)))
					return (err);
				mp->b_cont = NULL;	/* data absorbed */
				return (0);
			}
			seldom();
			err = LMI_BADPRIM;
			break;	/* No M_DATA block */
		}
		seldom();
		err = LMI_PROTOSHORT;
		break;		/* M_PROTO block too short */
	} while (0);
	seldom();
	return m_error_reply(sl, err, mp);
}

/*
 *  SL_EMERGENCY_REQ
 *  ---------------------------------------------
 */
static int sl_emergency_req(sl_t * sl, mblk_t * mp)
{
	int err;
	size_t mlen = mp->b_wptr - mp->b_rptr;
	sl_emergency_req_t *p = (sl_emergency_req_t *) mp->b_rptr;
	do {
		if (mlen >= sizeof(*p)) {
			return m2ua_emergency(sl, mp);
		}
		seldom();
		err = LMI_PROTOSHORT;
		break;		/* M_PROTO block too short */
	} while (0);
	seldom();
	return m_error_reply(sl, err, mp);
}

/*
 *  SL_EMERGENCY_CEASES_REQ
 *  ---------------------------------------------
 */
static int sl_emergency_ceases_req(sl_t * sl, mblk_t * mp)
{
	int err;
	size_t mlen = mp->b_wptr - mp->b_rptr;
	sl_emergency_ceases_req_t *p = (sl_emergency_ceases_req_t *) mp->b_rptr;
	do {
		if (mlen >= sizeof(*p)) {
			return m2ua_emergency_ceases(sl, mp);
		}
		seldom();
		err = LMI_PROTOSHORT;
		break;		/* M_PROTO block too short */
	} while (0);
	seldom();
	return m_error_reply(sl, err, mp);
}

/*
 *  SL_START_REQ
 *  ---------------------------------------------
 */
static int sl_start_req(sl_t * sl, mblk_t * mp)
{
	int err;
	size_t mlen = mp->b_wptr - mp->b_rptr;
	sl_start_req_t *p = (sl_start_req_t *) mp->b_rptr;
	do {
		if (mlen >= sizeof(*p)) {
			return m2ua_start(sl, mp);
		}
		seldom();
		err = LMI_PROTOSHORT;
		break;		/* M_PROTO block too short */
	} while (0);
	seldom();
	return m_error_reply(sl, err, mp);
}

/*
 *  SL_STOP_REQ
 *  ---------------------------------------------
 */
static int sl_stop_req(sl_t * sl, mblk_t * mp)
{
	int err;
	size_t mlen = mp->b_wptr - mp->b_rptr;
	sl_stop_req_t *p = (sl_stop_req_t *) mp->b_rptr;
	do {
		if (mlen >= sizeof(*p)) {
			return m2ua_stop(sl, mp);
		}
		seldom();
		err = LMI_PROTOSHORT;
		break;		/* M_PROTO block too short */
	} while (0);
	seldom();
	return m_error_reply(sl, err, mp);
}

/*
 *  SL_RETRIEVE_BSNT_REQ
 *  ---------------------------------------------
 */
static int sl_retrieve_bsnt_req(sl_t * sl, mblk_t * mp)
{
	int err;
	size_t mlen = mp->b_wptr - mp->b_rptr;
	sl_retrieve_bsnt_req_t *p = (sl_retrieve_bsnt_req_t *) mp->b_rptr;
	do {
		if (mlen >= sizeof(*p)) {
			return m2ua_retrieve_bsnt(sl, mp);
		}
		seldom();
		err = LMI_PROTOSHORT;
		break;		/* M_PROTO block too short */
	} while (0);
	seldom();
	return m_error_reply(sl, err, mp);
}

/*
 *  SL_RETRIEVAL_REQUEST_AND_FSNC_REQ
 *  ---------------------------------------------
 */
static int sl_retrieval_request_and_fsnc_req(sl_t * sl, mblk_t * mp)
{
	int err;
	size_t mlen = mp->b_wptr - mp->b_rptr;
	sl_retrieval_req_and_fsnc_t *p = (sl_retrieval_req_and_fsnc_t *) mp->b_rptr;
	do {
		if (mlen >= sizeof(*p)) {
			return m2ua_retrieval_request_and_fsnc(sl, mp, p->sl_fsnc);
		}
		seldom();
		err = LMI_PROTOSHORT;
		break;		/* M_PROTO block too short */
	} while (0);
	seldom();
	return m_error_reply(sl, err, mp);
}

/*
 *  SL_RESUME_REQ
 *  ---------------------------------------------
 */
static int sl_resume_req(sl_t * sl, mblk_t * mp)
{
	int err;
	size_t mlen = mp->b_wptr - mp->b_rptr;
	sl_resume_req_t *p = (sl_resume_req_t *) mp->b_rptr;
	do {
		if (mlen >= sizeof(*p)) {
			return m2ua_resume(sl, mp);
		}
		seldom();
		err = LMI_PROTOSHORT;
		break;		/* M_PROTO block too short */
	} while (0);
	seldom();
	return m_error_reply(sl, err, mp);
}

/*
 *  SL_CLEAR_BUFFERS_REQ
 *  ---------------------------------------------
 */
static int sl_clear_buffers_req(sl_t * sl, mblk_t * mp)
{
	int err;
	size_t mlen = mp->b_wptr - mp->b_rptr;
	sl_clear_buffers_req_t *p = (sl_clear_buffers_req_t *) mp->b_rptr;
	do {
		if (mlen >= sizeof(*p)) {
			return m2ua_clear_buffers(sl, mp);
		}
		seldom();
		err = LMI_PROTOSHORT;
		break;		/* M_PROTO block too short */
	} while (0);
	seldom();
	return m_error_reply(sl, err, mp);
}

/*
 *  SL_CLEAR_RTB_REQ
 *  ---------------------------------------------
 */
static int sl_clear_rtb_req(sl_t * sl, mblk_t * mp)
{
	int err;
	size_t mlen = mp->b_wptr - mp->b_rptr;
	sl_clear_rtb_req_t *p = (sl_clear_rtb_req_t *) mp->b_rptr;
	do {
		if (mlen >= sizeof(*p)) {
			return m2ua_clear_rtb(sl, mp);
		}
		seldom();
		err = LMI_PROTOSHORT;
		break;		/* M_PROTO block too short */
	} while (0);
	seldom();
	return m_error_reply(sl, err, mp);
}

/*
 *  SL_LOCAL_PROCESSOR_OUTAGE_REQ
 *  ---------------------------------------------
 */
static int sl_local_processor_outage_req(sl_t * sl, mblk_t * mp)
{
	int err;
	size_t mlen = mp->b_wptr - mp->b_rptr;
	sl_local_proc_outage_req_t *p = (sl_local_proc_outage_req_t *) mp->b_rptr;
	do {
		if (mlen >= sizeof(*p)) {
			return m2ua_local_processor_outage(sl, mp);
		}
		seldom();
		err = LMI_PROTOSHORT;
		break;		/* M_PROTO block too short */
	} while (0);
	seldom();
	return m_error_reply(sl, err, mp);
}

/*
 *  SL_CONGESTION_DISCARD_REQ
 *  ---------------------------------------------
 */
static int sl_congestion_discard_req(sl_t * sl, mblk_t * mp)
{
	int err;
	size_t mlen = mp->b_wptr - mp->b_rptr;
	sl_cong_discard_req_t *p = (sl_cong_discard_req_t *) mp->b_rptr;
	do {
		if (mlen >= sizeof(*p)) {
			return m2ua_congestion_discard(sl, mp);
		}
		seldom();
		err = LMI_PROTOSHORT;
		break;		/* M_PROTO block too short */
	} while (0);
	seldom();
	return m_error_reply(sl, err, mp);
}

/*
 *  SL_CONGESTION_ACCEPT_REQ
 *  ---------------------------------------------
 */
static int sl_congestion_accept_req(sl_t * sl, mblk_t * mp)
{
	int err;
	size_t mlen = mp->b_wptr - mp->b_rptr;
	sl_cong_accept_req_t *p = (sl_cong_accept_req_t *) mp->b_rptr;
	do {
		if (mlen >= sizeof(*p)) {
			return m2ua_congestion_accept(sl, mp);
		}
		seldom();
		err = LMI_PROTOSHORT;
		break;		/* M_PROTO block too short */
	} while (0);
	seldom();
	return m_error_reply(sl, err, mp);
}

/*
 *  SL_NO_CONGESTION_REQ
 *  ---------------------------------------------
 */
static int sl_no_congestion_req(sl_t * sl, mblk_t * mp)
{
	int err;
	size_t mlen = mp->b_wptr - mp->b_rptr;
	sl_no_cong_req_t *p = (sl_no_cong_req_t *) mp->b_rptr;
	do {
		if (mlen >= sizeof(*p)) {
			return m2ua_no_congestion(sl, mp);
		}
		seldom();
		err = LMI_PROTOSHORT;
		break;		/* M_PROTO block too short */
	} while (0);
	seldom();
	return m_error_reply(sl, err, mp);
}

/*
 *  SL_POWER_ON_REQ
 *  ---------------------------------------------
 */
static int sl_power_on_req(sl_t * sl, mblk_t * mp)
{
	int err;
	size_t mlen = mp->b_wptr - mp->b_rptr;
	sl_power_on_req_t *p = (sl_power_on_req_t *) mp->b_rptr;
	do {
		if (mlen >= sizeof(*p)) {
			return m2ua_power_on(sl, mp);
		}
		seldom();
		err = LMI_PROTOSHORT;
		break;		/* M_PROTO block too short */
	} while (0);
	seldom();
	return m_error_reply(sl, err, mp);
}

/*
 *  -------------------------------------------------------------------------
 *
 *  NPI Provider -> NPI User (M2UA) Primitives
 *
 *  -------------------------------------------------------------------------
 *
 *  N_DATA_IND
 *  ---------------------------------------------
 */
static int n_data_ind(sl_t * sl, mblk_t * mp)
{
	int err;
	mblk_t *dp;
	size_t mlen = mp->b_wptr - mp->b_rptr;
	N_data_ind_t *p = (N_data_ind_t *) mp->b_rptr;
	ensure(mlen >= sizeof(*p), return (-EFAULT));
	if ((dp = mp->b_cont)) {
		if (sl->i_state == LMI_ENABLED) {
			if ((err = m2ua_recv_msg(sl, dp)))
				return (err);
			mp->b_cont = NULL;	/* absorbed data */
			return (0);
		}
		rare();
		return (-EPROTO);	/* ignore data in other states */
	}
	rare();
	return (-EFAULT);
}

/*
 *  N_EXDATA_IND
 *  ---------------------------------------------
 */
static int n_exdata_ind(sl_t * sl, mblk_t * mp)
{
	int err;
	mblk_t *dp;
	size_t mlen = mp->b_wptr - mp->b_rptr;
	N_exdata_ind_t *p = (N_exdata_ind_t *) mp->b_rptr;
	ensure(mlen >= sizeof(*p), return (-EFAULT));
	if ((dp = mp->b_cont)) {
		if (sl->i_state == LMI_ENABLED) {
			if ((err = m2ua_recv_msg(sl, dp)))
				return (err);
			mp->b_cont = NULL;	/* absorbed data */
			return (0);
		}
		rare();
		return (-EPROTO);	/* ignore data in other states */
	}
	rare();
	return (-EFAULT);
}

/*
 *  N_DATACK_IND
 *  ---------------------------------------------
 */
static int n_datack_ind(sl_t * sl, mblk_t * mp)
{
	int err;
	size_t mlen = mp->b_wptr - mp->b_rptr;
	N_datack_ind_t *p = (N_datack_ind_t *) mp->b_rptr;
	ensure(mlen >= sizeof(*p), return (-EFAULT));
	return (0);
	rare();
	return (-EFAULT);	/* shouldn't be getting these */
}

/*
 *  N_DISCON_IND
 *  ---------------------------------------------
 */
static int n_discon_ind(sl_t * sl, mblk_t * mp)
{
	int err;
	size_t mlen = mp->b_wptr - mp->b_rptr;
	N_discon_ind_t *p = (N_discon_ind_t *) mp->b_rptr;
	ensure(mlen >= sizeof(*p), return (-EFAULT));
	if ((err = sl_lsc_out_of_service(sl, SL_FAIL_SUERM_EIM)))
		return (err);
	if (sl->notify.events & SL_EVT_FAIL_SUERM_EIM)
		if ((err = lmi_event_ind(sl, SL_EVT_FAIL_SUERM_EIM, 0, NULL, 0)))
			return (err);
	ptrace(("Link failed: SUERM/EIM\n"));
	fixme(("Do something here... send a HANGUP or something...\n"));
	return (0);
}

/*
 *  N_RESET_IND
 *  ---------------------------------------------
 */
static int n_reset_ind(sl_t * sl, mblk_t * mp)
{
	size_t mlen = mp->b_wptr - mp->b_rptr;
	N_reset_ind_t *p = (N_reset_ind_t *) mp->b_rptr;
	ensure(mlen >= sizeof(*p), return (-EFAULT));
	fixme(("Do something here...\n"));
	return (-EFAULT);
}

/*
 *  N_CONN_IND
 *  ---------------------------------------------
 */
static int n_conn_ind(sl_t * sl, mblk_t * mp)
{
	size_t mlen = mp->b_wptr - mp->b_rptr;
	N_conn_ind_t *p = (N_conn_ind_t *) mp->b_rptr;
	ensure(mlen >= sizeof(*p), return (-EFAULT));
	fixme(("Do something here...\n"));
	return (-EFAULT);
}

/*
 *  N_CONN_RES
 *  ---------------------------------------------
 */
static int n_conn_req(sl_t * sl, mblk_t * mp)
{
	size_t mlen = mp->b_wptr - mp->b_rptr;
	N_conn_req_t *p = (N_conn_req_t *) mp->b_rptr;
	ensure(mlen >= sizeof(*p), return (-EFAULT));
	fixme(("Do something here...\n"));
	return (-EFAULT);
}

/*
 *  N_INFO_ACK
 *  ---------------------------------------------
 */
static int n_info_ack(sl_t * sl, mblk_t * mp)
{
	size_t mlen = mp->b_wptr - mp->b_rptr;
	N_info_ack_t *p = (N_info_ack_t *) mp->b_rptr;
	ensure(mlen >= sizeof(*p), return (-EFAULT));
	fixme(("Do something here...\n"));
	return (-EFAULT);
}

/*
 *  N_BIND_ACK
 *  ---------------------------------------------
 */
static int n_bind_ack(sl_t * sl, mblk_t * mp)
{
	size_t mlen = mp->b_wptr - mp->b_rptr;
	N_bind_ack_t *p = (N_bind_ack_t *) mp->b_rptr;
	ensure(mlen >= sizeof(*p), return (-EFAULT));
	fixme(("Do something here...\n"));
	return (-EFAULT);
}

/*
 *  N_OK_ACK
 *  ---------------------------------------------
 */
static int n_ok_ack(sl_t * sl, mblk_t * mp)
{
	size_t mlen = mp->b_wptr - mp->b_rptr;
	N_ok_ack_t *p = (N_ok_ack_t *) mp->b_rptr;
	ensure(mlen >= sizeof(*p), return (-EFAULT));
	fixme(("Do something here...\n"));
	return (-EFAULT);
}

/*
 *  N_ERROR_ACK
 *  ---------------------------------------------
 */
static int n_error_ack(sl_t * sl, mblk_t * mp)
{
	size_t mlen = mp->b_wptr - mp->b_rptr;
	N_error_ack_t *p = (N_error_ack_t *) mp->b_rptr;
	ensure(mlen >= sizeof(*p), return (-EFAULT));
	fixme(("Do something here...\n"));
	return (-EFAULT);
}

/*
 *  N_RESET_CON
 *  ---------------------------------------------
 */
static int n_reset_con(sl_t * sl, mblk_t * mp)
{
	size_t mlen = mp->b_wptr - mp->b_rptr;
	N_other_ind_t *p = (N_other_ind_t *) mp->b_rptr;
	ensure(mlen >= sizeof(*p), return (-EFAULT));
	fixme(("Do something here...\n"));
	return (-EFAULT);
}

/*
 *  =========================================================================
 *
 *  STREAMS Message Handling
 *
 *  =========================================================================
 */
/*
 *  -------------------------------------------------------------------------
 *
 *  M_IOCDATA Handling
 *
 *  -------------------------------------------------------------------------
 */
static sl_w_iocdata(queue_t * q, mblk_t * mp)
{
	(void) q;
	(void) mp;
	return (4);
}

/*
 *  -------------------------------------------------------------------------
 *
 *  M_IOCTL Handling
 *
 *  -------------------------------------------------------------------------
 */
static int sl_w_ioctl(queue_t * q, mblk_t * mp)
{
	sl_t *sl = (sl_t *) q->q_ptr;
	struct iocblk *iocp = (struct iocblk *) mp->b_rptr;
	switch (_IOC_TYPE(iocp->ioc_cmd)) {
	default:
		return (4);
	case __SID:
	case SL_IOC_MAGIC:
	case SDT_IOC_MAGIC:
	case SDL_IOC_MAGIC:
	case DEV_IOC_MAGIC:
		break;
	}
	mp->b_datap->db_type = M_IOCNAK;
	iocp->ioc_error = EOPNOTSUPP;
	iocp->ioc_rval = -1;
	qreply(q, mp);
	return (1);
}

/*
 *  -------------------------------------------------------------------------
 *
 *  M_PROTO, M_PCPROTO Handling
 *
 *  -------------------------------------------------------------------------
 */
static int sl_w_proto(queue_t * q, mblk_t * mp)
{
	int rtn;
	sl_t *sl = (sl_t *) q->q_ptr;
	ulong oldstate = sl->i_state;
	switch (*((ulong *) mp->b_rptr)) {
	case LMI_INFO_REQ:
		rtn = lmi_info_req(sl, mp);
		break;
	case LMI_ATTACH_REQ:
		rtn = lmi_attach_req(sl, mp);
		break;
	case LMI_DETACH_REQ:
		rtn = lmi_detach_req(sl, mp);
		break;
	case LMI_ENABLE_REQ:
		rtn = lmi_enable_req(sl, mp);
		break;
	case LMI_DISABLE_REQ:
		rtn = lmi_disable_req(sl, mp);
		break;
	case LMI_OPTMGMT_REQ:
		rtn = lmi_optmgmt_req(sl, mp);
		break;
	case SL_PDU_REQ:
		rtn = sl_pdu_req(sl, mp);
		break;
	case SL_EMERGENCY_REQ:
		rtn = sl_emergency_req(sl, mp);
		break;
	case SL_EMERGENCY_CEASES_REQ:
		rtn = sl_emergency_ceases_req(sl, mp);
		break;
	case SL_START_REQ:
		rtn = sl_start_req(sl, mp);
		break;
	case SL_STOP_REQ:
		rtn = sl_stop_req(sl, mp);
		break;
	case SL_RETRIEVE_BSNT_REQ:
		rtn = sl_retrieve_bsnt_req(sl, mp);
		break;
	case SL_RETRIEVAL_REQUEST_AND_FSNC_REQ:
		rtn = sl_retrieval_request_and_fsnc_req(sl, mp);
		break;
	case SL_RESUME_REQ:
		rtn = sl_resume_req(sl, mp);
		break;
	case SL_CLEAR_BUFFERS_REQ:
		rtn = sl_clear_buffers_req(sl, mp);
		break;
	case SL_CLEAR_RTB_REQ:
		rtn = sl_clear_rtb_req(sl, mp);
		break;
	case SL_LOCAL_PROCESSOR_OUTAGE_REQ:
		rtn = sl_local_processor_outage_req(sl, mp);
		break;
	case SL_CONGESTION_DISCARD_REQ:
		rtn = sl_congestion_discard_req(sl, mp);
		break;
	case SL_CONGESTION_ACCEPT_REQ:
		rtn = sl_congestion_accept_req(sl, mp);
		break;
	case SL_NO_CONGESTION_REQ:
		rtn = sl_no_congestion_req(sl, mp);
		break;
	case SL_POWER_ON_REQ:
		rtn = sl_power_on_req(sl, mp);
		break;
	default:
		rtn = -EOPNOTSUPP;
		break;
	}
	if (rtn < 0) {
		seldom();
		sl->i_state = oldstate;
	}
	return (rtn);
}
static int sl_r_proto(queue_t * q, mblk_t * mp)
{
	int rtn;
	sl_t *sl = (sl_t *) q->q_ptr;
	switch (*((ulong *) mp->b_rptr)) {
	case N_DATA_IND:
		rtn = n_data_ind(sl, mp);
		break;
	case N_EXDATA_IND:
		rtn = n_exdata_ind(sl, mp);
		break;
	case N_DATACK_IND:
		rtn = n_datack_ind(sl, mp);
		break;
	case N_DISCON_IND:
		rtn = n_discon_ind(sl, mp);
		break;
	case N_RESET_IND:
		rtn = n_reset_ind(sl, mp);
		break;
	case N_CONN_IND:
		rtn = n_conn_ind(sl, mp);
		break;
	case N_CONN_RES:
		rtn = n_conn_req(sl, mp);
		break;
	case N_INFO_ACK:
		rtn = n_info_ack(sl, mp);
		break;
	case N_BIND_ACK:
		rtn = n_bind_ack(sl, mp);
		break;
	case N_OK_ACK:
		rtn = n_ok_ack(sl, mp);
		break;
	case N_ERROR_ACK:
		rtn = n_error_ack(sl, mp);
		break;
	case N_RESET_CON:
		rtn = n_reset_con(sl, mp);
		break;
	default:
		rtn = -EOPNOTSUPP;
		break;
	}
	if (rtn < 0) {
		seldom();
	}
	return (rtn);
}

/*
 *  -------------------------------------------------------------------------
 *
 *  M_DATA Handling
 *
 *  -------------------------------------------------------------------------
 */
static int sl_w_data(queue_t * q, mblk_t * mp)
{
	sl_t *sl = (sl_t *) q->q_ptr;
	return m2ua_send_msg(sl, mp);
}
static int sl_r_data(queue_t * q, mblk_t * mp)
{
	sl_t *sl = (sl_t *) q->q_ptr;
	return m2ua_recv_msg(sl, mp);
}

/*
 *  -------------------------------------------------------------------------
 *
 *  M_CTL Handling (Events)
 *
 *  -------------------------------------------------------------------------
 */
static int sl_r_ctl(queue_t * q, mblk_t * mp)
{
	(void) q;
	(void) mp;
	return (4);
}

/*
 *  -------------------------------------------------------------------------
 *
 *  M_ERROR Handling
 *
 *  -------------------------------------------------------------------------
 */
static int sl_r_error(queue_t * q, mblk_t * mp)
{
	(void) q;
	(void) mp;
	return (4);
}

/*
 *  -------------------------------------------------------------------------
 *
 *  M_HANGUP Handling
 *
 *  -------------------------------------------------------------------------
 */
static int sl_r_hangup(queue_t * q, mblk_t * mp)
{
	(void) q;
	(void) mp;
	return (0);
}

/*
 *  -------------------------------------------------------------------------
 *
 *  M_FLUSH Handling
 *
 *  -------------------------------------------------------------------------
 */
static int sl_w_flush(queue_t * q, mblk_t * mp)
{
	(void) q;
	(void) mp;
	return (3);
}
static int sl_r_flush(queue_t * q, mblk_t * mp)
{
	(void) q;
	(void) mp;
	return (3);
}

/*
 *  -------------------------------------------------------------------------
 *
 *  Other messages (e.g. M_IOCACK)
 *
 *  -------------------------------------------------------------------------
 */
static int sl_w_other(queue_t * q, mblk_t * mp)
{
	(void) q;
	(void) mp;
	return (4);
}
static int sl_r_other(queue_t * q, mblk_t * mp)
{
	(void) q;
	(void) mp;
	return (4);
}

/*
 *  =========================================================================
 *
 *  PUT and SRV
 *
 *  =========================================================================
 */
static INT sl_wput(queue_t * q, mblk_t * mp)
{
	int rtn;
	sl_t *sl = (sl_t *) q->q_ptr;
	ensure(q, return ((INT) (-EFAULT)));
	ensure(sl, return ((INT) (-EFAULT)));
	ensure(mp, return ((INT) (-EFAULT)));
	switch (mp->b_datap->db_type) {
	case M_DATA:
		rtn = sl_w_data(q, mp);
		break;
	case M_PROTO:
	case M_PCPROTO:
		rtn = sl_w_proto(q, mp);
		break;
	case M_FLUSH:
		rtn = sl_w_flush(q, mp);
		break;
	case M_IOCTL:
		rtn = sl_w_ioctl(q, mp);
		break;
	case M_IOCDATA:
		rtn = sl_w_iocdata(q, mp);
		break;
	default:
		rtn = sl_w_other(q, mp);
		break;
	}
	switch (rtn) {
	case 0:
		freemsg(mp);
	case 1:
		break;
	case 2:
		freeb(mp);
		break;
	case 3:
	case 4:
		putnext(q, mp);
		break;
	default:
		ptrace(("Error = %d\n", rtn));
		freemsg(mp);
		return (INT) (rtn);
	}
	return (INT) (0);
}

static INT sl_rput(queue_t * q, mblk_t * mp)
{
	int rtn = 0;
	sl_t *sl = (sl_t *) q->q_ptr;
	ensure(q, return ((INT) (-EFAULT)));
	ensure(sl, return ((INT) (-EFAULT)));
	ensure(mp, return ((INT) (-EFAULT)));
	switch (mp->b_datap->db_type) {
	case M_DATA:
		rtn = sl_r_data(q, mp);
		break;
	case M_PROTO:
	case M_PCPROTO:
		rtn = sl_r_proto(q, mp);
		break;
	case M_CTL:
		rtn = sl_r_ctl(q, mp);
		break;
	case M_ERROR:
		rtn = sl_r_error(q, mp);
		break;
	case M_FLUSH:
		rtn = sl_r_flush(q, mp);
		break;
	case M_HANGUP:
		rtn = sl_r_hangup(q, mp);
		break;
	default:
		rtn = sl_r_other(q, mp);
		break;
	}
	switch (rtn) {
	case 0:
		freemsg(mp);
	case 1:
		break;
	case 2:
		freeb(mp);
		break;
	case 3:
	case 4:
		putnext(q, mp);
		break;
	default:
		ptrace(("Error = %d\n", rtn));
		freemsg(mp);
		return (INT) (rtn);
	}
	return (INT) (0);
}

/*
 *  =========================================================================
 *
 *  Private Structure allocation, deallocation and cache
 *
 *  =========================================================================
 */
kmem_cache_t *sl_cachep = NULL;

static void sl_init_caches(void)
{
	if (!sl_cachep &&
	    !(sl_cachep =
	      kmem_cache_create("sl_cachep", sizeof(sl_t), 0, SLAB_HWCACHE_ALIGN, NULL, NULL)))
		panic("%s:Cannot alloc sl_cachep.\n", __FUNCTION__);
	return;
}
static void sl_term_caches(void)
{
	if (sl_cachep)
		if (kmem_cache_destroy(sl_cachep))
			cmn_err(CE_PANIC, "m2ua: couldn't destroy sl_cachep\n");
	return;
}

static sl_t *sl_alloc_priv(queue_t * q)
{
	sl_t *sl;

	if ((sl = kmem_cache_alloc(sl_cachep, SLAB_ATOMIC))) {
		bzero(sl, sizeof(*sl));
		RD(q)->q_ptr = WR(q)->q_ptr = sl;
		sl->rq = RD(q);
		sl->wq = WR(q);
		sl->i_state = LMI_DISABLED;
	}
	return (sl);
}
static void sl_free_priv(queue_t * q)
{
	sl_t *sl = (sl_t *) q->q_ptr;
	kmem_cache_free(sl_cachep, sl);
	return;
}

/*
 *  =========================================================================
 *
 *  OPEN and CLOSE
 *
 *  =========================================================================
 */
static int sl_open(queue_t * q, dev_t * devp, int flag, int sflag, cred_t * crp)
{
	(void) crp;		/* for now */
	if (q->q_ptr != NULL)	/* already open */
		return (0);
	if (sflag == MODOPEN || WR(q)->q_next != NULL) {
		fixme(("Check module we are being pushed over.\n"));
		if (!(sl_alloc_priv(q)))
			return ENOMEM;
		return (0);
	}
	return EIO;
}
static int sl_close(queue_t * q, int flag, cred_t * crp)
{
	(void) flag;
	(void) crp;

	sl_free_priv(q);
	return (0);
}

/*
 *  =========================================================================
 *
 *  Lis Module Initialization
 *
 *  =========================================================================
 */
void sl_init(void)
{
	int modnum;
	unless(sl_minfo.mi_idnum, return);
	cmn_err(CE_NOTE, M2UA_BANNER);	/* console splash */
	sl_init_caches();
	if (!(modnum = lis_register_strmod(&sl_info, sl_minfo.mi_idname))) {
		sl_minfo.mi_idnum = 0;
		rare();
		cmn_err(CE_NOTE, "m2ua: couldn't register as module\n");
		return;
	}
	sl_minfo.mi_idnum = modnum;
	return;
}
void sl_terminate(void)
{
	ensure(sl_minfo.mi_idnum, return);
	if ((sl_minfo.mi_idnum = lis_unregister_strmod(&sl_info)))
		cmn_err(CE_WARN, "m2ua: couldn't unregister as module!\n");
	sl_term_caches();
	return;
}

/*
 *  =========================================================================
 *
 *  Kernel Module Initialization
 *
 *  =========================================================================
 */
int init_module(void)
{
	sl_init();
	return (0);
}
void cleanup_module(void)
{
	sl_terminate();
	return;
}


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

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

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