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/ua/ua_upper.c#ident "@(#) $RCSfile: ua_upper.c,v $ $Name: $($Revision: 0.8.2.2 $) $Date: 2003/04/03 19:51:46 $" static char const ident[] = "$RCSfile: ua_upper.c,v $ $Name: $($Revision: 0.8.2.2 $) $Date: 2003/04/03 19:51:46 $"; #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 "ua.h" #include "ua_data.h" //#include "ua_msgs.h" #include "ua_ctrl.h" //#include "ua_prov.h" //#include "ua_pdu.h" #include "../sl/sl_user.h" #include "../mtp/mtp_user.h" #include "../sccpi/sccp_user.h" #include "../tcap/tcap_user.h" /* * ========================================================================= * * Message Processing * * ========================================================================= */ /* * M_DATA Processing * ------------------------------------------------------------------------- */ static inline int ua_data(queue_t * q, mblk_t * mp) { dp_t *dp = (dp_t *) q->q_ptr; ensure(dp, return -EFAULT); ensure(dp->w_data, return -EFAULT); return (*dp->w_data) (q, mp); } /* * M_PROTO Processing * ------------------------------------------------------------------------- */ static inline int ua_proto(queue_t * q, mblk_t * mp) { dp_t *dp = (dp_t *) q->q_ptr; ensure(dp, return -EFAULT); ensure(dp->w_proto, return -EFAULT); return (*dp->w_proto) (q, mp); } /* * M_PCPROTO Processing * ------------------------------------------------------------------------- */ static inline int ua_pcproto(queue_t * q, mblk_t * mp) { dp_t *dp = (dp_t *) q->q_ptr; ensure(dp, return -EFAULT); ensure(dp->w_pcproto, return -EFAULT); return (*dp->w_pcproto) (q, mp); } /* * M_ERROR Processing * ------------------------------------------------------------------------- * We don't accept M_ERRORs from above. */ /* * M_HANGUP Processing * ------------------------------------------------------------------------- * We don't accept M_HANGUPs from above. */ /* * M_FLUSH Processing * ------------------------------------------------------------------------- * Take flushes from above and turn them back around back up to the SS7 User. * Perhaps we should push a FLUSH downwards and make a BEAT out of it, * waiting for the BEAT Ack before returning the flush back upstream. */ static int ua_w_flush(queue_t * q, mblk_t * mp) { if (*mp->b_rptr & FLUSHW) { if (*mp->b_rptr & FLUSHBAND) flushband(q, mp->b_rptr[1], FLUSHALL); else flushq(q, FLUSHALL); *mp->b_rptr &= ~FLUSHW; } if (*mp->b_rptr & FLUSHR && !(mp->b_flag & MSGNOLOOP)) { if (*mp->b_rptr & FLUSHBAND) flushband(RD(q), mp->b_rptr[1], FLUSHALL); else flushq(RD(q), FLUSHALL); mp->b_flag |= MSGNOLOOP; qreply(q, mp); /* flush all the way back up */ return (0); } freemsg(mp); return (0); } /* * ========================================================================= * * M_IOCTL Processing * * ========================================================================= */ /* * I_LINK, I_PLINK Handling * ------------------------------------------------------------------------- * SS7 or SGP Provider or ASP User streams can be linked under the UA * multiplexing driver. We permit normal SS7 streams to perform an I_LINK of * SS7 or SGP provider or ASP user streams under the UA driver, but we only * permit the SS7 control stream to perform an I_PLINK of SS7 or SGP provider * or ASP user streams. This is so that if the configuration daemon crashes * it can come back and the configuration has not been destroyed. * * When linked, we generate the appropriate information request downstream to * the newly linked SS7 or SGP provider or ASP user stream. The purpose of * this is to discover the response from the stream as to which state the * stream is currently in and which addresses might be currently bound. This * permits the caller to bind the SS7 or SGP provider or ASP user streams. */ static inline int ua_i_link(queue_t * q, mblk_t * pdu, struct linkblk *lb) { mblk_t *mp; lp_t *lp; queue_t *lq; ensure(lb, return (-EFAULT)); lq = RD(lb->l_qbot); if (!(lp = kmalloc(sizeof(*lp), GFP_KERNEL))) return (-ENOMEM); bzero(lp, sizeof(*lp)); lp->q = RD(lq); lp->lmp = RD(q); lp->muxid = lb->l_index; lp->state = 0; RD(lq)->q_ptr = WR(lq)->q_ptr = lp; if ((lp->next = ua_links)) lp->next->prev = &lp->next; lp->prev = &ua_links; qdisable(lq); /* disable queue till configured */ return (lb->l_index); } /* * I_UNLINK, I_PUNLINK Handling * ------------------------------------------------------------------------- * When we unlink, if we still have referencing upper SS7-user streams, we * send each of them a M_HANGUP message indicating the loss of the * connection. This might result in a SIG_PIPE signal being sent to the * process if the SS7-user is a stream head. */ static inline int ua_i_unlink(queue_t * q, struct linkblk *lb) { int err; lp_t *lp; uint muxid; ensure(lb, return (-EFAULT)); muxid = lb->l_lindex; for (lp = ua_links; lp && lp->muxid != muxid; lp = lp->next); if (!lp) return (-EINVAL); if ((err = m_flush_all(q, NULL, FLUSHW, 0))) return (err); if ((err = m_hanup_all(q, NULL))) return (err); if ((*(lp->prev) = lp->next)) lp->next->prev = lp->prev; lp->q->q_ptr = WR(lp->q)->q_ptr = NULL; kfree(lp); return (0); } static int ua_w_ioctl(queue_t * q, mblk_t * pdu) { int ret = -EINVAL; void *arg = pdu->b_cont ? pdu->b_cont->b_rptr : NULL; struct iocblk = *iocp = (struct iocblk *) pdu->b_wptr; int cmd = iocp->ioc_cmd; switch (_IOC_TYPE(cmd)) { case __SID: switch (cmd) { case I_PLINK: if (RD(q) != ua_lmq) { ret = -EPERM; break; } case I_LINK: ret = ua_i_link(q, pdu, arg); break; case I_PUNLINK: if (RD(q) != ua_lmq) { ret = -EPERM; break; } case I_UNLINK: ret - ua_i_unlink(q, arg); break; } break; case UA_IOC_MAGIC: default: ret = -EOPNOTSUPP; break; } pdu->b_datap->db_type = ret < 0 ? M_IOCNAK : M_IOCACK; iocp->ioc_error = ret < 0 ? -ret : 0; iocp->ioc_rva = ret > 0 ? ret : -1; qreply(q, pdu); return (0); } /* * ========================================================================= * * QUEUE PUT and SERVICE routines * * ========================================================================= */ static inline int ua_recover(queue_t * q, mblk_t * mp, int err) { switch (err) { case -EBUSY: case -EAGAIN: case -ENOMEM: case -ENOBUFS: putq(q, mp); return (0); } freemsg(mp); return (err); } static inline int ua_reservice(queue_t * q, mblk_t * mp, int err) { if (mp->b_datap->db_type < QPCTL) switch (err) { case -EBUSY: case -EAGAIN: case -ENOMEM: case -ENOBUFS: putbq(q, mp); return (0); } freemsg(mp); return (err); } /* * WRITE PUT and SERVICE (Message from above SS7-User --> UA) * ------------------------------------------------------------------------- */ static inline int ua_wr(queue_t * q, mblk_t * mp) { switch (mp->b_datap->db_type) { case M_DATA: return ua_w_data(q, mp); case M_PROTO: return ua_w_proto(q, mp); case M_PCPROTO: return ua_w_pcproto(q, mp); case M_CTL: return ua_w_ctl(q, mp); case M_FLUSH: return ua_w_flush(q, mp); case M_IOCTL: return ua_w_ioctl(q, mp); } } INT ua_u_wput(queue_t * q, mblk_t * mp) { int err; dp_t *dp = (dp_t *) q->q_ptr; if (mp->b_datap->db_type < QPCTL && q->q_count) { putq(q, mp); return (INT) (0); } if ((err = (*dp->rd) (q, mp))) return (INT) (ua_recover(q, mp, err)); return (INT) (0); } INT ua_u_wsrv(queue_t * q) { mblk_t *mp; dp_t *dp = (dp_t *) q->q_ptr; while ((mp = getq(q))) { int err; if ((err = (*dp->rd) (q, mp))) return (INT) (ua_reservice(q, mp, err)); } return (INT) (0); }
|
|||||||||||||||||||||||||||
OpenSS7 SS7 for the Common Man |
Home | Overview | Status | News | Documentation | Resources | About | ||||||||||||||||||||
© Copyright 1997-2004,OpenSS7 Corporation, All Rights Reserved. |