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/m3ua/m3ua_ss7.c#ident "@(#) $RCSfile: m3ua_ss7.c,v $ $Name: $($Revision: 0.8.2.2 $) $Date: 2003/04/03 19:50:32 $" static char const ident[] = "$RCSfile: m3ua_ss7.c,v $ $Name: $($Revision: 0.8.2.2 $) $Date: 2003/04/03 19:50:32 $"; #define __NO_VERSION__ #include <linux/config.h> #include <linux/version.h> #ifdef MODVERSIONS #include <linux/modversions.h> #endif #include <sys/stream.h> #include <sys/stropts.h> #include <sys/cmn_err.h> #include "m3ua.h" #include "m3ua_data.h" #include "m3ua_ctrl.h" #include "m3ua_msg.h" /* * ========================================================================= * * MTP-User --> M3UA (ASP) Downstream Primitives * * ========================================================================= */ static inline int mtp_error_reply(queue_t * q, mblk_t * pdu, int prim, int err) { mblk_t *mp; if ((mp = mtp_error_ack(prim, err))) { freemsg(pdu); qreply(q, mp); return (0); } return (-ENOBUFS); } static inline int mtp_uderror_reply(queue_t * q, mblk_t * pdu, int err) { mblk_t *mp; N_unitdata_req_t *p = (N_unitdata_req_t *) pdu->b_rptr; if ((mp = mtp_uderror_ind(err, p->DEST_length ? (mtp_addr_t *) (pdu->b_rptr + p->DEST_offset) : 0, p->SRC_length ? (mtp_addr_t *) (pdu->b_rptr + p->SRC_offset) : 0, pdu->b_cont))) { freeb(pdu); qreply(q, mp); return (0); } return (-ENOBUFS); } static int parse_options(queue_t * q, mblk_t * pdu, int prim, caddr_t opt_ptr, size_t opt_len) { mtp_t *mtp = (mtp_t *) q->q_ptr; if (opt_len < sizeof(uint32_t)) return mtp_error_reply(q, pdu, prim, NBADQOSTYPE); switch (*((ulong *) opt_ptr)) { case N_QOS_SEL_MTP: { N_qos_sel_mtp_t *p = (N_qos_sel_mtp_t *) opt_ptr; if (prim == N_OPTMGMT_REQ) goto parse_options_badqostype; if (opt_len < sizeof(*p)) goto parse_options_badqostype; if (prim != N_CONN_REQ && prim != N_CONN_RES && prim != N_UNITDATA_REQ) goto parse_options_badqostype; if (p->sls == QOS_UNKNOWN) mtp->sls = mtp_next_sls_value++; else mtp->sls = p->sls; if (p->mp == QOS_UNKNOWN) mtp->mp = 0; else mtp->mp = p->mp; break; } case N_QOS_OPT_SEL_MTP: { N_qos_opt_sel_mtp_t *p = (N_qos_sel_mtp_t *) opt_ptr; if (prim != N_OPTMGMT_REQ) goto parse_options_badqostype; if (opt_len < sizeof(*p)) goto parse_options_badqostype; break; } default: goto parse_options_badqostype; } return (0); parse_options_badqostype:return mtp_error_reply(q, pdu, prim, NBADQOSTYPE); } /* * N_CONN_REQ 0 - NC request * ------------------------------------------------------------------------- * This request is only valid for ISUP/TUP MTP-Users. When we receive a * connect request, we either have an existing AS which has the indicated * Routing Key or we request that the LM queue create and return an AS. If * the AS exists and is statically provisioned, then we can perform ASPAC * procedures on any associated SGP. If no SGP are associated, we can refuse * the connection request. If SGP are associated we send an ASPAC and wait * for the result before responding with an N_CONN_CON. */ static int ss7_conn_req(queue_t * q, mblk_t * pdu) { mtp_addr_t *a; mtp_t *mtp = (mtp_t *) q->q_ptr; N_conn_req_t *p = (N_conn_req_t *) pdu->b_rptr; if (pdu->b_wptr - pdu->b_rptr < sizeof(*p)) goto ss7_conn_req_emsgsize; if (pdu->b_rptr + p->DEST_offset > pdu->b_wptr - p->DEST_length) goto ss7_conn_req_badaddr; if (pdu->b_rptr + p->QOS_offset > pdu->b_wptr - p->QOS_length) goto ss7_conn_req_badopt; if (p->DEST_length == 0) goto ss7_conn_req_noaddr; if (p->DEST_length < sizeof(*a)) goto ss7_conn_req_badaddr; if (mtp->state != NS_IDLE) goto ss7_conn_req_outstate; if ((err = parse_options(q, pdu, N_CONN_REQ, pdu->b_rptr + p->QOS_offset, p->QOS_length))) return (err); a = (mtp_addr_t *) (pdu->b_rptr + p->DEST_offset); bcopy(a, &mtp->dst, sizeof(*a)); /* * FIXME: There is a couple of things we could do here: * * 1) We could formulate a Routing Key and then check the list of * configured Routing Keys to see if one is associated with a * current AS. * * 2) If we find an RK match but it is not associated with an AS, * yet it is associated with SGPs for dynamic registration, we * can create an AS and attempt to dynamically register the RK * with a REG REQ for those SGP supporting it. * * 3) If we cannot find an RK match, we can ask the LM queue to map * the RK for us. * * 4) If we cannot find an RK match, we can formulate a REG REQ and * send it to all available SGPs. * */ mtp->state = NS_WCON_CREQ; freemsg(pdu); return (0); ss7_conn_req_emsgsize:return mtp_error_reply(q, pdu, N_CONN_REQ, -EMSGSIZE); ss7_conn_req_badaddr:return mtp_error_reply(q, pdu, N_CONN_REQ, NBADADDR); ss7_conn_req_badopt:return mtp_error_reply(q, pdu, N_CONN_REQ, NBADOPT); ss7_conn_req_noaddr:return mtp_error_reply(q, pdu, N_CONN_REQ, NNOADDR); ss7_conn_req_outstate:return mtp_error_reply(q, pdu, N_CONN_REQ, NOUTSTATE); } /* * N_DISCON_REQ 2 - NC disconnection request * ------------------------------------------------------------------------- * This request is only valid for ISUP/TUP MTP-Users. When we receive a * disconnect request from the user, we should detach the SS7 stream from the * AS and change the AS state if necessary. If the AS state changes to * INACTIVE from ACTIVE we should perorm ASPIA procedures with each * associated SGP (IPC or UAP) and ASPIA Ack procedures with each associated * ASP (IPC). Reasons are not given. */ static int ss7_discon_req(queue_t * q, mblk_t * pdu) { mblk_t *mp; size_t dlen = msgdsize(pdu); size_t mlen = pdu->b_wptr - pdu->b_rptr; mtp_t *mpt = (mtp_t *) q->q_ptr; N_discon_req_t *p = (N_discon_req_t *) pdu->b_rptr; if (mlen < sizeof(*p)) goto ss7_discon_req_emsgsize; if (dlen > 0) goto ss7_discon_req_baddata; switch (mtp->state) { case NS_WCON_CREQ: /* * FIXME: we are trying to connect, we need to abort * the connection request. */ break; case NS_DATA_XFER: case NS_WRES_RIND: /* * FIXME: initiate disconnect. This consists of * deactivating the SS7 stream and seeing if the AS * is now deactivated. If the AS is inactive as a * result, send ASPIA for the AS. */ default: goto mtp_discon_req_outstate; } freemsg(pdu); return (0); ss7_discon_req_outstate:return mtp_error_reply(q, pdu, N_DISCON_REQ, NOUTSTATE); ss7_discon_req_baddata:return mtp_error_reply(q, pdu, N_DISCON_REQ, NBADDATA); ss7_discon_req_emsgsize:return mtp_error_reply(q, pdu, N_DISCON_REQ, -EMSGSIZE); } /* * N_DATA_REQ 3 - Connection-Mode data transfer request * ------------------------------------------------------------------------- * This request is only valid for ISUP/TUP MTP-Users. If the interface is in * the NS_DATA_XFER state, we select an SGP and send DATA messages, otherwise * we return an error or N_DISCON_IND. */ static int ss7_data_req(queue_t * q, mblk_t * pdu) { mblk_t *mp; uint more; size_t dlen = msgdsize(pdu); size_t mlen = pdu->b_wptr - pdu->b_rptr; mtp_t *mtp = (mtp_t *) q->q_ptr; N_data_req_t *p = (N_data_req_t *) pdu->b_rptr; if (mlen < sizeof(*p)) goto ss7_data_req_eproto; if (!dlen || dlen > mtp->nidu) goto ss7_data_req_eproto; if (mtp->state == NS_IDLE || sccp->state == NS_WRES_RIND) goto ss7_data_req_ignore; if (mtp->state != NS_DATA_XFER) goto ss7_data_req_eproto; if (!pdu->b_cont) goto ss7_data_req_eproto; if (p->DATA_xfer_flags & N_RC_FLAG) goto ss7_data_req_eproto; if (p->DATA_xfer_flags & N_MORE_DATA_FLAG) { if (!mtp->assemble) mtp->assemble = pdu->b_cont; else linkb(mtp->assemble, pdu->b_cont); freeb(pdu); return (0); } if (mtp->assemble) { linkb(mtp->assemble, pdu->b_cont); pdu->b_cont = mtp->assemble; mtp->assemble = NULL; if (msgdsize(pdu) > mtp->nidu) goto ss7_data_req_eproto; } /* * FIXME: select an SGP and formulate a DATA message and send * it to the SGP on a selected stream. */ putq(q, mp); freeb(pdu); return (0); ss7_data_req_ignore:freemsg(pdu); return (0); ss7_data_req_eproto:return m_error_reply(q, pdu, EPROTO, EPROTO); } /* * Same as N_DATA_REQ but with M_DATA only. */ static int ss7_w_data(queue_t * q, mblk_t * pdu) { } /* * N_INFO_REQ 5 - Information Request * ------------------------------------------------------------------------- * Valid for both CNLS and CONS. We always return current information * associated with the interface in an N_INFO_ACK. */ static int ss7_info_req(queue_t * q, mblk_t * mp) { } /* * N_BIND_REQ * ------------------------------------------------------------------------- * Depending on CNLS or CONS. CNLS we check for Routing Keys associated with * ASPs which match the requested bind. If no AS is found with the requested * bind, we RK or perform a REG REQ to associated SGP. If an AS is found, we * or REG REQ is successful, we perform ASPAC procedures to associated SGP. * For CONS, we bind the local address and return N_BIND_ACK. */ static int ss7_bind_req(queue_t * q, mblk_t * mp) { mblk_t *rp; mtp_addr_t *a; mtp_t *mtp = (mtp_t *) q->q_ptr; N_bind_req_t *p = (N_bind_req_t *) pdu->b_rptr; if (pdu->b_wptr - pdu->b_rptr < sizeof(*p)) goto ss7_bind_req_emsgsize; if (pdu->b_rptr + p->ADDR_offset > pdu->b_wptr - p->ADDR_length) goto ss7_bind_req_badaddr; if (pdu->b_rptr + p->PROTOID_offset > pdu->b_wptr - p->PROTOID_length) goto ss7_bind_req_badprot; if (p->ADDR_length == 0) goto ss7_bind_req_noaddr; if (p->ADDR_length < sizeof(*a)) goto ss7_bind_req_badaddr; if (mtp->state != NS_UNBND) goto ss7_conn_req_outstate; a = (mtp_addr_t *) (pdu->b_rptr + p->ADDR_offset); bcopy(a, &mtp->src, sizeof(*a)); /* * FIXME: There is a couple of things we could do here: * * 1) We could formulate a RK and then check the list of configured * RKs to see if one is associated with a current AS. * * 2) If we find an RK match but it is not associated with an AS, * yet it is associated with SGPs for dynamic registration, we * can create an AS and attempt to dynamically register the RK * with a REG REQ for those SGP supporting it. * * 3) If we cannot find an RK match, we can ask the LM queue to map * the RK for us. * * 4) If we cannot find an RK match, we can formulate a REG REQ and * send it to all available SGPs. */ mtp->state = NS_IDLE; freemsg(pdu); return (0); ss7_bind_req_emsgsize:return mtp_error_reply(q, pdu, N_BIND_REQ, -EMSGSIZE); ss7_bind_req_badaddr:return mtp_error_reply(q, pdu, N_BIND_REQ, NBADADDR); ss7_bind_req_badprot:return mtp_error_reply(q, pdu, N_BIND_REQ, NBADPROTO); ss7_bind_req_noaddr:return mtp_error_reply(q, pdu, N_BIND_REQ, NNOADDR); ss7_conn_req_outstate:return mtp_error_reply(q, pdu, N_BIND_REQ, NOUTSTATE); } /* * N_UNBIND_REQ * ------------------------------------------------------------------------- * We always just change state and return a N_OK_ACK. For CNLS, unbinding * the stream also needs to deactivate it. If the associated AS becomes * inactive due to this, the ASPIA procedures may need to be performed. */ static int ss7_unbind_req(queue_t * q, mblk_t * pdu) { mblk_t *rp; mtp_t *mtp = (mtp_t *) q->q_ptr; N_unbind_req_t *p = (N_unbind_req_t *) pdu->b_rptr; if (pdu->b_wptr - pdu->b_rptr < sizeof(*p)) goto ss7_unbind_req_emsgsize; if (mtp->state != NS_IDLE) goto ss7_unbind_req_outstate; if (!(rp = mtp_ok_ack(N_UNBIND_REQ))) return (-ENOBUFS); mtp->state = NS_WACK_UREQ; qreply(q, mp); mtp->state = NS_UNBND; freemsg(pdu); return (0); ss7_unbind_req_emsgsize:return mtp_error_reply(q, pdu, N_UNBIND_REQ, -EMSGSIZE); ss7_unbind_req_outstate:return mtp_error_reply(q, pdu, N_UNBIND_REQ, NOUTSTATE); } /* * N_UNITDATA_REQ * ------------------------------------------------------------------------- * This request is only valid for non-ISUP/TUP MTP-Users. If we are in * NS_IDLE state we formulate a DATA message and send it on to a selected * SGP (or return error). */ static int ss7_unitdata_req(queue_t * q, mblk_t * mp) { mtp_addr_t *src, *dst; N_qos_sel_mtp_t *qos; mtp_t *mtp = (mtp_t *) q->q_ptr; size_t dlen = msgdsize(pdu); size_t mlen = pdu->b_wptr - pdu->b_rptr; N_unitdata_req_t *p = (N_unitdata_req_t *) pdu->b_rptr; if (mlen < sizeof(*p) || mlen < p->DEST_offset + p->DEST_length || mlen < p->SRC_offset + p->SRC_length || mlen < p->QOS_offset + p->QOS_length) goto ss7_unitdata_req_emsgsize; if (mtp->state != NS_IDLE || dlen > mtp->nidu) goto ss7_unitdata_req_eproto; if (!dlen) goto ss7_unitdata_req_baddata; if (!p->QOS_length || p->QOS_length < sizeof(*qos)) goto ss7_unitdata_req_badqos; else { qos = (N_qos_sel_mtp_t *) (pdu->b_rptr + p->QOS_offset); if (qos->n_qos_type != N_QOS_SEL_MTP) goto ss7_unitdata_req_badqos; /* fill in missing QOS parameters for user */ if (qos->sls == -1) mtp->sls = mtp_next_sls_value++; if (qos->mp == -1) mtp->mp = 0; } if (!p->SRC_length) { /* implicit source address */ src = &mtp->src; } else { /* check provided source address */ src = (mtp_addr_t *) (pdu->b_rptr + p->SRC_offset); if (p->SRC_length < sizeof(*src)) goto ss7_unitdata_req_badaddr; /* fill in PC for user */ if (!src->ni || src->ni == -1) src->ni = mtp->src.ni; if (!src->pc || src->pc == -1) src->pc = mtp->src.pc; if (!src->si || src->si == -1) src->si = mtp->src.si; } if (!p->DEST_length) { /* destination address is mandatory */ goto mtp_unitdata_req_badaddr; } else { /* check provided destination address */ dst = (mtp_addr_t *) (pdu->b_rptr + p->DEST_offset); if (p->DEST_length < sizeof(*dst)) goto ss7_unitdata_req_badaddr; if (!dst->ni || dst->ni == -1) dst->ni = mtp->src.ni; if (!dst->si || dst->si == -1) dst->si = mtp->src.si; if (!dst->ni || dst->ni == -1) goto ss7_unitdata_req_badaddr; } /* * FIXME: Package up the data, select an SGP, stream and transmit * message. */ freeb(pdu); return (0); mtp_unitdata_req_badaddr:return mtp_uderror_reply(q, pdu, NBADADDR); mtp_unitdata_req_badqos:return mtp_uderror_reply(q, pdu, NBADOPT); mtp_unitdata_req_baddata:return mtp_uderror_reply(q, pdu, NBADDATA); mtp_unitdata_req_emsgsize:return mtp_error_reply(q, pdu, N_UNITDATA_REQ, -EMSGSIZE); mtp_unitdata_req_eproto:return m_error_reply(q, pdu, EPROTO, EPROTO); } /* * N_OPTMGMT_REQ * ------------------------------------------------------------------------- * This depends on a number of factors. Some requests are local, some * require interaction with the SGP. */ static int ss7_optmgmt_req(queue_t * q, mblk_t * mp) { } /* * N_RESET_RES * ------------------------------------------------------------------------- * This request is only valid for ISUP/TUP MTP-Users. This indicates that * the User has accepted a reset indication. We change state back to * NS_DATA_XFER. */ static int ss7_reset_res(queue_t * q, mblk_t * mp) { int err; mblk_t *rp; size_t mlen = pdu->b_wptr - pdu->b_rptr; mtp_t *mtp = (mtp_t *) q->q_ptr; N_reset_res_t *p = (N_reset_res_t *) pdu->b_rptr; if (mlen < sizeof(*p)) goto ss7_reset_res_emsgsize; if (mtp->state == NS_IDLE) goto ss7_reset_req_ignore; if (mtp->state != NS_WRES_RIND) goto ss7_reset_req_outstate; if (!(rp = mtp_ok_ack(N_RESET_RES))) return (-ENOBUFS); /* * TODO: more... */ mtp->state = NS_WACK_RRES; qreply(q, rp); mtp->state = NS_DATA_XFER; /* on success */ ss7_reset_res_ignore: freemsg(pdu); return (0); ss7_reset_res_emsgsize:return mtp_reply_error(q, pdu, N_RESET_RES, -EMSGSIZE); ss7_reset_res_outstate:return mtp_reply_error(q, pdu, N_RESET_RES, NOUTSTATE); } static int (*ss7_dstr_prim[]) (queue_t *, mblk_t *) = { #define MTP_DSTR_FIRST N_CONN_REQ ss7_conn_req, /* N_CONN_REQ 0 */ NULL, /* N_CONN_RES 1 */ ss7_discon_req, /* N_DISCON_REQ 2 */ ss7_data_req, /* N_DATA_REQ 3 */ NULL, /* N_EXDATA_REQ 4 */ ss7_info_req, /* N_INFO_REQ 5 */ ss7_bind_req, /* N_BIND_REQ 6 */ ss7_unbind_req, /* N_UNBIND_REQ 7 */ ss7_unitdata_req, /* N_UNITDATA_REQ 8 */ ss7_optmgmt_req, /* N_OPTMGMT_REQ 9 */ NULL, /* 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 */ NULL, /* N_INFO_ACK 16 */ NULL, /* N_BIND_ACK 17 */ NULL, /* N_ERROR_ACK 18 */ NULL, /* N_OK_ACK 19 */ NULL, /* N_UNITDATA_IND 20 */ NULL, /* N_UDERROR_IND 21 */ NULL, /* 22 */ NULL, /* N_DATACK_REQ 23 */ NULL, /* N_DATACK_IND 24 */ NULL, /* N_RESET_REQ 25 */ NULL, /* N_RESET_IND 26 */ ss7_reset_res, /* N_RESET_RES 27 */ #define MTP_DSTR_LAST N_RESET_RES NULL, /* N_RESET_CON 28 */ }; static int ss7_w_proto(queue_t * q, mblk_t * mp) { int prim = *((long *) mp->b_wptr); if (MTP_DSTR_FIRST <= prim && prim <= MTP_DSTR_LAST && ss7_dstr_prim[prim]) return ((*ss7_dstr_prim[prim]) (q, mp)); return (-EOPNOTSUPP); } static int ss7_w_flush(queue_t * q, mblk_t * mp) { return ua_w_flush(q, mp); } static int (*ss7_w_ops[]) (queue_t *, mblk_t *) = { ss7_w_data, /* M_DATA */ ss7_w_proto, /* M_PROTO */ NULL, /* M_BREAK */ NULL, /* M_CTL */ NULL, /* M_DELAY */ NULL, /* M_IOCTL */ NULL, /* M_PASSFP */ NULL, /* M_RSE */ NULL, /* M_SETOPTS */ NULL, /* M_SIG */ NULL, /* M_COPYIN */ NULL, /* M_COPYOUT */ NULL, /* M_ERROR */ ss7_w_flush, /* M_FLUSH */ NULL, /* M_HANGUP */ NULL, /* M_IOCACK */ NULL, /* M_IOCNAK */ NULL, /* M_IOCDATA */ ss7_w_proto, /* M_PCPROTO */ NULL, /* M_PCRSE */ NULL, /* M_PCSIG */ NULL, /* M_READ */ NULL, /* M_STOP */ NULL, /* M_START */ NULL, /* M_STARTI */ NULL /* M_STOPI */ }; struct ops ss7_ops = { NULL, /* read operations */ &ss7_w_ops /* write operations */ }; /* * ========================================================================= * * (SG) MTPP --> M2UA (Upstream Primitives) * * ========================================================================= * These primitives are sent from the lower mux MTP Provider in SG operation * to a Signalling Gateway Process (SGP). */ /* * N_CONN_IND 11 - Incoming connection indication * ------------------------------------------------------------------------- */ /* * N_CONN_CON 12 - Connection established * ------------------------------------------------------------------------- */ /* * N_DISCON_IND 13 - NC disconnected * ------------------------------------------------------------------------- */ /* * N_DATA_IND 14 - Incoming connection-mode data indication * ------------------------------------------------------------------------- */ /* * N_EXDATA_IND 15 - Incoming expedited data indication * ------------------------------------------------------------------------- */ /* * N_INFO_ACK 16 - Information Acknowledgement * ------------------------------------------------------------------------- */ static int ss7_info_ack(queue_t * q, mblk_t * mp) { /* * FIXME: might want to look at this one to get some pertinent * information and then pass it on. We might have generated the * infor request ourselves. */ mtp_t *mtp = Q_MTP(q); N_info_ack_t *p = (N_info_ack_t *) mp->b_rptr; if (mp->b_wptr - mp->b_rptr < sizeof(*p)) return -EPROTO; mtp->max_sdu = p->NSDU_size; /* maximum NSDU size */ mtp->header_len = p->ADDR_size; /* address size */ /* * FIXME: need to dig out bound ADDR. (Do I?) * FIXME: need to dig out QOS values, these would be size of the SLS. */ mtp->options = p->OPTIONS_flags; mtp->service = p->SERV_type; mtp->state = p->CURRENT_state; mtp->provider = p->PROVIDER_type; mtp->opt_sdu = p->NODU_size; mtp->version = p->NPI_version; return (lm_link_ind(q, mp)); } /* * N_BIND_ACK 17 - NS User bound to network address * ------------------------------------------------------------------------- */ static int ss7_bind_ack(queue_t * q, mblk_t * mp) { /* * FIXME: might want to look at this one to echo the state of the * interface and then pass it on. */ return (lm_link_ind(q, mp)); } /* * N_ERROR_ACK 18 - Error Acknowledgement * ------------------------------------------------------------------------- */ static int ss7_error_ack(queue_t * q, mblk_t * mp) { /* * FIXME: might want to look at this one to echo the state of the * interface and then pass it on. */ return (lm_link_ind(q, mp)); } /* * N_OK_ACK 19 - Success Acknowledgement * ------------------------------------------------------------------------- */ static int ss7_ok_ack(queue_t * q, mblk_t * mp) { /* * FIXME: might want to look at this one to echo the state of the * interface and then pass it on. */ return (lm_link_ind(q, mp)); } /* * N_UNITDATA_IND 20 - Connection-less data receive indication * ------------------------------------------------------------------------- * N_UNITDATA_IND (MTP_TRANSFER_IND) * ------------------------------------------------------------------------- * This covers only the MTP-TRANSFER-Indication primitive. * * Let me ask a question here: why dont we just pass the unitdata on to the * ASP and let the ASP translate it into an M3UA message. That way, if there * are different ASPs supporting different versions, that can be handled at * the ASP instead of here. Also, we don't know the transport type. If it * is an SCTP transport, it can do other things with the message, like select * stream. */ static int ss7_unitdata_ind(queue_t * q, mblk_t * msg) { sls_t *sls; queue_t *wq; mtp_t *mtp = Q_MTP(q); mblk_t *mp, *db = msg->b_cont; size_t dlen = msgdsize(db); N_unitdata_ind_t *p = (N_unitdata_req_t *) msg->b_rptr; struct mtp_rl *rl = (mtp_rt *) (((caddr_t) p) + p->SRC_offset); static const size_t mlen = M3UA_MHDR_SIZE + M3UA_PARM_SIZE_RC + M3UA_PARM_SIZE_RL + M3UA_PHDR_SIZE; /* * First let's find out where the data is going. The AS should have * this all set up for us in the SLS tables. */ ensure(mtp, return (-EFAULT)); ensure(mtp->rc, return (-EFAULT)); ensure(mtp->rc->as, return (-EFAULT)); sls = &mtp->rc->as->sls[(rl->sls & UA_SLS_MASK)]; ensure(sls->sp, return (-EFAULT)); ensure(sls->sp->lp, return (-EFAULT)); ensure(sls->sp->lp->q, return (-EFAULT)); if (!(sls->flags & UA_SLS_BUFFERING)) if (!(canput((wq = WR(sls->sp->lp->q))))) return (-EBUSY); /* apply backpressure! */ if ((mp = allocb(mlen, BPRI_MED))) { mp->b_datap->db_type = M_DATA; *((uint32_t *) mp->b_wptr)++ = M3UA_MAUP_DATA; *((uint32_t *) mp->b_wptr)++ = htonl(mlen + dlen); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_NA; *((uint32_t *) mp->b_wptr)++ = htonl(mtp->na); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_RC; *((uint32_t *) mp->b_wptr)++ = htonl(mtp->rc); /* * A couple of big arguments on what should be in the * messages here... */ *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_RL; *((uint32_t *) mp->b_wptr)++ = hotnl(rl->opc); *((uint32_t *) mp->b_wptr)++ = hotnl(rl->dpc); *((uint8_t *) mp->b_wptr)++ = 0; *((uint8_t *) mp->b_wptr)++ = hotnl(rl->sls); *((uint8_t *) mp->b_wptr)++ = hotnl(rl->ni); *((uint8_t *) mp->b_wptr)++ = hotnl(rl->mp); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_DATA; mp->b_cont = db; freeb(msg); if (sls->flags & UA_SLS_BUFFERING) /* hold back data for this sls */ bufq_queue(&sls->buf, mp); else putq(wq, mp); return (0); } return (-ENOBUFS); /* try again later */ } /* * N_UDERROR_IND 21 - UNITDATA Error Indication * ------------------------------------------------------------------------- * N_UDERROR_IND (MTP_PAUSE_IND, MTP_RESUME_IND, MTP_STATUS_IND, MTP_RESTART_IND) * ------------------------------------------------------------------------- * This covers the MTP-STATUS-Indication, MTP-PAUSE-Indication, * MTP-RESUME-Indication, MTP-RESTART-BEGINS and MTP-RESTART-ENDS. */ static mblk_t *ss7_uderror_ind(queue_t * q, mblk_t * msg) { mblk_t *mp; mtp_t *mtp = Q_MTP(q); static const size_t mlen = FIXME; if ((mp = allocb(mlen, BPRI_MED))) { N_uderror_ind_t *p = (N_uderror_ind_t *) msg->b_rptr; struct mtp_rl *rl = (mtp_rl *) (((caddr_t) p) + p->DEST_offset - sizeof(uint32_t)); mp->b_datap->db_type = M_DATA; switch (p->ERROR_type) { case MTP_DEST_CONGESTED: *((uint32_t *) mp->b_wptr)++ = M3UA_MAUP_SCON; *((uint32_t *) mp->b_wptr)++ = __constant_htohl(mlen); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_NA; *((uint32_t *) mp->b_wptr)++ = htonl(mtp->na); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_RC; *((uint32_t *) mp->b_wptr)++ = htonl(mtp->rc); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_APC; *((uint32_t *) mp->b_wptr)++ = htonl(rl->dpc); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_CONG_LEVEL; *((uint32_t *) mp->b_wptr)++ = htonl(rl->mp); break; case MTP_DEST_PROHIBITED: *((uint32_t *) mp->b_wptr)++ = M3UA_MAUP_DUNA; *((uint32_t *) mp->b_wptr)++ = __constant_htohl(mlen); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_NA; *((uint32_t *) mp->b_wptr)++ = htonl(mtp->na); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_RC; *((uint32_t *) mp->b_wptr)++ = htonl(mtp->rc); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_APC; *((uint32_t *) mp->b_wptr)++ = htonl(rl->dpc); break; case MTP_DEST_RESTRICTED: *((uint32_t *) mp->b_wptr)++ = M3UA_MAUP_DRST; *((uint32_t *) mp->b_wptr)++ = __constant_htohl(mlen); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_NA; *((uint32_t *) mp->b_wptr)++ = htonl(mtp->na); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_RC; *((uint32_t *) mp->b_wptr)++ = htonl(mtp->rc); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_APC; *((uint32_t *) mp->b_wptr)++ = htonl(rl->dpc); break; case MTP_CLUSTER_PROHIBITED: *((uint32_t *) mp->b_wptr)++ = M3UA_MAUP_DUNA; *((uint32_t *) mp->b_wptr)++ = __constant_htohl(mlen); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_NA; *((uint32_t *) mp->b_wptr)++ = htonl(mtp->na); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_RC; *((uint32_t *) mp->b_wptr)++ = htonl(mtp->rc); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_APC; *((uint32_t *) mp->b_wptr)++ = htonl(0x08000000 | rl->dpc); break; case MTP_CLUSTER_RESTRICTED: *((uint32_t *) mp->b_wptr)++ = M3UA_MAUP_DRST; *((uint32_t *) mp->b_wptr)++ = __constant_htohl(mlen); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_NA; *((uint32_t *) mp->b_wptr)++ = htonl(mtp->na); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_RC; *((uint32_t *) mp->b_wptr)++ = htonl(mtp->rc); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_APC; *((uint32_t *) mp->b_wptr)++ = htonl(0x08000000 | rl->dpc); break; case MTP_RESTARTING: *((uint32_t *) mp->b_wptr)++ = M3UA_MAUP_DUNA; *((uint32_t *) mp->b_wptr)++ = __constant_htohl(mlen); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_NA; *((uint32_t *) mp->b_wptr)++ = htonl(mtp->na); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_RC; *((uint32_t *) mp->b_wptr)++ = htonl(mtp->rc); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_APC; *((uint32_t *) mp->b_wptr)++ = htonl(0xff000000 | rl->dpc); break; case MTP_USER_PART_UNKNOWN: *((uint32_t *) mp->b_wptr)++ = M3UA_MAUP_DUPU; *((uint32_t *) mp->b_wptr)++ = __constant_htohl(mlen); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_NA; *((uint32_t *) mp->b_wptr)++ = htonl(mtp->na); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_RC; *((uint32_t *) mp->b_wptr)++ = htonl(mtp->rc); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_APC; *((uint32_t *) mp->b_wptr)++ = htonl(rl->dpc); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_USER_CAUSE; *((uint16_t *) mp->b_wptr)++ = M3UA_USER_UNKNOWN; *((uint16_t *) mp->b_wptr)++ = htons(rl->si); break; case MTP_USER_PART_UNEQUIPPED: *((uint32_t *) mp->b_wptr)++ = M3UA_MAUP_DUPU; *((uint32_t *) mp->b_wptr)++ = __constant_htohl(mlen); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_NA; *((uint32_t *) mp->b_wptr)++ = htonl(mtp->na); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_RC; *((uint32_t *) mp->b_wptr)++ = htonl(mtp->rc); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_APC; *((uint32_t *) mp->b_wptr)++ = htonl(rl->dpc); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_USER_CAUSE; *((uint16_t *) mp->b_wptr)++ = M3UA_USER_UNEQUIPPED; *((uint16_t *) mp->b_wptr)++ = htons(rl->si); break; case MTP_USER_PART_UNAVAILABLE: *((uint32_t *) mp->b_wptr)++ = M3UA_MAUP_DUPU; *((uint32_t *) mp->b_wptr)++ = __constant_htohl(mlen); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_NA; *((uint32_t *) mp->b_wptr)++ = htonl(mtp->na); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_RC; *((uint32_t *) mp->b_wptr)++ = htonl(mtp->rc); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_APC; *((uint32_t *) mp->b_wptr)++ = htonl(rl->dpc); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_USER_CAUSE; *((uint16_t *) mp->b_wptr)++ = M3UA_USER_INACCESSIBLE; *((uint16_t *) mp->b_wptr)++ = htons(rl->si); break; default: /* * FIXME: The default will be a zero-sized * M_DATA message if we don't fix this. * Someone downstream is going to complian! */ } } return (mp); } /* * N_DATACK_IND 24 - Data acknowledgement indication * ------------------------------------------------------------------------- * We receive one of these from MTP when we have asked for receipt * confirmation, in which case, the MTP sends us one of these each time that * a message has been transferred from the MTP-User write queue to a * SL-Provider write queue (i.e., committed for delivery). Before this * indication is received, the corresponding message in the MTP-User write * queue may yet be discarded due to an inaccessible or congested point code, * or an unavailable user part. * * When receipt confirmation is used, the MTP-User should hang onto a copy of * its transmitted messages until this. */ static int ss7_datack_ind(queue_t * q, mblk_t * msg) { } /* * N_RESET_IND 26 - Incoming NC reset request indication * ------------------------------------------------------------------------- * (MTP-PAUSE, MTP-STATUS, MTP-RESTART indications) * ------------------------------------------------------------------------- * The NSD reset facility is used to indicate to point code-to-point code * connection-oriented MTP-Users the unavailability, restriction, congestion * or user-part unavailability. * * This reset is rather uni-directional in that messages are not flushed from * the read queue, they will just be flushed from the write queue. If * receipt confirmation is on, the MTP-User at the other end will know which * messages have not been received. */ static int ss7_reset_ind(queue_t * q, mblk_t * msg) { mblk_t *mp; mtp_t *mtp = Q_MTP(q); size_t mlen = FIXME; N_reset_ind_t *p = (N_reset_ind_t *) msg->b_rptr; if (msg->b_wptr - msg->b_rptr < sizeof(*p)) return (-EFAULT); if ((mp = allocb(mlen, BPRI_MED))) { mp->b_datap->db_type = M_DATA; mp->b_band = 2; /* double expedite to ASP */ switch (p->RESET_reason) { case MTP_DEST_CONGESTED: case MTP_DEST_CONGESTED_LEVEL_1: case MTP_DEST_CONGESTED_LEVEL_2: case MTP_DEST_CONGESTED_LEVEL_3: mlen = sizeof(uint32_t) * 10; *((uint32_t *) mp->b_wptr)++ = M3UA_MAUP_SCON; *((uint32_t *) mp->b_wptr)++ = __constant_htohl(mlen); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_NA; *((uint32_t *) mp->b_wptr)++ = htonl(mtp->na); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_RC; *((uint32_t *) mp->b_wptr)++ = htonl(mtp->rc); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_APC; *((uint32_t *) mp->b_wptr)++ = htonl(mtp->dpc); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_CONG_LEVEL; switch (p->RESET_reason) { case MTP_DEST_CONGESTED_LEVEL_1: *((uint32_t *) mp->b_wptr)++ = htonl(1); break; case MTP_DEST_CONGESTED_LEVEL_2: *((uint32_t *) mp->b_wptr)++ = htonl(2); break; case MTP_DEST_CONGESTED: case MTP_DEST_CONGESTED_LEVEL_3: *((uint32_t *) mp->b_wptr)++ = htonl(3); break; } break; case MTP_DEST_PROHIBITED: mlen = sizeof(uint32_t) * 8; *((uint32_t *) mp->b_wptr)++ = M3UA_MAUP_DUNA; *((uint32_t *) mp->b_wptr)++ = __constant_htohl(mlen); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_NA; *((uint32_t *) mp->b_wptr)++ = htonl(mtp->na); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_RC; *((uint32_t *) mp->b_wptr)++ = htonl(mtp->rc); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_APC; *((uint32_t *) mp->b_wptr)++ = htonl(mtp->dpc); break; case MTP_DEST_RESTRICTED: mlen = sizeof(uint32_t) * 8; *((uint32_t *) mp->b_wptr)++ = M3UA_MAUP_DRST; *((uint32_t *) mp->b_wptr)++ = __constant_htohl(mlen); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_NA; *((uint32_t *) mp->b_wptr)++ = htonl(mtp->na); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_RC; *((uint32_t *) mp->b_wptr)++ = htonl(mtp->rc); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_APC; *((uint32_t *) mp->b_wptr)++ = htonl(mtp->dpc); break; case MTP_RESTARTING: mlen = sizeof(uint32_t) * 8; *((uint32_t *) mp->b_wptr)++ = M3UA_MAUP_DUNA; *((uint32_t *) mp->b_wptr)++ = __constant_htohl(mlen); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_NA; *((uint32_t *) mp->b_wptr)++ = htonl(mtp->na); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_RC; *((uint32_t *) mp->b_wptr)++ = htonl(mtp->rc); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_APC; *((uint32_t *) mp->b_wptr)++ = htonl(0xff000000 | mtp->dpc); break; case MTP_USER_PART_UNKNOWN: case MTP_USER_PART_UNEQUIPPED: case MTP_USER_PART_UNAVAILABLE: mlen = sizeof(uint32_t) * 11; *((uint32_t *) mp->b_wptr)++ = M3UA_MAUP_DUPU; *((uint32_t *) mp->b_wptr)++ = __constant_htohl(mlen); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_NA; *((uint32_t *) mp->b_wptr)++ = htonl(mtp->na); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_RC; *((uint32_t *) mp->b_wptr)++ = htonl(mtp->rc); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_APC; *((uint32_t *) mp->b_wptr)++ = htonl(mtp->dpc); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_USER_CAUSE; switch (p->RESET_reason) { case MTP_USER_PART_UNKNOWN: *((uint16_t *) mp->b_wptr)++ = M3UA_USER_UNKNOWN; break; case MTP_USER_PART_UNEQUIPPED: *((uint16_t *) mp->b_wptr)++ = M3UA_USER_UNEQUIPPED; break; case MTP_USER_PART_UNAVAILABLE: *((uint16_t *) mp->b_wptr)++ = M3UA_USER_UNAVAILABLE; break; } *((uint16_t *) mp->b_wptr)++ = htons(mtp->si); break; default: freemsg(mp); return (-EFAULT); } } } /* * ------------------------------------------------------------------------- * * MTP-Provider/MTP-User --> M3UA Primitive Translator * * ------------------------------------------------------------------------- * Many of the messages of M3UA map directly onto MTP primitives. These * message encoder functions take an MTP primitive and return an M3UA message * which is the direct equivalent of the primitives. These functions are * called by functions which service MTP primitives. */ /* * N_UNITDATA_REQ (MTP_TRANSFER_REQ) * ------------------------------------------------------------------------- * This covers only the MTP-TRANSFER-Request primitive. */ static mblk_t *ss7_unitdata_req(queue_t * q, mblk_t * msg) { mblk_t *mp, *db = msg->b_cont; mtp_t *mtp = Q_MTP(q); static const size_t mlen = M3UA_MHDR_SIZE + M3UA_PARM_SIZE_RC + M3UA_PARM_SIZE_RL + M3UA_PHDR_SIZE; if ((mp = allocb(mlen, BPRI_MED))) { size_t dlen = msgdsize(db); N_unitdata_req_t *p = (N_unitdata_req_t *) msg->b_rptr; struct mtp_rl *rl = (mtp_rl *) (((caddr_t) p) + p->DEST_offset - sizeof(uint32_t)); mp->b_datap->db_type = M_DATA; *((uint32_t *) mp->b_wptr)++ = M3UA_MAUP_DATA; *((uint32_t *) mp->b_wptr)++ = htonl(mlen + dlen); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_NA; *((uint32_t *) mp->b_wptr)++ = htonl(mtp->na); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_RC; *((uint32_t *) mp->b_wptr)++ = htonl(mtp->rc); /* * A couple of big arguments on what should be in the * messages here... */ *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_RL; *((uint32_t *) mp->b_wptr)++ = hotnl(rl->opc); *((uint32_t *) mp->b_wptr)++ = hotnl(rl->dpc); *((uint8_t *) mp->b_wptr)++ = 0; *((uint8_t *) mp->b_wptr)++ = hotnl(rl->sls); *((uint8_t *) mp->b_wptr)++ = hotnl(rl->ni); *((uint8_t *) mp->b_wptr)++ = hotnl(rl->mp); *((uint32_t *) mp->b_wptr)++ = M3UA_PARM_DATA; mp->b_cont = db; freeb(msg); } return (mp); } static int (*ss7_dstr_prim[]) (queue_t *, mblk_t *) { #define MTP_DSTR_FIRST N_CONN_REQ ss7_conn_req, /* N_CONN_REQ 0 */ NULL, /* N_CONN_RES 1 */ ss7_discon_req, /* N_DISCON_REQ 2 */ ss7_data_req, /* N_DATA_REQ 3 */ ss7_exdata_req, /* N_EXDATA_REQ 4 */ ss7_info_req, /* N_INFO_REQ 5 */ ss7_bind_req, /* N_BIND_REQ 6 */ ss7_unbind_req, /* N_UNBIND_REQ 7 */ ss7_unitdata_req, /* N_UNITDATA_REQ 8 */ ss7_optmgmt_req, /* N_OPTMGMT_REQ 9 */ NULL, /* 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 */ NULL, /* N_INFO_ACK 16 */ NULL, /* N_BIND_ACK 17 */ NULL, /* N_ERROR_ACK 18 */ NULL, /* N_OK_ACK 19 */ NULL, /* N_UNITDATA_IND 20 */ NULL, /* N_UDERROR_IND 21 */ NULL, /* 22 */ ss7_datack_req, /* N_DATACK_REQ 23 */ NULL, /* N_DATACK_IND 24 */ NULL, /* N_RESET_REQ 25 */ NULL, /* N_RESET_IND 26 */ ss7_reset_res, /* N_RESET_RES 27 */ #define MTP_DSTR_LAST N_RESET_RES NULL, /* N_RESET_CON 28 */ }; static int (*ss7_ustr_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, /* 10 */ NULL, /* N_CONN_IND 11 */ #define MTP_USTR_FIRST N_CONN_CON ss7_conn_con, /* N_CONN_CON 12 */ ss7_discon_ind, /* N_DISCON_IND 13 */ ss7_data_ind, /* N_DATA_IND 14 */ ss7_exdata_ind, /* N_EXDATA_IND 15 */ ss7_info_ack, /* N_INFO_ACK 16 */ ss7_bind_ack, /* N_BIND_ACK 17 */ ss7_error_ack, /* N_ERROR_ACK 18 */ ss7_ok_ack, /* N_OK_ACK 19 */ ss7_unitdata_ind, /* N_UNITDATA_IND 20 */ ss7_uderror_ind, /* N_UDERROR_IND 21 */ NULL, /* 22 */ NULL, /* N_DATACK_REQ 23 */ ss7_datack_ind, /* N_DATACK_IND 24 */ NULL, /* N_RESET_REQ 25 */ ss7_reset_ind, /* N_RESET_IND 26 */ #define MTP_USTR_LAST N_RESET_IND NULL, /* N_RESET_RES 27 */ NULL /* N_RESET_CON 28 */ }; /* * M_DATA Processing * ------------------------------------------------------------------------- */ static int ss7_w_data(queue_t * q, mblk_t * mp) { int err; mblk_t *np; if (!(np = ss7_data(q, mp))) return (-ENOBUFS); if ((err = m3ua_as_write(q, np))) return (err); return (0); } static int ss7_r_data(queue_t * q, mblk_t * mp) { int err; mblk_t *np; if (!(np = ss7_data(q, mp))) return (-ENOBUFS); if ((err = m3ua_as_read(q, np))) return (err); return (0); } /* * M_PROTO, M_PCPROTO Processing * ------------------------------------------------------------------------- */ static int ss7_w_proto(queue_t * q, mblk_t * mp) { int prim = *((long *) mp->b_wptr); if (MTP_DSTR_FIRST <= prim && prim <= MTP_DSTR_LAST && ss7_dstr_prim[prim]) return ((*ss7_dstr_prim[prim]) (q, mp)); return (-EOPNOTSUPP); } static int ss7_r_proto(queue_t * q, mblk_t * mp) { int prim = *((long *) mp->b_wptr); if (MTP_USTR_FIRST <= prim && prim <= MTP_USTR_LAST && ss7_ustr_prim[prim]) return ((*ss7_ustr_prim[prim]) (q, mp)); return (-EOPNOTSUPP); } /* * M_ERROR, M_HANGUP Processing * ------------------------------------------------------------------------- */ /* * M_FLUSH Processing * ------------------------------------------------------------------------- */ static int (*ss7_w_ops[]) (queue_t *, mblk_t *) = { ss7_w_data, /* M_DATA */ ss7_w_proto, /* M_PROTO */ NULL, /* M_BREAK */ NULL, /* M_CTL */ NULL, /* M_DELAY */ NULL, /* M_IOCTL */ NULL, /* M_PASSFP */ NULL, /* M_RSE */ NULL, /* M_SETOPTS */ NULL, /* M_SIG */ NULL, /* M_COPYIN */ NULL, /* M_COPYOUT */ NULL, /* M_ERROR */ ss7_w_flush, /* M_FLUSH */ NULL, /* M_HANGUP */ NULL, /* M_IOCACK */ NULL, /* M_IOCNAK */ NULL, /* M_IOCDATA */ ss7_w_proto, /* M_PCPROTO */ NULL, /* M_PCRSE */ NULL, /* M_PCSIG */ NULL, /* M_READ */ NULL, /* M_STOP */ NULL, /* M_START */ NULL, /* M_STARTI */ NULL /* M_STOPI */ }; static int (*ss7_r_ops[]) (queue_t *, mblk_t *) = { ss7_r_data, /* M_DATA */ ss7_r_proto, /* M_PROTO */ NULL, /* M_BREAK */ NULL, /* M_CTL */ NULL, /* M_DELAY */ NULL, /* M_IOCTL */ NULL, /* M_PASSFP */ NULL, /* M_RSE */ NULL, /* M_SETOPTS */ NULL, /* M_SIG */ NULL, /* M_COPYIN */ NULL, /* M_COPYOUT */ ss7_r_error, /* M_ERROR */ ss7_r_flush, /* M_FLUSH */ ss7_r_hangup, /* M_HANGUP */ NULL, /* M_IOCACK */ NULL, /* M_IOCNAK */ NULL, /* M_IOCDATA */ ss7_r_proto, /* M_PCPROTO */ NULL, /* M_PCRSE */ NULL, /* M_PCSIG */ NULL, /* M_READ */ NULL, /* M_STOP */ NULL, /* M_START */ NULL, /* M_STARTI */ NULL /* M_STOPI */ }; static void ss7_l_create(lp_t * lp) { }; static void ss7_l_delete(lp_t * lp) { }; struct ops m3ua_ss7_l_ops = { &ss7_l_create, /* create priv struct */ &ss7_l_delete, /* delete priv struct */ &ss7_r_ops, /* read operations */ NULL /* write operations */ };
|
|||||||||||||||||||||||||||
OpenSS7 SS7 for the Common Man |
Home | Overview | Status | News | Documentation | Resources | About | ||||||||||||||||||||
© Copyright 1997-2004,OpenSS7 Corporation, All Rights Reserved. |