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/sigtran/sua.c


File /code/strss7/drivers/sigtran/sua.c



#ident "@(#) $RCSfile: sua.c,v $ $Name:  $($Revision: 0.8.2.3 $) $Date: 2003/04/03 19:51:07 $"

static char const ident[] =
    "$RCSfile: sua.c,v $ $Name:  $($Revision: 0.8.2.3 $) $Date: 2003/04/03 19:51:07 $";

#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 "../debug.h"
#include "../bufq.h"

#include "ua.h"
#include "ua_data.h"
#include "ua_msgs.h"
#include "sua_msgs.h"

/*
 *  =========================================================================
 *
 *  STREAMS Message Handling
 *
 *  =========================================================================
 */
/*
 *  -------------------------------------------------------------------------
 *
 *  Management Stream (LM) Message Handling
 *
 *  -------------------------------------------------------------------------
 */
/*
 *  LM --> SUA Primitives
 *  -----------------------------------
 */
int lm_as_add_req(queue_t * q, mblk_t * mp)
{
}

int lm_as_del_req(queue_t * q, mblk_t * mp)
{
}
int lm_proc_add_req(queue_t * q, mblk_t * mp)
{
}
int lm_proc_del_req(queue_t * q, mblk_t * mp)
{
}
int lm_link_add_req(queue_t * q, mblk_t * mp)
{
}
int lm_link_del_req(queue_t * q, mblk_t * mp)
{
}
int lm_route_add_req(queue_t * q, mblk_t * mp)
{
}
int lm_route_del_req(queue_t * q, mblk_t * mp)
{
}
int lm_reg_res(queue_t * q, mblk_t * mp)
{
}
int lm_reg_ref(queue_t * q, mblk_t * mp)
{
}
static int sua_m_w_ioctl(queue_t * q, mblk_t * mp)
{
}
static int sua_m_w_proto(queue_t * q, mblk_t * mp)
{
	switch (*((long *) mp->b_rptr)) {
	case LM_AS_ADD_REQ:
		return lm_as_add_req(q, mp);
	case LM_AS_DEL_REQ:
		return lm_as_del_req(q, mp);
	case LM_PROC_ADD_REQ:
		return lm_proc_add_req(q, mp);
	case LM_PROC_DEL_REQ:
		return lm_proc_del_req(q, mp);
	case LM_LINK_ADD_REQ:
		return lm_link_add_req(q, mp);
	case LM_LINK_DEL_REQ:
		return lm_link_del_req(q, mp);
	case LM_ROUTE_ADD_REQ:
		return lm_route_add_req(q, mp);
	case LM_ROUTE_DEL_REQ:
		return lm_route - del_req(q, mp);
	case LM_REG_RES:
		return lm_reg_res(q, mp);
	case LM_REG_REF:
		return lm_reg_ref(q, mp);
	}
	return (-EOPNOTSUPP);
}
static int sua_m_w_pcproto(queue_t * q, mblk_t * mp)
{
	return sua_m_w_proto(q, mp);
}
static int sua_m_w_prim(queue_t * q, mblk_t * mp)
{
	switch (mp->b_datap->db_type) {
	case M_PROTO:
		return sua_m_w_proto(q, mp);
	case M_PCPROTO:
		return sua_m_w_pcproto(q, mp);
	case M_IOCTL:
		return sua_m_w_ioctl(q, mp);
	case M_FLUSH:
		return ua_w_flush(q, mp);
	}
	return (-EOPNOTSUPP);
}

/*
 *  SUA --> LM Primitives
 *  -----------------------------------
 */
static int sua_m_r_prim(queue_t * q, mblk_t * mp)
{
	switch (mp->b_datap->db_type) {
	case M_FLUSH:
		return ua_r_flush(q, mp);
	}
	return (5);
}

/*
 *  =========================================================================
 *
 *  STREAMS Message Handling
 *
 *  -------------------------------------------------------------------------
 *
 *  SCCP User (SCCPU) Stream Message Handling
 *
 *  -------------------------------------------------------------------------
 *
 *  SCCP User --> SUA Primitives
 *  -----------------------------------
 *  This is the SCCPU upper write routines.  This takes SCCP user primitives
 *  and converts them to SCCP M_DATA and M_CTL messages, if required.  If the
 *  provider is a local SG, then the primitives are forwarded as is.
 *
 *  These are primitives sent from a local SCCP user to the SUA layer on the
 *  upper mux stream.  This is part of the Adaptation Layer at an ASP
 *  (Application Server Process).  Each message is converted from an SCCP user
 *  request or response primitive to an SUA message.  These functions are pure
 *  translation only.  When they return zero, they return the SCCP primitive
 *  translated in `mpp'.  When they return non-zero, they return an error an
 *  `mpp' is untouched.
 */
