|
OpenSS7 SS7 for the Common Man |
© Copyright 1997-2004,OpenSS7 Corporation, All Rights Reserved. |
||||||||||||||||||||||||||
| Home | Overview | Status | News | Documentation | Resources | About | |||||||||||||||||||||
File /code/strss7/drivers/tcap/tcap_lower.c
#ident "@(#) $RCSfile: tcap_lower.c,v $ $Name: $($Revision: 0.8.2.2 $) $Date: 2003/04/03 19:51:40 $"
static char const ident[] =
"$RCSfile: tcap_lower.c,v $ $Name: $($Revision: 0.8.2.2 $) $Date: 2003/04/03 19:51:40 $";
#define __NO_VERSION__
#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 "../debug.h"
#include "../bufq.h"
#include "tcap.h"
#include "tcap_data.h"
#include "tcap_msgs.h"
#include "tcap_ctrl.h"
#include "tcap_prov.h"
#include "../sccpi/sccp_user.h"
/*
* =========================================================================
*
* TCAP INPUT EVENT State Machines
*
* =========================================================================
* These functions take an input msg at the TCAP stream and run the state
* machine associated with the TCAP stream. These are the Transaction (TR)
* Sub-Layer services.
*/
static int tcap_i_uni(queue_t * q, mblk_t * msg)
{
mblk_t *mp;
TC_uni_ind_t *p;
N_unitdata_ind_t *s = (N_unitdata_ind_t *) msg->b_cont->b_rptr;
tcap_t *tcap = (tcap_t *) q->q_ptr;
tr_msg_t *m = (tr_msg_t *) msg->b_rptr;
(void) m;
(void) tcap;
/*
* TODO: process message...
*
* Provide a TC_UNI_IND and follow with any TC_XXX_IND component
* indications.
*/
if (!(mp = allocb(sizeof(*p), BPRI_MED)))
return (-ENOBUFS);
p = (TC_uni_ind_t *) mp->b_wptr;
mp->b_datap->db_type = M_PROTO;
p->PRIM_type = TC_UNI_IND;
p->SRC_length = s->SRC_length;
p->SRC_offset = s->SRC_length ? sizeof(*p) : 0;
p->DEST_length = s->DEST_length;
p->DEST_offset = s->DEST_length ? sizeof(*p) + s->SRC_length : 0;
p->QOS_length = 0;
p->QOS_offset = 0;
p->CONTEXT_length = FIXME;
p->CONTEXT_offset = FIXME;
p->DIALOG_id = 0;
p->COMP_flags = (m->parms & TCAP_PTF_CSEQ) ? 1 : 0;
mp->b_wptr += sizeof(*p);
/* FIXME */
return (0);
}
/*
* =========================================================================
*
* SCCP --> TCAP (Upstream Primitives received from downstream)
*
* =========================================================================
*/
/*
* N_INFO_ACK 16 - Information Acknowledgement
* ----------------------------------------------------------------
*/
static int sccp_info_ack(queue_t * q, mblk_t * pdu)
{
sccp_t *sccp = (sccp_t *) q->q_ptr;
N_info_ack_t *p = (N_info_ack_t *) pdu->b_rptr;
if (pdu->b_wptr - pdu->b_rptr < sizeof(*p))
return m_error_all(q, pdu, EFAULT, EFAULT);
sccp->flags = p->OPTIONS_flags;
sccp->nsdu = p->NSDU_size;
sccp->nidu = p->NIDU_size;
sccp->nodu = p->NODU_size;
if (p->ADDR_length >= sizeof(sccp_addr_t)) {
sccp_addr_t *add = (sccp_addr_t *) (pdu->b_rptr + p->ADDR_offset);
bcopy(add, &sccp->bnd, sizeof(*add) + add->alen);
}
if (p->PROTOID_length == 1)
sccp->ssn = *((uint8_t *) (pdu->b_rptr + p->PROTOID_offset));
sccp->state = p->CURRENT_state;
freemsg(pdu);
return (0);
}
/*
* N_BIND_ACK 17 - NS User bound to network address
* ----------------------------------------------------------------
*/
static int sccp_bind_ack(queue_t * q, mblk_t * pdu)
{
sccp_t *sccp = (sccp_t *) q->q_ptr;
N_bind_ack_t *p = (N_bind_ack_t *) pdu->b_rptr;
if (pdu->b_wptr - pdu->b_rptr < sizeof(*p))
return m_error_reply(q, pdu, EFAULT, EFAULT);
if (sccp->state != NS_WACK_BREQ)
return m_error_reply(q, pdu, EPROTO, EPROTO);
if (p->ADDR_length >= sizeof(sccp_addr_t)) {
sccp_addr_t *add = (sccp_addr_t *) (pdu->b_rptr + p->ADDR_offset);
bcopy(add, &sccp->bnd, sizeof(*add) + add->alen);
}
if (p->PROTOID_length == 1)
sccp->ssn = *((uint8_t *) (pdu->b_rptr + p->PROTOID_offset));
sccp->state = NS_IDLE;
freemsg(pdu);
return (0);
}
/*
* N_ERROR_ACK 18 - Error Acknowledgement
* ----------------------------------------------------------------
*/
static int sccp_error_ack(queue_t * q, mblk_t * pdu)
{
sccp_t *sccp = (sccp_t *) q->q_ptr;
N_error_ack_t *p = (N_error_ack_t *) pdu->b_rptr;
if (pdu->b_wptr - pdu->b_rptr < sizeof(*p))
return m_error_reply(q, pdu, EFAULT, EFAULT);
switch (sccp->state) {
case NS_WACK_BREQ:
if (p->ERROR_prim == N_BIND_REQ)
sccp->state = NS_UNBND;
break;
case NS_WACK_UREQ:
if (p->ERROR_prim == N_UNBIND_REQ)
sccp->state = NS_IDLE;
break;
case NS_WACK_OPTREQ:
if (p->ERROR_prim == N_OPTMGMT_REQ)
sccp->state = sccp->state;
break;
case NS_WCON_CREQ:
if (p->ERROR_prim == N_CONN_REQ)
sccp->state = NS_IDLE;
break;
case NS_WRES_CIND:
if (p->ERROR_prim == N_CONN_RES)
sccp->state = sccp->state;
break;
case NS_WACK_CRES:
case NS_DATA_XFER:
case NS_WCON_RREQ:
case NS_WRES_RIND:
case NS_WACK_DREQ6:
case NS_WACK_DREQ7:
case NS_WACK_DREQ9:
case NS_WACK_DREQ10:
case NS_WACK_DREQ11:
default:
case NS_NOSTATES:
}
freemsg(pdu);
return (0);
}
/*
* N_OK_ACK 19 - Success Acknowledgement
* ----------------------------------------------------------------
*/
static int sccp_ok_ack(queue_t * q, mblk_t * pdu)
{
sccp_t *sccp = (sccp_t *) q->q_ptr;
N_ok_ack_t *p = (N_ok_ack_t *) pdu->b_rptr;
if (pdu->b_wptr - pdu->b_rptr < sizeof(*p))
return m_error_reply(q, pdu, EFAULT, EFAULT);
switch (sccp->state) {
case NS_WACK_BREQ:
case NS_WACK_UREQ:
case NS_WACK_OPTREQ:
case NS_WCON_CREQ:
case NS_WRES_CIND:
case NS_WACK_CRES:
case NS_DATA_XFER:
case NS_WCON_RREQ:
case NS_WRES_RIND:
case NS_WACK_DREQ6:
case NS_WACK_DREQ7:
case NS_WACK_DREQ9:
case NS_WACK_DREQ10:
case NS_WACK_DREQ11:
default:
case NS_NOSTATES:
}
/*
* TODO: more...
*/
freemsg(pdu);
return (0);
}
/*
* N_UNITDATA_IND 20 - Connection-less data receive indication
* ----------------------------------------------------------------
*/
static int sccp_unitdata_ind(queue_t * q, mblk_t * pdu)
{
sccp_t *sccp = (sccp_t *) q->q_ptr;
N_unitdata_ind_t *p = (N_unitdata_ind_t *) pdu->b_rptr;
(void) sccp;
if (pdu->b_wptr - pdu->b_rptr < sizeof(*p))
return m_error_all(q, pdu, EFAULT, EFAULT);
if (p->SRC_length < sizeof(sccp_addr_t))
return m_error_all(q, pdu, EFAULT, EFAULT);
if (p->DEST_length < sizeof(sccp_addr_t))
return m_error_all(q, pdu, EFAULT, EFAULT);
if (!pdu->b_cont)
return (-EINVAL);
return tcap_recv_msg(q, pdu);
}
/*
* N_UDERROR_IND 21 - UNITDATA Error Indication
* ----------------------------------------------------------------
*/
static int sccp_uderror_ind(queue_t * q, mblk_t * pdu)
{
tcap_t *tcap;
int ecode;
sccp_t *sccp = (sccp_t *) q->q_ptr;
N_uderror_ind_t *p = (N_uderror_ind_t *) pdu->b_rptr;
(void) ecode;
if (pdu->b_wptr - pdu->b_rptr < sizeof(*p))
return m_error_all(q, pdu, EFAULT, EFAULT);
if (p->DEST_length < sizeof(sccp_addr_t))
return m_error_all(q, pdu, EFAULT, EFAULT);
/*
* TODO: have to propagate error to TCAP-Users. Most of these turn
* into aborts (TR_ABORT_IND). We still have to generate a
* TRE_ABT_RES msg.
*/
for (tcap = sccp->tcap; tcap; tcap = tcap->sccp_next) {
if (tcap->outcnt > 0) {
/*
* Send TRE_ABT_RES msg to tcap user....
*/
}
}
freemsg(pdu);
return (0);
}
int (*sccp_dprim[]) (queue_t *, mblk_t *) = {
#define SCCP_DSTR_FIRST N_CONN_REQ
NULL, /* N_CONN_REQ 0 - NC request */
NULL, /* N_CONN_RES 1 - Accept prev NC indication */
NULL, /* N_DISOCN_REQ 2 - NC disconnect request */
NULL, /* N_DATA_REQ 3 - CO data transfer request */
NULL, /* N_EXDATA_REQ 4 - CO data transfer request */
NULL, /* N_INFO_REQ 5 - Information request */
NULL, /* N_BIND_REQ 6 - Bind an NS user */
NULL, /* N_UNBIND_REQ 7 - Unbind an NS user */
NULL, /* N_UNITDATA_REQ 8 - CL data transfer request */
NULL, /* N_OPTMGMT_REQ 9 - Options mgmt request */
NULL, /* (not used) 10 - (not used) */
NULL, /* N_CONN_IND 11 - Incoming NC indication */
NULL, /* N_CONN_CON 12 - NC established */
NULL, /* N_DISCON_IND 13 - NC disconnected */
NULL, /* N_DATA_IND 14 - CO data transfer indication */
NULL, /* N_EXDATA_IND 15 - CO data transfer indication */
sccp_info_ack, /* N_INFO_ACK 16 - Information Acknowledgement */
sccp_bind_ack, /* N_BIND_ACK 17 - NS User bound Ack */
sccp_error_ack, /* N_ERROR_ACK 18 - Error Acknowledgement */
sccp_ok_ack, /* N_OK_ACK 19 - Success Acknowledgement */
sccp_unitdata_ind, /* N_UNITDATA_IND 20 - CL data transfer indication */
sccp_uderror_ind, /* N_UDERROR_IND 21 - CL data error indication */
NULL, /* (not used) 22 - (not used) */
NULL, /* N_DATACK_REQ 23 - Data ack request */
NULL, /* N_DATACK_IND 24 - Data ack indication */
NULL, /* N_RESET_REQ 25 - NC reset request */
NULL, /* N_RESET_IND 26 - Incoming NC reset ind */
NULL, /* N_RESET_RES 27 - Reset processing accepted */
NULL /* N_RESET_CON 28 - Reset processing complete */
#define SCCP_DSTR_LAST N_RESET_CON
};
static int tcap_r_proto(queue_t * q, mblk_t * mp)
{
/* FIXME */
freemsg(mp);
return (0);
}
/*
* =========================================================================
*
* M_ERROR Processing
*
* =========================================================================
* We propagate any M_ERROR(s) received on the lower stream from the SCCP
* Provider to every TCAP-User upper stream which is using the SCCP provider.
* We also set states here to indicate the error. This is because if we run
* out of mblks to propagate the M_ERROR, we will discard the priority
* message (M_ERROR) if we are in the read service routine. Setting the
* error ensures that we will respond with an M_ERROR later when resources
* are available.
*/
static int tcap_r_error(queue_t * q, mblk_t * pdu)
{
/*
* FIXME: Notify this SCCP-Provider's management stream that the
* SCCP-Provider has errored out...
*/
return m_error_all(q, pdu, *(pdu->b_rptr + 4), *(pdu->b_wptr - 1));
}
/*
* =========================================================================
*
* M_HANGUP Processing
*
* =========================================================================
* We propagate any M_HANGUP(s) received on the lower stream from the SCCP
* Provider to every TCAP-User upper stream which is using the SCCP provider.
* We also set states here to indicate the error. This is because if we run
* out of mblks to propagate the M_HANGUP, we will discard the priority
* message (M_HANGUP) if we are in the read service routine. Setting the
* error ensures that we will respond with an M_HANGUP later when resources
* are available.
*/
static int tcap_r_hangup(queue_t * q, mblk_t * pdu)
{
/*
* FIXME: Notify this SCCP-Provider's management stream that the
* SCCP-Provider has hung up...
*/
return m_hangup_all(q, pdu);
}
/*
* =========================================================================
*
* QUEUE PUT and SERVICE routines
*
* =========================================================================
*/
/*
* READ PUT and SERVICE (Message from below SCCP-Provider --> TCAP)
* -------------------------------------------------------------------------
*/
int tcap_l_r_prim(queue_t * q, mblk_t * mp)
{
switch (mp->b_datap->db_type) {
case M_PROTO:
case M_PCPROTO:
return tcap_r_proto(q, mp);
case M_FLUSH:
return tcap_r_flush(q, mp);
case M_ERROR:
return tcap_r_error(q, mp);
case M_HANGUP:
return tcap_r_hangup(q, mp);
}
return (-EOPNOTSUPP);
}
|
|||||||||||||||||||||||||||
|
OpenSS7 SS7 for the Common Man |
Home | Overview | Status | News | Documentation | Resources | About | ||||||||||||||||||||
|
© Copyright 1997-2004,OpenSS7 Corporation, All Rights Reserved. |
|||||||||||||||||||||||||||