static int sccpu_info_req(queue_t * q, mblk_t * mp)
{
}
static int sccpu_bind_req(queue_t * q, mblk_t * mp)
{
}
static int sccpu_unbind_req(queue_t * q, mblk_t * mp)
{
}
static int sccpu_unitdata_req(queue_t * q, mblk_t * mp)
{
}
static int sccpu_optmgmt_req(queue_t * q, mblk_t * mp)
{
}
static int sua_u_w_ioctl(queue_t * q, mblk_t * mp)
{
}
static int sua_u_w_data(queue_t * q, mblk_t * dp)
{
	/* 
	 *  Need to convert data to SL_PDU_REQ.
	 */
	int rtn;
	mblk_t *mp;
	sl_pdu_req_t *p;
	if ((mp = allocb(sizeof(*p), BPRI_MED))) {
		mp->b_datap->db_type = M_PROTO;
		p = ((typeof(p)) mp->b_wptr)++;
		p->sl_primitive = SL_PDU_REQ;
		mp->b_cont = dp;
		switch ((rtn = slu_pdu_req(q, mp))) {
		}
		return (1);
	}
	return (-ENOBUFS);
}
static int sua_u_w_proto(queue_t * q, mblk_t * mp)
{
	switch (*((long *) mp->b - rptr)) {
	case N_INFO_REQ:
		return sccpu_info_req(q, mp);
	case N_BIND_REQ:
		return sccpu_bind_req(q, mp);
	case N_UNBIND_REQ:
		return sccpu_unbind_req(q, mp);
	case N_UNITDATA_REQ:
		return sccpu_unitdata_req(q, mp);
	case N_OPTMGMT_REQ:
		return sccpu_optmgmt_req(q, mp);
	}
	return (-EOPNOTSUPP);
}
static int sua_u_w_pcproto(queue_t * q, mblk_t * mp)
{
	return sua_u_w_proto(q, mp);
}
static int sua_u_w_prim(queue_t * q, mblk_t * mp)
{
	switch (mp->b_datap->db_type) {
	case M_DATA:
		return sua_u_w_data(q, mp);
	case M_PROTO:
		return sua_u_w_proto(q, mp);
	case M_PCPROTO:
		return sua_u_w_pcproto(q, mp);
	case M_IOCTL:
		return sua_u_w_ioctl(q, mp);
	case M_FLUSH:
		return ua_w_flush(q, mp);
	}
	return (-EOPNOTSUPP);
}

/*
 *  SUA --> SCCP User Primitives
 *  -----------------------------------
 */
static int sua_u_r_data(queue_t * q, mblk_t * mp)
{
	return sua_r_msg(q, mp);
}
static int sua_u_r_ctl(queue_t * q, mblk_t * mp)
{
	return sua_r_msg(q, mp);
}
static int sua_u_r_prim(queue_t * q, mblk_t * mp)
{
	switch (mp->b_datap->db_type) {
	case M_DATA:
		return sua_u_r_data(q, mp);
	case M_CTL:
		return sua_u_r_ctl(q, mp);
	case M_FLUSH:
		return ua_r_flush(q, mp);
	}
	return (5);
}

/*
 *  -------------------------------------------------------------------------
 *
 *  SCCP Provider (SCCPP) Stream Message Handling
 *
 *  -------------------------------------------------------------------------
 */
/*
 *  SUA --> SCCP Provider Primitives
 *  -----------------------------------
 */
static int sua_l_w_data(queue_t * q, mblk_t * mp)
{
	return sua_w_msg(q, mp);
}
static int sua_l_w_ctl(queue_t * q, mblk_t * mp)
{
	return sua_w_msg(q, mp);
}
static int sua_l_w_error(queue_t * q, mblk_t * mp)
{
}
static int sua_l_w_hangup(queue_t * q, mblk_t * mp)
{
}
static int sua_l_w_prim(queue_t * q, mblk_t * mp)
{
	switch (mp->b_datap->db_type) {
	case M_DATA:
		return sua_l_w_data(q, mp);
	case M_CTL:
		return sua_l_w_ctl(q, mp);
	case M_ERROR:
		return sua_l_w_error(q, mp);
	case M_HANGUP:
		return sua_l_w_hangup(q, mp);
	case M_FLUSH:
		return ua_w_flush(q, mp);
	}
	return (5);
}

/*
 *  SCCP Provider --> SUA Primitives
 *  -------------------------------------------------------------------------
 *  This is the SCCPP lower read routine.  This takes SCCP Primitives and
 *  converts them to SUA M_DATA and M_CTL messages, if required.  If the user
 *  is a local AS, then the primitives are forwarded as is.
 */
static int sccpp_info_ack(queue_t * q, mblk_t * mp)
{
	ptrace(("Aarrgh! Got unexpected N_INFO_ACK\n"));
	return (-EFAULT);
}
static int sccpp_bind_ack(queue_t * q, mblk_t * mp)
{
	lp_t *lp = (lp_t *) q->q_ptr;
	as_t *as = lp->as;
	if (lp->l.state != NS_WACK_BREQ) {
		ptrace(("Aarrgh! Got unexpected N_BIND_ACK\n"));
		return (-EFAULT);
	}
	ensure(as, return (-EFAULT));
	as->xpia_count--;
	as->xpac_count++;
	as->l.state = AS_ACTIVE;
	fixme(("Do some more...\n"));
	return (-EFAULT);
}
static int sccpp_error_ack(as_t * as, mblk_t ** mpp)
{
	mblk_t *mp;
	N_error_ack_t *p = (typeof(p)) (*mpp)->b_rptr;
	switch (p->ERROR_primitive) {
	case N_CONN_REQ:
	{
		size_t mlen = *sizeof(uint32_t);
		if ((mp = allocb(mlen, BPRI_MED))) {
			mp->b_datap->db_type = M_DATA;
			*((uint32_t *) mp->b_wptr)++ = SUA_CONS_COREF;
			*((uint32_t *) mp->b_wptr)++ = htonl(mlen);
			*((uint32_t *) mp->b_wptr)++ = UA_PARM_RC;
			*((uint32_t *) mp->b_wptr)++ = htonl(as->l.id.rc);
			*((uint32_t *) mp->b_wptr)++ = SUA_PARM_DRN;
			*((uint32_t *) mp->b_wptr)++ = htonl(as->drn);
			fixme(("Get cause from ERROR_code\n"));
			*((uint32_t *) mp->b_wptr)++ = SUA_PARM_CAUSE;
			*((uint32_t *) mp->b_wptr)++ = htonl(cause);
			(*mpp) = mp;
			return (0);
		}
		return ua_bufcall(as->ss7->rq, mlen);
	}
	}
	return (-EPROTO);
}
static int sccpp_ok_ack(as_t * as, mblk_t ** mpp)
{
	mblk_t *mp;
	N_ok_ack_t *p = (typeof(p)) (*mpp)->b_rptr;
	switch (p->CORRECT_primitive) {
	case N_DISCON_REQ:
	{
		size_t mlen = 8 * sizeof(uint32_t);
		if ((mp = allocb(mlen, BPRI_MED))) {
			mp->b_datap->db_type = M_DATA;
			*((uint32_t *) mp->b_wptr)++ = SUA_CONS_RELCO;
			*((uint32_t *) mp->b_wptr)++ = htonl(mlen);
			*((uint32_t *) mp->b_wptr)++ = UA_PARM_RC;
			*((uint32_t *) mp->b_wptr)++ = htonl(as->l.id.rc);
			*((uint32_t *) mp->b_wptr)++ = SUA_PARM_DRN;
			*((uint32_t *) mp->b_wptr)++ = htonl(as->drn);
			*((uint32_t *) mp->b_wptr)++ = SUA_PARM_SRN;
			*((uint32_t *) mp->b_wptr)++ = htonl(as->srn);
			/* Note: se never send importance here */
			(*mpp) = mp;
			return (0);
		}
		return ua_bufcall(as->ss7->rq, mlen);
	}
	}
	return (-EPROTO);
}
static int sccpp_conn_ind(as_t * as, mblk_t ** mpp)
{
	mblk_t *mp;
	N_conn_ind_t *p = (typeof(p)) (*mpp)->b_rptr;
	sccp_addr_t *src = (typeof(src)) ((*mpp)->b_rptr + p->SRC_offset);
	sccp_addr_t *dst = (typeof(src)) ((*mpp)->b_rptr + p->DEST_offset);
	N_qos_sel_conn_sctp_t *qos = (typeof(qos)) ((*mpp)->b_rptr + p->QOS_offset);
	uint pclass = qos->protocol_class;
	size_t mlen = *sizeof(uint32_t);
	size_t dlen = msgdsize((*mpp)->b_cont);
	if ((mp = allocb(mlen, BPRI_MED))) {
		mp->b_datap->db_type = M_DATA;
		*((uint32_t *) mp->b_wptr)++ = SUA_CONS_CORE;
		*((uint32_t *) mp->b_wptr)++ = htonl(mlen + PAD4(dlen));
		*((uint32_t *) mp->b_wptr)++ = UA_PARM_RC;
		*((uint32_t *) mp->b_wptr)++ = htonl(as->l.id.rc);
		*((uint32_t *) mp->b_wptr)++ = SUA_PARM_PCLS;
		*((uint32_t *) mp->b_wptr)++ = htonl(qos->protocol_class);
		*((uint32_t *) mp->b_wptr)++ = SUA_PARM_SRN;
		*((uint32_t *) mp->b_wptr)++ = htoml(srn);
		*((uint32_t *) mp->b_wptr)++ = SUA_PARM_SEQ_CTL;
		*((uint32_t *) mp->b_wptr)++ = htonl(qos->sequence_control);
		*((uint32_t *) mp->b_wptr)++ = SUA_PARM_HOP_CNT;
		*((uint32_t *) mp->b_wptr)++ =;
		*((uint32_t *) mp->b_wptr)++ = SUA_PARM_IMP;
		*((uint32_t *) mp->b_wptr)++ = htonl(qos->importance);
		*((uint32_t *) mp->b_wptr)++ = SUA_PARM_MP;
		*((uint32_t *) mp->b_wptr)++ = htonl(qos->message_priority);
		if (p->DEST_length >= sizeof(*dst)) {
			fixme(("Place Dest address in message\n"));
			*((uint32_t *) mp->b_wptr)++ = UA_PARM(SUA_PARM_DEST_ADDR, dlen);
		}
		if (p->SRC_length >= sizeof(*src)) {
			fixme(("Place Srce address in message\n"));
			*((uint32_t *) mp->b_wptr)++ = UA_PARM(SUA_PARM_SRCE_ADDR, slen);
			/* 
			 *  There are strange statements in the draft as to
			 *  when to place SRC address in the message.
			 */
		}
		if (pclass == 3) {
			*((uint32_t *) mp->b_wptr)++ = SUA_PARM_SEQ_NUM;
			*((uint32_t *) mp->b_wptr)++ =;
			*((uint32_t *) mp->b_wptr)++ = SUA_PARM_CREDIT;
			*((uint32_t *) mp->b_wptr)++ =;
		}
		if (dlen) {
			*((uint32_t *) mp->b_wptr)++ = UA_PARM(SUA_PARM_DATA, dlen);
			mp->b_cont = (*mpp)->b_cont;
			(*mpp)->b_cont = NULL;
		}
		(*mpp) = mp;
		return (0);
	}
	return ua_bufcall(as->ss7->rq, mlen);
}
static int sccpp_conn_con(as_t * as, mblk_t ** mpp)
{
	mblk_t *mp;
	N_conn_con_t *p = (typeof(p)) (*mpp)->b_rptr;
	sccp_addr_t *res = (typeof(src)) ((*mpp)->b_rptr + p->RES_offset);
	N_qos_sel_conn_sctp_t *qos = (typeof(qos)) ((*mpp)->b_rptr + p->QOS_offset);
	uint pclass = qos->protocol_class;
	size_t mlen = *sizeof(uint32_t);
	size_t dlen = msgdsize((*mpp)->b_cont);
	if ((mp = allocb(mlen, BPRI_MED))) {
		mp->b_datap->db_type = M_DATA;
		*((uint32_t *) mp->b_wptr)++ = SUA_CONS_COAK;
		*((uint32_t *) mp->b_wptr)++ = htonl(mlen + PAD4(dlen));
		*((uint32_t *) mp->b_wptr)++ = UA_PARM_RC;
		*((uint32_t *) mp->b_wptr)++ = htonl(as->l.id.rc);
		*((uint32_t *) mp->b_wptr)++ = SUA_PARM_PCLS;
		*((uint32_t *) mp->b_wptr)++ = htonl(qos->protocol_class);
		*((uint32_t *) mp->b_wptr)++ = SUA_PARM_DRN;
		*((uint32_t *) mp->b_wptr)++ = htoml(drn);
		*((uint32_t *) mp->b_wptr)++ = SUA_PARM_SRN;
		*((uint32_t *) mp->b_wptr)++ = htoml(srn);
		*((uint32_t *) mp->b_wptr)++ = SUA_PARM_SEQ_CTL;
		*((uint32_t *) mp->b_wptr)++ = htonl(qos->sequence_control);
		*((uint32_t *) mp->b_wptr)++ = SUA_PARM_IMP;
		*((uint32_t *) mp->b_wptr)++ = htonl(qos->importance);
		*((uint32_t *) mp->b_wptr)++ = SUA_PARM_MP;
		*((uint32_t *) mp->b_wptr)++ = htonl(qos->message_priority);
		if (p->RES_length >= sizeof(*res)) {
			fixme(("Place Dest address in message\n"));
			*((uint32_t *) mp->b_wptr)++ = UA_PARM(SUA_PARM_DEST_ADDR, dlen);
			/* 
			 *  There are strange statements in the draft as to
			 *  when to place Dest address in the message.
			 */
		}
		if (pclass == 3) {
			*((uint32_t *) mp->b_wptr)++ = SUA_PARM_CREDIT;
			*((uint32_t *) mp->b_wptr)++ =;
		}
		if (dlen) {
			*((uint32_t *) mp->b_wptr)++ = UA_PARM(SUA_PARM_DATA, dlen);
			mp->b_cont = (*mpp)->b_cont;
			(*mpp)->b_cont = NULL;
		}
		(*mpp) = mp;
		return (0);
	}
	return ua_bufcall(as->ss7->rq, mlen);
}
static int sccpp_discon_ind(as_t * as, mblk_t ** mpp)
{
	switch (as->ss7->l.state) {
	case NS_WCON_CREQ:
	{
		mblk_t *mp;
		N_discon_ind_t *p = (typeof(p)) (*mpp)->b_rptr;
		sccp_addr_t *res = (typeof(src)) ((*mpp)->b_rptr + p->RES_offset);
		size_t mlen = *sizeof(uint32_t);
		size_t dlen = msgdsize((*mpp)->b_cont);
		if ((mp = allocb(mlen, BPRI_MED))) {
			mp->b_datap->db_type = M_DATA;
			*((uint32_t *) mp->b_wptr)++ = SUA_CONS_COREF;
			*((uint32_t *) mp->b_wptr)++ = htonl(mlen);
			*((uint32_t *) mp->b_wptr)++ = UA_PARM_RC;
			*((uint32_t *) mp->b_wptr)++ = htonl(as->l.id.rc);
			*((uint32_t *) mp->b_wptr)++ = SUA_PARM_DRN;
			*((uint32_t *) mp->b_wptr)++ = htonl(drn);
			*((uint32_t *) mp->b_wptr)++ = SUA_PARM_IMP;
			*((uint32_t *) mp->b_wptr)++ = htonl(qos->importance);
			*((uint32_t *) mp->b_wptr)++ = SUA_PARM_CAUSE;
			fixme(("Get cause from DISCON_orig and DISCON_reason\n"));
			*((uint32_t *) mp->b_wptr)++ = htonl(cause);
			if (p->RES_length >= sizeof(*res)) {
				fixme(("Place Dest address in message\n"));
				*((uint32_t *) mp->b_wptr)++ = UA_PARM(SUA_PARM_DEST_ADDR, dlen);
				/* 
				 *  There are strange statements in the draft as to
				 *  when to place Dest address in the message.
				 */
			}
			if (dlen) {
				*((uint32_t *) mp->b_wptr)++ = UA_PARM(SUA_PARM_DATA, dlen);
				mp->b_cont = (*mpp)->b_cont;
				(*mpp)->b_cont = NULL;
			}
			(*mpp) = mp;
			return (0);
		}
		return ua_bufcall(as->ss7->rq, mlen);
	}
	case NS_DATA_XFER:
	{
		mblk_t *mp;
		N_discon_ind_t *p = (typeof(p)) (*mpp)->b_rptr;
		size_t mlen = *sizeof(uint32_t);
		if ((mp = allocb(mlen, BPRI_MED))) {
			mp->b_datap->db_type = M_DATA;
			*((uint32_t *) mp->b_wptr)++ = SUA_CONS_RELRE;
			*((uint32_t *) mp->b_wptr)++ = htonl(mlen);
			*((uint32_t *) mp->b_wptr)++ = UA_PARM_RC;
			*((uint32_t *) mp->b_wptr)++ = htonl(as->l.id.rc);
			*((uint32_t *) mp->b_wptr)++ = SUA_PARM_DRN;
			*((uint32_t *) mp->b_wptr)++ = htoml(drn);
			*((uint32_t *) mp->b_wptr)++ = SUA_PARM_SRN;
			*((uint32_t *) mp->b_wptr)++ = htoml(srn);
			*((uint32_t *) mp->b_wptr)++ = SUA_PARM_IMP;
			*((uint32_t *) mp->b_wptr)++ = htonl(qos->importance);
			*((uint32_t *) mp->b_wptr)++ = SUA_PARM_CAUSE;
			fixme(("Get cause from DISCON_orig and DISCON_reason\n"));
			*((uint32_t *) mp->b_wptr)++ = htonl(cause);
			if (dlen) {
				*((uint32_t *) mp->b_wptr)++ = UA_PARM(SUA_PARM_DATA, dlen);
				mp->b_cont = (*mpp)->b_cont;
				(*mpp)->b_cont = NULL;
			}
			(*mpp) = mp;
			return (0);
		}
		return ua_bufcall(as->ss7->rq, mlen);
	}
	}
	ptrace(("Received N_DISCON_IND in unexpected state\n"));
	return (-EFAULT);
}
static int sccpp_data_ind(as_t * as, mblk_t ** mpp)
{
	mblk_t *mp;
	N_data_ind_t *p = (typeof(p)) (*mpp)->b_rptr;
	sccp_addr_t *src = (typeof(src)) ((*mpp)->b_rptr + p->SRC_offset);
	sccp_addr_t *dst = (typeof(src)) ((*mpp)->b_rptr + p->DEST_offset);
	N_qos_sel_data_sctp_t *qos = (typeof(qos)) (dst + 1);
	size_t mlen = *sizeof(uint32_t);
	size_t dlen = msgdsize((*mpp)->b_cont);
	if ((mp = allocb(mlen, BPRI_MED))) {
		mp->b_datap->db_type = M_DATA;
		(*mpp) = mp;
		return (0);
	}
	return ua_bufcall(as->ss7->rq, mlen);
}
static int sccpp_exdata_ind(as_t * as, mblk_t ** mpp)
{
	mblk_t *mp;
	N_exdata_ind_t *p = (typeof(p)) (*mpp)->b_rptr;
	sccp_addr_t *src = (typeof(src)) ((*mpp)->b_rptr + p->SRC_offset);
	sccp_addr_t *dst = (typeof(src)) ((*mpp)->b_rptr + p->DEST_offset);
	N_qos_sel_data_sctp_t *qos = (typeof(qos)) (dst + 1);
	size_t mlen = *sizeof(uint32_t);
	size_t dlen = msgdsize((*mpp)->b_cont);
	if ((mp = allocb(mlen, BPRI_MED))) {
		mp->b_datap->db_type = M_DATA;
		(*mpp) = mp;
		return (0);
	}
	return ua_bufcall(as->ss7->rq, mlen);
}
static int sccpp_unitdata_ind(as_t * as, mblk_t ** mpp)
{
	mblk_t *mp;
	N_unitdata_ind_t *p = (typeof(p)) (*mpp)->b_rptr;
	sccp_addr_t *src = (typeof(src)) ((*mpp)->b_rptr + p->SRC_offset);
	sccp_addr_t *dst = (typeof(src)) ((*mpp)->b_rptr + p->DEST_offset);
	N_qos_sel_data_sctp_t *qos = (typeof(qos)) (dst + 1);
	size_t mlen = *sizeof(uint32_t);
	if ((mp = allocb(mlen, BPRI_MED))) {
		mp->b_datap->db_type = M_DATA;
		(*mpp) = mp;
		return (0);
	}
	return ua_bufcall(as->ss7->rq, mlen);
}
static int sccpp_uderror_ind(as_t * as, mblk_t ** mpp)
{
	mblk_t *mp;
	N_uderror_ind_t *p = (typeof(p)) (*mpp)->b_rptr;
	sccp_addr_t *src = (typeof(src)) ((*mpp)->b_rptr + p->SRC_offset);
	sccp_addr_t *dst = (typeof(src)) ((*mpp)->b_rptr + p->DEST_offset);
	N_qos_sel_data_sctp_t *qos = (typeof(qos)) (dst + 1);
	size_t mlen = *sizeof(uint32_t);
	if ((mp = allocb(mlen, BPRI_MED))) {
		mp->b_datap->db_type = M_DATA;
		(*mpp) = mp;
		return (0);
	}
	return ua_bufcall(as->ss7->rq, mlen);
}
static int sccpp_datack_ind(as_t * as, mblk_t ** mpp)
{
	mblk_t *mp;
	N_datack_ind_t *p = (typeof(p)) (*mpp)->b_rptr;
	size_t mlen = *sizeof(uint32_t);
	if ((mp = allocb(mlen, BPRI_MED))) {
		mp->b_datap->db_type = M_DATA;
		(*mpp) = mp;
		return (0);
	}
	return ua_bufcall(as->ss7->rq, mlen);
}
static int sccpp_reset_ind(as_t * as, mblk_t ** mpp)
{
	mblk_t *mp;
	N_reset_ind_t *p = (typeof(p)) (*mpp)->b_rptr;
	size_t mlen = 10 * sizeof(uint32_t);
	if ((mp = allocb(mlen, BPRI_MED))) {
		mp->b_datap->db_type = M_DATA;
		*((uint32_t *) mp->b_wptr)++ = SUA_CONS_RESRE;
		*((uint32_t *) mp->b_wptr)++ = htonl(mlen);
		*((uint32_t *) mp->b_wptr)++ = UA_PARM_RC;
		*((uint32_t *) mp->b_wptr)++ = htonl(as->l.id.rc);
		*((uint32_t *) mp->b_wptr)++ = SUA_PARM_DRN;
		*((uint32_t *) mp->b_wptr)++ = htonl(as->drn);
		*((uint32_t *) mp->b_wptr)++ = SUA_PARM_SRN;
		*((uint32_t *) mp->b_wptr)++ = htonl(as->srn);
		fixme(("Get cause from RESET_reason\n"));
		*((uint32_t *) mp->b_wptr)++ = SUA_PARM_CAUSE;
		*((uint32_t *) mp->b_wptr)++ = hotnl(cause);
		(*mpp) = mp;
		return (0);
	}
	return ua_bufcall(as->ss7->rq, mlen);
}
static int sccpp_reset_con(as_t * as, mblk_t ** mpp)
{
	mblk_t *mp;
	N_reset_con_t *p = (typeof(p)) (*mpp)->b_rptr;
	size_t mlen = 8 * sizeof(uint32_t);
	if ((mp = allocb(mlen, BPRI_MED))) {
		mp->b_datap->db_type = M_DATA;
		*((uint32_t *) mp->b_wptr)++ = SUA_CONS_RESCO;
		*((uint32_t *) mp->b_wptr)++ = htonl(mlen);
		*((uint32_t *) mp->b_wptr)++ = UA_PARM_RC;
		*((uint32_t *) mp->b_wptr)++ = htonl(as->l.id.rc);
		*((uint32_t *) mp->b_wptr)++ = SUA_PARM_DRN;
		*((uint32_t *) mp->b_wptr)++ = htonl(as->drn);
		*((uint32_t *) mp->b_wptr)++ = SUA_PARM_SRN;
		*((uint32_t *) mp->b_wptr)++ = htonl(as->srn);
		(*mpp) = mp;
		return (0);
	}
	return ua_bufcall(as->ss7->rq, mlen);
}
static int sccpp_xlat(as_t * as, mblk_t ** mpp)
{
	switch (*((long *) (*mpp)->b_rptr)) {
	case N_ERROR_ACK:
		return sccpp_error_ack(as, mpp);
	case N_OK_ACK:
		return sccpp_ok_ack(as, mpp);
	case N_CONN_IND:
		return sccpp_conn_ind(as, mpp);
	case N_CONN_CON:
		return sccpp_conn_con(as, mpp);
	case N_DISCON_IND:
		return sccpp_discon_ind(as, mpp);
	case N_DATA_IND:
		return sccpp_data_ind(as, mpp);
	case N_EXDATA_IND:
		return sccpp_exdata_ind(as, mpp);
	case N_UNITDATA_IND:
		return sccpp_unitdata_ind(as, mpp);
	case N_UDERROR_IND:
		return sccpp_uderror_ind(as, mpp);
	case N_DATACK_IND:
		return sccpp_datack_ind(as, mpp);
	case N_RESET_IND:
		return sccpp_reset_ind(as, mpp);
	case N_RESET_CON:
		return sccpp_reset_con(as, mpp);
	}
	return (-ENOTSUPP);
}
static int sccpp_xlat_prim(queue_t * q, mblk_t * mp)
{
	int err;
	xp_t *xp;
	pp_t *pp;
	as_t *as;
	lp_t *lp = (lp_t *) q->q_ptr;
	ensure(q, return (-EFAULT));
	ensure(lp, return (-EFAULT));
	if (!(as = ua_pp_route(lp)))
		return (0);
	/* 
	 *  If we have a local SCCP User, then just pass the primitive on to
	 *  the local user.
	 */
	if ((pp = ua_as_route_loc(as))) {
		if (mp->b_datap->db_type < QPCTL && !canput(pp->rq))
			return (-EBUSY);
		putq(pp->rq, mp);
		return (1);
	}
	/* 
	 *  If we have a remote SCCP User (i.e, SUA AS), then translate the
	 *  primitive to an SUA message and pass it to the AS.
	 */
	if ((xp = ua_as_route_rem(as))) {
		if (!(pp = xp->pp.pp)) {
			ptrace(("Have route to XP but no LP\n"));
			return (-EFAULT);
		}
		if (mp->b_datap->db_type < QPCTL && !canput(pp->rq))
			return (-EBUSY);
		if ((err = sccpp_xlat(as, &mp)))
			return (err);
		putq(pp->rq, mp);
		return (1);
	}
	ptrace(("AS-U marked active but no active AS-U\n"));
	return (-EFAULT);
}
static int sua_l_r_proto(queue_t * q, mblk_t * mp)
{
	switch (*((long *) mp->b_rptr)) {
	case N_INFO_ACK:
		return sccpp_info_ack(q, mp);
	case N_BIND_ACK:
		return sccpp_bind_ack(q, mp);
	case N_ERROR_ACK:
	case N_OK_ACK:
	case N_CONN_IND:
	case N_CONN_CON:
	case N_DISCON_IND:
	case N_DATA_IND:
	case N_EXDATA_IND:
	case N_UNITDATA_IND:
	case N_UDERROR_IND:
	case N_DATACK_IND:
	case N_RESET_IND:
	case N_RESET_CON:
		return sccpp_xlat_prim(q, mp);
	}
	return (-EOPNOTSUPP);
}
static int sua_l_r_pcproto(queue_t * q, mblk_t * mp)
{
	return sua_l_r_proto(q, mp);
}
static int sua_l_r_error(queue_t * q, mblk_t * mp)
{
	fixme(("Deactivate and take down AS, notify LM\n"));
	return (-EFAULT);
}
static int sua_l_r_hangup(queue_t * q, mblk_t * mp)
{
	fixme(("Deactivate and take down AS, notify LM\n"));
	return (-EFAULT);
}
static int sua_l_r_prim(queue_t * q, mblk_t * mp)
{
	switch (mp->b_datap->db_type) {
	case M_PROTO:
		return sua_l_r_proto(q, mp);
	case M_PCPROTO:
		return sua_l_r_pcproto(q, mp);
	case M_ERROR:
		return sua_l_r_error(q, mp);
	case M_HANGUP:
		return sua_l_r_hangup(q, mp);
	case M_FLUSH:
		return ua_r_flush(q, mp);
	}
	return (-EOPNOTSUPP);
}

/*
 *  -------------------------------------------------------------------------
 *
 *  SCTP NPI Transport Message Handling
 *
 *  -------------------------------------------------------------------------
 *
 *  SUA --> SCTP NPI Transport Primitives
 *  -------------------------------------------------------------------------
 */
static int sua_s_w_data(queue_t * q, mblk_t * dp)
{
	mblk_t *mp;
	N_data_req_t *p;
	N_qos_sel_data_sctp_t *q;
	if ((mp = allocb(sizeof(*p) + sizeof(*q), BPRI_MED))) {
		uint32_t mhdr = ((uint32_t *) dp->b_rptr)[0];
		mp->b_datap->db_type = M_PROTO;
		p = ((typeof(p)) mp->b_wptr)++;
		p->PRIM_type = N_DATA_REQ;
		p->DATA_xfer_flags = 0;
		q = ((typeof(q)) mp->b_wptr)++;
		q->n_qos_type = N_QOS_SEL_DATA_SCTP;
		q->ppi = SUA_PPI;
		q->tsn = 0;
		q->ssn = 0;
		mp->b_cont = dp;
		switch (UA_MSG_CLAS(mhdr)) {
		case UA_CLASS_MGMT:
		case UA_CLASS_ASPS:
		case UA_CLASS_RKMM:
			q->sid = 0;
			break;
		case UA_CLASS_ASPT:
		case UA_CLASS_XFER:
		case UA_CLASS_SNMM:
		{
			uint32_t rc = ((uint32_t *) dp->b_rptr)[3];
			fixme(("Map RC onto a stream id\n"));
			q->sid = rc;
			break;
		}
		default:
		case UA_CLASS_MAUP:
		case UA_CLASS_Q921:
		case UA_CLASS_CNLS:
		case UA_CLASS_CONS:
		case UA_CLASS_TDHM:
		case UA_CLASS_TCHM:
			freeb(mp);
			return (-EPROTO);
		}
		putq(q, mp);
		return (1);
	}
	return (-ENOBUFS);
}
static int sua_s_w_ctl(queue_t * q, mblk_t * mp)
{
	return sua_s_w_data(q, mp);
}
static int sua_s_w_error(queue_t * q, mblk_t * mp)
{
	fixme(("Disconnect, deactivate and take down ASP and notify LM\n"));
	noenable(q);
	return (-EFAULT);
}
static int sua_s_w_hangup(queue_t * q, mblk_t * mp)
{
	fixme(("Disconnect, deactivate and take down ASP and notify LM\n"));
	noenable(q);
	return (-EFAULT);
}
static int sua_x_w_prim(queue_t * q, mblk_t * mp)
{
	switch (mp->b_datap->db_type) {
	case M_DATA:
		return sua_s_w_data(q, mp);
	case M_CTL:
		return sua_s_w_ctl(q, mp);
	case M_ERROR:
		return sua_s_w_error(q, mp);
	case M_HANGUP:
		return sua_s_w_hangup(q, mp);
	case M_FLUSH:
		return ua_w_flush(q, mp);
	}
	return (-EOPNOTSUPP);
}

/*
 *  SCTP NPI Transport --> SUA Primitives
 *  -------------------------------------------------------------------------
 */
static int sua_s_data_ind(queue_t * q, mblk_t * mp)
{
}
static int sua_s_exdata_ind(queue_t * q, mblk_t * mp)
{
}
static int sua_s_other_ind(queue_t * q, mblk_t * mp)
{
}
static int sua_s_r_proto(queue_t * q, mblk_t * mp)
{
	switch (*((long *) mp->b_rptr)) {
	case N_DATA_IND:
		return sua_s_data_ind(q, mp);
	case N_EXDATA_IND:
		return sua_s_exdata_ind(q, mp);
	default:
		return sua_s_other_ind(q, mp);
	}
}
static int sua_s_r_pcproto(queue_t * q, mblk_t * mp)
{
	return sua_s_r_proto(q, mp);
}
static int sua_s_r_error(queue_t * q, mblk_t * mp)
{
	fixme(("Deactivate and take down ASP and notify LM\n"));
	noenable(q);
	return (-EFAULT);
}
static int sua_s_r_hangup(queue_t * q, mblk_t * mp)
{
	fixme(("Deactivate and take down ASP and notify LM\n"));
	noenable(q);
	return (-EFAULT);
}
static int sua_x_r_prim(queue_t * q, mblk_t * mp)
{
	switch (mp->b_datap->db_type) {
	case M_PROTO:
		return sua_s_r_proto(q, mp);
	case M_PCPROTO:
		return sua_s_r_pcproto(q, mp);
	case M_ERROR:
		return sua_s_r_error(q, mp);
	case M_HANGUP:
		return sua_s_r_hangup(q, mp);
	case M_FLUSH:
		return ua_r_flush(q, mp);
	}
	return (-EOPNOTSUPP);
}

extern struct drv sua_driver = {
	SUA_CMAJOR,
	SUA_NMAJOR,
	SUA_NMINOR,
	{&sua_u_r_prim, &sua_u_w_prim},
	{&sua_l_r_prim, &sua_l_w_prim},
	{&sua_x_r_prim, &sua_x_w_prim}
};


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

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

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